2010-12-20

[GWT]Amazon API のXMLを解析する (クライアントサイド)

Amazon Product Advertising APIを利用して商品データを解析するGWTのサンプルです。クライアント側の処理なので、XMLパーザーは、com.google.gwt.xml.client.*のパッケージのクラスを利用します。まあ、ふつうのXMLの処理ですので特筆するべきところはありませんが、商品によって要素が抜ける場合がありますので注意が必要です。例えば下記では、AuthorとCreatorの扱い方など。
Document doc = XMLParser.parse(result);//resultにXMLデータが入っている
NodeList itemList = doc.getElementsByTagName("Item");
int num = itemList.getLength();
for (int i = 0; i < num; i++) {
Element node = (Element) itemList.item(i);
//タイトルの入手
Node titleNode = node.getElementsByTagName("Title").item(0);
titleName = titleNode.getFirstChild().getNodeValue();
//Window.alert("title入手");
//著者の入手 ここはAuthorかCreator
if (0 < node.getElementsByTagName("Author").getLength()) {
authorName = node.getElementsByTagName("Author").item(0).getFirstChild().getNodeValue();
} else if (0 < node.getElementsByTagName("Creator").getLength()) {
authorName = node.getElementsByTagName("Creator").item(0).getFirstChild().getNodeValue();
} else {
authorName ="<著者情報なし>";
}
//出版社の入手
Node publisherNode = node.getElementsByTagName("Publisher").item(0);
publisherName = publisherNode.getFirstChild().getNodeValue();
}


2010-12-17

[Java]ファイルアップロードサーブレットプログラム

純粋なサーブレットでのファイルアップロードプログラムの例です。下記のプログラムの動作には、
のライブラリが必要です。
  1. protected void processRequest(HttpServletRequest request, HttpServletResponse response)  
  2.             throws ServletException, IOException {  
  3.         Logger log = Logger.getLogger(Logger.GLOBAL_LOGGER_NAME);  
  4.         try {  
  5.   
  6.             //URLより保存場所の絶対パスを入手  
  7.             ServletContext sc = getServletContext();  
  8.             String path = sc.getRealPath("/WEB-INF");  
  9.             log.info("filepath:" + path);  
  10.             File fileDir = new File(path);  
  11.   
  12.             if (!ServletFileUpload.isMultipartContent(new ServletRequestContext(request))) {  
  13.                 throw (new Exception("Not FileUpload Request"));  
  14.             }  
  15.             ServletFileUpload upload = new ServletFileUpload(new DiskFileItemFactory());  
  16.             List<fileitem> list = upload.parseRequest(request);  
  17.             for (Iterator<fileitem> iter = list.iterator(); iter.hasNext();) {  
  18.                 FileItem fItem = (FileItem) iter.next();  
  19.                 if (fItem.isFormField()) {  
  20.                     continue;  
  21.                 }  
  22.                 String fileName = (new File(fItem.getName())).getName();  
  23.                 File newFile = new File(fileDir, fileName);  
  24.                 fItem.write(newFile);  
  25.   
  26.             }  
  27.             log.info("アップロード終了");  
  28.         } catch (Exception ex) {  
  29.             log.warning("アップロード処理異常終了");  
  30.         }  
  31.   
  32.     }  


2010-12-16

[C++] Visual C++でerror C2143: 構文エラー がでた場合の原因と対処

卒研のプログラムで、
  • error C2143: 構文エラー : ';' が '◯◯' の前に必要です。
というエラーが発生。ちょっとハマったのでそのメモ書きです。まず、その原因は次の2つのいずれかです。
  1. ケアレスミス。括弧やセミコロンが抜けているなど
  2. 利用しているクラスが未定義

今回の原因は後者でした。具体的に言いますと以下のような記述のところでエラーがでました。
  1. CString str;  
  2. CTest* test; // ←ここでerror C2143  
なにがまずいかというと、この状況でのエラーは、「CTestがクラスとして認識されていない」のが原因だったようです。

【解決策】
  • CTestを定義しているヘッダをincludeする
  • プロジェクトのプロパティ→構成プロパティ→C/C++→全般→追加のインクルードディレクトリ にCTest.hが入っているディレクトリを指定する
インクルードディレクトリの設定もうっかり忘れることがありますので、気をつけたいものです。


2010-12-14

[C#] WebRequestクラスの利用時のプロトコル違反への対応策

WebRequestクラスを利用してウェブサーバにアクセスした場合、
  • サーバーによってプロトコル違反が発生しました. Section=ResponseHeader Detail=CR の後には LF を指定しなければなりません。
という意味不明なエラーが発生します。このようなときは、アクセスする前に以下のような記述をしてください。
  1. Configuration config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);  
  2. SettingsSection section = (SettingsSection)config.GetSection("system.net/settings");  
  3. section.HttpWebRequest.UseUnsafeHeaderParsing = true;  
  4. config.Save();  
なお、ここで記述しているクラスは、
  • System.Configuration
  • System.Net.Configuration
のライブラリを利用します。参照設定で追加しておきましょう。


2010-12-13

Netbeansのインストールでトラブった場合の対処法

Netbeansのバージョンアップを繰り返すと、最新版にした場合にインストール後の動作がおかしくなる場合があります。例えば

  • インストールしたはずのサーバがない、登録できない
  • プラグインが見つからない
  • 動作がやけに遅くなる
などなど、、、これらは、前バージョンの設定ファイルを継承し続けたことによる弊害が原因の場合があります。
思い切ってフレッシュな気分で新しいバージョンのNetbeansを使いたいときは、
  • ホームディレクトリ下の隠しファイルになっている「.netbeans*」関係のファイルをごっそり消す
という荒業をすることで、正常に動作するかもしれません。うちの研究室では、きままにバージョンアップをしているので、バージョンが変わったときに前の設定の継承を何回か行う傾向があります。その際に、何らかのデータの齟齬が発生して、まともに動かなくなることがあります。今日もそういったトラブルがあり、再インストールなどを行って3時間ぐらい時間を潰しましたが、結局設定ファイルを削除してOKという感じでした。




2010-12-10

ET研究会に参加してきました

「Web検索APIを利用した英語表現評価支援システム」という題目で、信学会教育工学研究会にて発表をしてきました。発表したのは院生でしたが、無事終了です。質疑応答もちょっと難しかったですが自分なりに答えてたと思います。で、反省と感想です。

質疑応答から感じたこと
「ターゲットとするユーザ」については、もう少し考えたほうがいいかもしれません。ただし、目的として支援したいユーザと、現状のシステムの実装機能で支援できる内容に齟齬が起きないように気をつけなければなりません。あるいは、現状のシステムが本来の目標に対してどのような立ち位置にあるのか?を説明できないといけないでしょう。
「先行研究」については、ちょっと調べ直しですね。元々のこの研究を始めた発端が、個人的なモチベーションからはじまったものなので、調査不足の点は否定できないですね。まあ、先行研究と類似していたとしても、前々から研究室でやりたかった「英語学習支援」がテーマなので、今回のシステムをベースに、いろいろ発展させていきたいなと思う今日この頃です。

その他の発表について
特に気になった発表を2点ほど。
「e-Leariningにおける受講者の動作の分析」については、うちの研究室でも動作分析の研究をやっていたので、興味深いものでした。特徴量の取り方とか、評価の仕方など参考になりそうです。
「学習・教育支援環境支援フレームワークMeshの構成」については、「汎用的なフレームワークを作る」という研究の視点はマネしたいなと。。。ただ、なかなか難しい感じがしているので、まずはWeb APIレベルかなぁというのが思っているんですが、、、
その他、今回の研究会のテーマにインタフェースというのがあったせいか、PCのマウス・キーボード以外のデバイスを利用する研究の多さが目立ちました。

[GWT] Cometでプッシュプログラミング ~クライアントプログラミング編~

GWTでCometサーバーにアクセスするクライアントプログラムの実装方法についてです。

基本的には、通常のサーバアクセスと同様にRequestBuilderを利用してCometサーバに非同期にアクセスします。Cometからデータが送られてくると、onResponseReceivedメソッドが呼ばれるのでそこで内容を抽出し処理を行います。処理が終わったら、再帰的に接続処理を呼び出すことで、Cometサーバとの通信を継続して処理することができます。

  1. private void connectComet() {  
  2.         try {  
  3.             Window.alert("CometConnect()");  
  4.             RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, cometURL);  
  5.               
  6.             requestBuilder.sendRequest(nullnew RequestCallback() {  
  7.                 @Override  
  8.                 public void onResponseReceived(Request request, Response response) {  
  9.                   String tmp= response.getText();  
  10.                   connectComet();  
  11.                 }  
  12.                 @Override  
  13.                 public void onError(Request request, Throwable exception) {  
  14.                                   }  
  15.             });  
  16.         } catch (RequestException ex) {  
  17.             //エラー処理をここで書く  
  18.         }  
  19.     }  


2010-12-08

Amazon Product Advertising API 利用時の日本語処理

Amazon Product Advertising API を利用したプログラムをGAE上で動かしているのだけれど、日本語の処理で手間取ったので、覚書き。いちおう話の前提としては、GWTとGWT-RPCを利用してサーバ側でAmazonに接続しています。アクセス方法は、HttpURLConnectionクラスを用いました。

【検索キーに日本語を含める場合】
検索クエリーを生成する際に、

  • URLEncoder.encode(keyword,"utf-8")

というように、UTF-8に変換しておきます。こうしておかないと、正しい検索がされません。

【検索結果に日本語が含まれる場合】
検索するプログラムについては、サンプルプログラムにある SignedRequestHelprクラスを利用してます。日本語が含まれていると文字化けとなって、ただしく受け取ることができません。そこで、BufferReaderに受け渡すときには、以下のように記述します。


  • BufferedReader reader = new BufferedReader(new InputStreamReader(urlconn.getInputStream(),"UTF-8"));


2010-12-06

プログラミングリソースをWebサービスで残す

うちの研究室にはいろいろプログラミングのリソースが溜まっているのだけれど、なかなか後年への技術継承が上手くいかない、、、その理由は、やはりソースコードレベルの継承だと、そもそもそのソースコードが汎用的に作られているかが怪しいし、継承する学生もその理解に追いつかないという問題。。。そう考えるともっと使いやすい形に落としこむ必要があるわけで、その策としてWebサービス化という結論に。。。このことは昔から思っていたんだけど、実際問題として実装時にWebサービス化する利点がなかなかなかったというのもある。最近は、研究室でも各種外部ウェブサービスをマッシュアップするようになったので、それだったら研究室のリソースもウェブサービス化したらいいじゃんということで、今回ウェブサービス化に踏み切ることに。。。

とりあえずは研究室での運用だけど、今後は学外への公開も視野に入れる予定。

[Java]Cometプログラミング ~Glassfishの設定~

ここでは、Glassfishをサーバにした際の設定について取り上げます。また、開発環境としてNetbeansを利用する場合についても取り上げます。

[Glassfishでの設定]
Cometを利用する際、古い記事を見るといろいろ設定が必要なような記述がみられますが、Glassfish v3では標準で Cometをサポートしていますので設定は簡単です。手順としては

  1. 管理コンソールを立ち上げる(4848が標準ポートです)
  2. ネットワーク設定→プロトコル→http-listerner-1を開く
  3. Cometサポートを有効にする

これだけでOKです。

[Netbeansで利用する場合]
Netbeansには、標準でGlassfishがついてきます(これがNetbeansをオススメする理由の一つでもあるんですが)。同様にすればいい、、、と思ってるとドツボにハマります。
実は、NetbeansでGlassfishの管理コンソールで設定した内容は一時的なもので、サーバを再起動すると設定が標準に戻ってしまいます。どうすればいいのかというと、

  1. Netbeansでサービスペインをクリック
  2. サーバ→Glassfishを右クリックし、プロパティを選択
  3. Cometサポートを有効にする

という手順をふみます。これがわからず、設定ファイルをいじったりして悩んでました。(^^ゞ

2010-12-03

徳島大への遠隔講義配信を行いました

昨年度もおこなった、徳島大への遠隔講義配信を行いました。1年前にやっていたので気を抜いてたのですが、前日にちょっと慌てました。。。。というのも、Polycomにネットワークカメラを接続するということを行っているのですが、それをどう接続すればよいのかというのをすっかり忘れてまして、、、(^^ゞやはりこういうちょっとしたノウハウも残しておくべきですね。昨日は、システムの配置位置とかを根本から考え直し、できるだけ柔軟にカメラを配置できるように、ラックに機器を収納するなど配置変更を行いました。おかげで、今日はすんなり行きましたが、、、、

さて、本日の講義の内容は昨年度と同様に
  • 画像映像処理技術を利用した教育システム
についてお話をさせてもらいました。前半は世間話でしたが、、、質問がなかったのが残念だなぁ。

なお、来年はハイビジョンカメラとハイビジョン対応Polycomを利用した配信を検討中です。


[Java] Cometでプッシュプログラミング ~サーバプログラミング編~

サーバーサイドからのプッシュ配信を実現するフレームワークとしてCometというのがあります。これは昔からありまして、うちの研究室でも数年前の卒論で利用してました。で、今年も利用することになったんですが、ノウハウを整理しきれてなくて卒論だけ見てもわかりにくい状況になってましたので、ここであらためて整理しておきます。

12/6 プログラムに一部追記しました。

Cometの原理
httpで接続したコネクションを接続しっぱなしにして、レスポンスのストリームにデータを流し込むことでプッシュを実現します。

クラス構成
サーバー側では少なくとも3つのクラスが必要です
  • Cometサーバ実装クラス ・・・ プッシュするためのコネクションを確保するクラス。サーブレットです
  • Cometハンドルクラス ・・・ CometHandlerを実装したクラス。ここにプッシュで送信する処理を記述します。
  • ユーザプログラム ・・・ Cometを利用するプログラムです。

関連ライブラリ
Glassfishには
  • grizzly-comet.jar
というライブラリが同梱されています。このファイル名で探せば出てくるはずですから、見つけたらクラスパスに設定しましょう。

 Cometサーバプログラム
 クライアントとの接続を確保します。まず、init内では
  • Cometエンジンの登録
  • Cometエンジンの設定
を行います。そして、ユーザからコネクション要求があれば、processRequest(サーブレットのdoGet、doPost相当)内で、以下のように書かれている処理を行います。
  • Cometエンジンの呼び出し
  • Cometハンドラーへのコネクションストリームの受け渡し
  • Cometハンドラーの登録
  1. //初期設定  
  2.     @Override  
  3.     public void init(ServletConfig config) throws ServletException {  
  4.         cometContextPath = config.getServletContext().getContextPath() + "/comet";  
  5.         System.out.println("cometContextPath:"+cometContextPath);  
  6.         CometContext context = CometEngine.getEngine().register(cometContextPath);  
  7.         context.setExpirationDelay(10 * 60 * 60 * 1000);  
  8.     }  
  9.     protected void processRequest(HttpServletRequest request, HttpServletResponse response)  
  10.             throws ServletException, IOException {  
  11.         response.setContentType("text/html;charset=UTF-8");  
  12.         PrintWriter out = response.getWriter();  
  13.         //CometHandlerクラスの登録  
  14.         CometHandler handler = new MyHandler();  
  15.         handler.attach(out);  
  16.         CometContext context = CometEngine.getEngine().getCometContext(cometContextPath);  
  17.         context.addCometHandler(handler);  
  18.     }  
Cometハンドラー Cometハンドラーとは何か?それは、Cometでの配信時の処理を記述するクラスです。ここで大切なのは、onEventメソッドです。これは、Pushする際に呼ばれるメソッドです。ここでwriterに対して書き込みを送ることで、クライアントにその内容が配信されます。なぜでしょう?それは、ここのwriterというのは、上記のサーバプログラムでハンドラーを登録する際にattachメソッドにて受渡したHttpServletResponseのWriterの事なのです。
  1. public class MyHandler implements CometHandler<PrintWriter> {  
  2.   
  3.     private PrintWriter writer = null;  
  4.   
  5.     public void onEvent(CometEvent event) throws IOException {  
  6.         if (CometEvent.NOTIFY == event.getType()) {  
  7.   
  8.            String id = (String) event.attachment();  
  9.             writer = response.getWriter();  
  10.             writer.write(id);  
  11.             writer.flush();  
  12.             event.getCometContext().resumeCometHandler(this);  
  13.         }  
  14.     public void onInitialize(CometEvent event) throws IOException {  
  15.         System.out.println("Init");  
  16.     }  
  17.   
  18.     public void onTerminate(CometEvent event) throws IOException {  
  19.         onInterrupt(event);  
  20.     }  
  21.   
  22.     public void onInterrupt(CometEvent event) throws IOException {  
  23.         writer.close();  
  24.         event.getCometContext().removeCometHandler(this);  
  25.     }  
  26.  //クライアントとのストリームを受け取る  
  27.     public void attach(PrintWriter writer) {  
  28.         this.writer = writer;  
  29.     }  
  30.    private void removeThisFromContext() throws IOException {  
  31.         response.getWriter().close();  
  32.         CometContext context =  
  33.                 CometEngine.getEngine().getCometContext(cometContextPath);  
  34.         context.removeCometHandler(this);  
  35.     }  
ユーザプログラム ユーザプログラムでの記述は下記の通りです。以下はサーブレットの例ですが、ポイントは最後の行です。notifyメソッドを呼ぶことで、CometハンドラークラスのonEventが呼ばれることになります。つまり、プッシュしたい時にnotifyを呼び出せば良いわけです。引数は、ハンドラーのonEventメソッドでeventのアタッチメントとして取り出すことができます。
  1. protected void processRequest(HttpServletRequest request, HttpServletResponse response)  
  2.     throws ServletException, IOException {  
  3.         ServletConfig config=this.getServletConfig();  
  4.         String id = request.getParameter("id");  
  5.         CometContext context = CometEngine.getEngine().getCometContext(cometContextPath);  
  6.         context.notify(id);  
  7.  }  
以上の3つを見比べることで、Cometが何をやっているのかわかるでしょう。コメットのサーバの設定や、クライアントプログラムの記述については、後日書こうかと思ってます。

2010-12-01

GWTでXMLを扱う ~クライアントサイド編~

GWTでのXMLプログラミングについて基本のところを書いてなかったので、、、今回は、クライアントサイド編です。クライアントサイドでの操作は、JavaScriptでの操作とほぼ同じになるのでそんなに難しく考える必要はないでしょう。利用するクラスは、 com.google.gwt.xml.clientパッケージを利用します。importする際には間違えないようにしましょう。

gwt.xmlファイルに以下の記述を追加してください。
<inherits name="com.google.gwt.xml.XML"></inherits>
view raw gwtxml.gwt.xml hosted with ❤ by GitHub
操作するXMLファイル
<message>
<from username="OCHI"></from>
<to username="OCHI1"></to>
<to username="OCHI2"></to>
<msg>よろしくー</msg>
<sbody><data>子供のデータ</data><data>子供のデータ2</data></sbody>
</message>
view raw xmlSample.xml hosted with ❤ by GitHub
Javaのコードは以下のようになります。基本的な使い方のパターンを挙げています。前提として、stringXML変数に上述のXMLデータが入っているものとします。
// XML形式の文字列情報をXMLDocumentクラスに格納
Document doc = XMLParser.parse(stringXML);
//ターゲットノードが一つの場合
Node fromNode = doc.getElementsByTagName("from").item(0);
String sfrom = ((Element) fromNode).getAttribute("userName");
Window.alert(sfrom);
//ターゲットノードが複数ある場合
NodeList toNodeList = doc.getElementsByTagName("to");
int num =toNodeList.getLength();
Element ele;
for(int i=0;i<num;i++){
//Attributeを取り出す場合はElementとして扱う
ele =(Element)toNodeList.item(i);
Window.alert(ele.getAttribute("userName"));
}
// Nodeの値を取り出す場合
Node msgNode= doc.getElementsByTagName("msg").item(0);
String sMsg=msgNode.getFirstChild().getNodeValue();
Window.alert("msg:"+sMsg);
//あるノードの子ノードの値を取ってくる場合
Node bodyNode= doc.getElementsByTagName("sbody").item(0);
NodeList childs=bodyNode.getChildNodes();
num =childs.getLength();
Window.alert("数:"+num);
for(int i=0;i<num;i++){
Node test= childs.item(i);
Window.alert("child:"+test.getFirstChild().getNodeValue());
}
注意点ですが、他のXMLパーザーと同様に子ノードを取ってくる際には、改行が入ってくると子ノードの個数が変わってきます。具体的に言うと、上記のXMLではsbosyタグの子ノードは2つとなりますが、これらに改行が入ってくると、改行がテキストノードとしてカウントされます。たいていのXMLドキュメントには改行は入ってないと思いますが、気をつけてください