2009年12月14日月曜日

AutoItで文字列の分割

AutoItで文字列の分割をどうすればいいのかなといろいろ試していたら
こんな感じでやればできました。
ついでなのでループも使ってみる。

|で文字列を分解して、順番に表示するサンプルです。

=======================================================
$days = StringSplit("Sun|Mon|Tue|Wed|Thu|Fri|Sat", "|")
For $i = 1 to $days[0] Step 1
 MsgBox(0, "曜日", $days[$i])
Next
MsgBox(0, "情報","ループ終了")
=======================================================

AutoItで他のファイルを取り込む

AutoItで他の用途で書いた関数などを呼び出す場合(Javaでいうところのimport) にどうしたらいいのかなと調べてみたところ、includeというものがあるようですね。

http://www.autoitscript.com/autoit3/docs/keywords/include.htm 

 #include "inc1.AU3" 
 #include "inc2.AU3" 

 という感じで書いてみると、そのまま、 "inc1.AU3" "inc2.AU3" が順番に実行されるようです。 inc1.auで定義した変数をinc2.auで使ってみても、使えるようなので、 COBOLでいうcopy句に近い概念なのかもしれません。

2009年12月12日土曜日

AutoItでクリップボードの操作

AutoItでクリップボードの操作例です。

クリップボードの文字を取得し、ダイアログに表示するサンプルです。

===============================================
$msg_text = ClipGet()
MsgBox(4096,"クリップボードテキスト",$msg_text)
===============================================
ドキュメントのリンクはこちら。
http://www.autoitscript.com/autoit3/docs/functions/ClipGet.htm

逆にクリップボードに渡したい場合には、ClipPut()を利用する。

http://www.autoitscript.com/autoit3/docs/functions/ClipPut.htm

これも上記のドキュメントを見れば簡単にできる。

AutoItでTreeViewを操作する

AutoItで外部からTreeViewを操作するサンプルを作ってみました。

エクスプローラでデスクトップを選択している状態のものを
ゴミ箱を選択している状態に変更するサンプル
===========================================
ControlTreeView("デスクトップ","","[CLASS:SysTreeView32;INSTANCE:1]","Expand","デスクトップ")
ControlTreeView("デスクトップ","","[CLASS:SysTreeView32;INSTANCE:1]","Exists","デスクトップ|ごみ箱")
ControlTreeView("デスクトップ","","[CLASS:SysTreeView32;INSTANCE:1]","Check","デスクトップ|ごみ箱")
ControlTreeView("デスクトップ","","[CLASS:SysTreeView32;INSTANCE:1]","Select","デスクトップ|ごみ箱")
ControlTreeView("デスクトップ","","[CLASS:SysTreeView32;INSTANCE:1]","Expand","デスクトップ|ごみ箱")

===========================================
ちなみに「デスクトップ|ごみ箱」の|はフォルダの区切れ目を意味しているようです。

AutoItでコンポーネントをクリックする命令を送る。

AutoItでコンポーネントをクリックする命令を送る方法

仕様リンク:
http://www.autoitscript.com/autoit3/docs/functions/ControlClick.htm


AutitV3 WindowInfoのControlのAdvanced(class)


を調べて

ControlClick("画面のタイトル","","上で調べた文字列")
 
もしくは、ボタンの文字列とクラスを下記のように指定してあげてもできるみたい。
 
ControlClick("画面のタイトル","","[CLASS:TButton;TEXT:保存]", )
 
第3引数の使用に関しては、下記が参考になる。
http://www.autoitscript.com/autoit3/docs/intro/controls.htm
 
 

AutoItでコマンドライン引数を受ける

AutoItで引数を受け取る方法はこんな感じでできるようです。

$CmdLine[0] コマンドラインの引数の数


$CmdLine[1~] 引数の値

2009年10月24日土曜日

Delphiでファイルの変化に反応するプログラム

よく、アプリケーションを使っていると、ファイルが他のプログラムで
変更されたことを検地する機能を持ったものがある。

これは、どうやってやっているんだろうかとぼんやりと思っていたのだけど、
必要に迫られることがなかったので、ずっと放置していたのだけども、
最近、ツールが作りたくなってこの機能があればスマートに実装できるので
ちょっと調べてみた。

すると、Delphiには、まさにそのためのコンポーネントがあるではないか。

それは、TShellChangeNotifierというクラス。

このクラスは、指定したフォルダ以下のファイルに変化があったら反応してくれる
コンポーネント。

下記が今回参考にしたサイトです。
http://www.geocities.jp/fjtkt/problems/2005_0008.html

2009年10月8日木曜日

シリアライズのテストプログラム

シリアライズをして復元するというようなプログラムをテストで
作ってみました。

いままではフレームワークで勝手にシリアライズしてくれるような部分で意識していなかった
部分だったのだけど、ちょっと自前で書いてみました。

Serializable なクラスをもつSerializable を作って
byte[]に格納した後に、そこからオブジェクトに復元してみる
というのを確かめたサンプルのソースコードです。

package SerializeTest;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

import javax.xml.parsers.DocumentBuilder;

import org.w3c.dom.Document;

public class Main {

 /**
  * @param args
  * @throws IOException 
  * @throws ClassNotFoundException 
  */
 public static void main(String[] args) throws IOException, ClassNotFoundException {
  classA  test = new classA();
//  DocumentBuilder docbu = DocumentBuilder.get;
  test.setLoginInfo(new LoginInfo("useree","passhhh"));
  test.setVal1("かきくけこ");
  test.setVal2("あいうえお");
  System.out.println(test.toString());
  
  ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
  ObjectOutputStream p = new ObjectOutputStream(baos);

  p.writeObject(test);
  p.writeObject("String");

  p.flush();
  byte [] bit = baos.toByteArray();
  baos.close();
    //
  ByteArrayInputStream bais = new ByteArrayInputStream(bit); 
  ObjectInputStream ois = new ObjectInputStream(bais);
  classA cla = (classA ) ois.readObject();
  String str = (String ) ois.readObject();
  System.out.println(cla.toString());
  System.out.println(str);
 }

}
 

============================
package SerializeTest;

import java.io.Serializable;

public class classA implements Serializable {
 /**
  * 
  */
 private static final long serialVersionUID = -345225844394172659L;
 LoginInfo loginInfo;
 String val1 ;
 String val2 ;
 
 public LoginInfo getLoginInfo() {
  return loginInfo;
 }

 public void setLoginInfo(LoginInfo loginInfo) {
  this.loginInfo = loginInfo;
 }

 public String getVal1() {
  return val1;
 }

 public void setVal1(String val1) {
  this.val1 = val1;
 }

 public String getVal2() {
  return val2;
 }

 public void setVal2(String val2) {
  this.val2 = val2;
 }

 public String toString(){
  return loginInfo.getUserName()
       +"/"+loginInfo.getPassword()
  +"/"+val1+"/"+val2;
 }
 
}

===============================
package SerializeTest;

import java.io.Serializable;

public class LoginInfo implements Serializable {
 /**
  * 
  */
 private static final long serialVersionUID = -8712859729005134670L;
 private String userName;
 private String password;
 public LoginInfo(String string, String string2) {
  userName =string;
  password=string2;
 }
 public String getUserName() {
  return userName;
 }
 public void setUserName(String userName) {
  this.userName = userName;
 }
 public String getPassword() {
  return password;
 }
 public void setPassword(String password) {
  this.password = password;
 }

}
 



2009年9月28日月曜日

EJBの仕組み概要

EJBって聞いたことはあるけどよく知らなかった仕組みなんで、
理解しようとしてみた。

初心者には、このページがわかりやすかった。

JBossで学ぶEJB入門

第二回までは、EJBの一般論が書かれているので、JBossでなくても
通用する話でした。

2009年9月19日土曜日

OracleでNotNull制約を解除する

先日、Oracleのテーブル定義でNotNull制約を解除するAlter文ってどう書くんだろう
ということではまってしまった。

ALTER TABLE XXXXXX MODIFY (YYYYYY VARchar(20))


とやってみてもNotNull制約は解除されない。正しくは、下記のように書くんですね。
ALTER TABLE XXXXXX MODIFY (YYYYYY VARchar(20) NULL)

2009年9月16日水曜日

DelphiアプリケーションのWindowsのダンプファイルの調査のしかた

Windowsファイルが出力するダンプファイルなんで今まで遠ざけていたのだけど、
ちょっとチャレンジしてみた。

まず、必要なものは、windbgというマイクロソフトの無料のツール
これは、下記から説明およびダウンロードができる。

http://www.microsoft.com/japan/whdc/devtools/debugging/debugstart.mspx

次にDelphiのアプリケーションからは、生成されないマップ情報を生成する必要が
あるのだけど、それは、下記のDelphiのmapファイルをdbgファイルに
変換してくれる便利なツール「map2dbg」があるようです。

参考になったサイトは下記のサイト(英文)です。
http://www.sandon.it/?q=node/45

これらを踏まえた上で、下記のサイトを見てwindbgを使ってみると、
スタックとレースを見ることが出来るという部分までが理解できた。

クラッシュダンプを読んでその原因を究明する

いろいろ見てみると、
STACK_TEXT:

という部分あたりに、関数の呼び出し履歴みたいなのが表示されるようです。

現実問題、これがわかるだけでも結構でかいなぁ....

昔、この本を読もうとして、ちょっとやめたのだけど、やっぱり読んでみようかな
とまた思い始めてみる。
Windowsダンプの極意 エラーが発生したら、まずダンプ解析! (大型本)





2009年9月15日火曜日

XMLDocumentをStringにする

XML処理のデバッグなどをしていると、
XMLDocumentをStringにしてみてみたいなぁと思い、それをする方法を調べていたら
下記のページにたどり着いた。

Java Technology & XML - Re: how to transform a dom object to String?

これをほんのちょっとだけ、アレンジして下記のようなmethodを作ったところ
イメージどおりの動作をしてくれました。

 private static String getStringFromDocument(Document doc){
   String str=null;
   try {
     TransformerFactory tfac = TransformerFactory.newInstance();
     StringWriter strWtr = new StringWriter();
     StreamResult strResult = new StreamResult(strWtr);
     Transformer trans = tfac.newTransformer();
     trans.transform(new DOMSource(doc.getDocumentElement()), strResult);
     str =strResult.getWriter().toString();  } 
   catch (TransformerException te) {
    te.printStackTrace();
   }
   return str;
 }
 

これで、どこがおかしかったのかを突き止めることが出来ました。

2009年9月5日土曜日

Google App Engine SDK 1.2.5リリース

Google App Engineのブログを見ていると新バージョンが出たというニュースが書かれていた。

App Engine SDK 1.2.5 released for Python and Java, now with XMPP support 

今回の目玉新機能としては、

XMPP Support

ということだそうです。
XMPPなんてよく知らなかったけど、GoogleTalkなんかでも利用されている
メッセンジャー系の仕様みたいです。

XMPPとは 【eXtensible Messaging and Presence Protocol】

また、今回は初のPythonとJavagの同時リリースということみたいです。
いままでJavaは遅れてのリリースだったのでPythonだけしかない機能が結構あったけど、
これはうれしい知らせです。

また、いつの間にかGoogle Plugin for Eclipse がEclipse 3.5 (Galileo)に対応したようなので
eclipseも3.5に更新しておきました。

3.5ではsoftware updateのメニュー構成が若干変わっていて少々戸惑いました。

インストール方法は、下記のページに書かれています。
Installing the Google Plugin for Eclipse

2009年8月25日火曜日

Excelにてオートシェイプの文字列を操作する

Excelのオートシェイプの文字列置換検索が出来ないのが非常に不便だったので、
Delphiで操作するのを試してみました。

OLEを操作する場合には、VBAなどが普通なんでしょうけど、Delphiの方が得意なんで
Delphiでやってみます。

OleObjectを使っています。

下記のような感じでやれば操作できました。

宣言
var E_Excel: Variant;
E_Application: Variant;
E_WorkBook: Variant;
E_WorkSheet: Variant;
E_Shape: Variant;

基本的な操作方法
E_Excel := CreateOleObject('Excel.Application');
E_Application := E_Excel.Application;
E_Excel.Visible:=True;
E_Application.WorkBooks.Open(FileName); // XLS ファイルを開く
E_WorkBook := E_Application.ActiveWorkbook;
E_WorkSheet := E_Application.ActiveSheet;
for i:=1 to E_WorkSheet.Shapes.Count do
begin
E_Shape:=E_WorkSheet.Shapes.item(i);
   E_Shape.TextFrame.Characters.Text;
E_Shape.TextFrame.Characters.Text:= 'test';
  end

いちばん苦労したのは、変更したオートシェイプを画面上にスクロール表示させる部分。
これに悩んだのですが、下記のページをいろいろと細かく見ていくと

Shape インターフェイス (Microsoft.Office.Interop.Excel)

BottomRightCell というプロパティがあったんで、

E_Shape.bottomRightCell.Select;

という感じで書いてあげると意図通りに動作してくれた。

ここら辺を使って、エクセルのオートシェイプの文字を検索するツールを作ってみました。
http://mitools.blogspot.com/2009/08/excel.html

2009年8月24日月曜日

削除機能の追加

GoogleAppEngineを久々にいじってみた。
今回は、地図から検索のアプリケーションにようやく削除機能を追加した。

削除機能は、自分が登録したデータに関しては、削除、他人が登録したデータに関しては、
削除リクエストの送信と言うような仕様にしております。

今回苦戦したのは、getObjectByIdを利用してデータを取得する部分。

ローカルのサーバでやるとうまく動作するのだけど、AppEngine上では、
どうしてもうまくいかない。

getObjectByIdでnullが返ってきてしまうようである。


08-23 06:20PM 52.000 /loarsh/greet 500 34ms 30cpu_ms 12api_cpu_ms 0kb Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729),gzip(gfe)
See details
125.52.110.203 - takes90 [23/Aug/2009:18:20:52 -0700] "POST /loarsh/greet HTTP/1.1" 500 113 "http://loarsh.appspot.com/loarsh/333D62B7647DD593777255D4248D6999.cache.html" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0; GTB6; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.04506.30; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729),gzip(gfe)" "loarsh.appspot.com"W 08-23 06:20PM 52.006
com.appspot.loarsh.server.GreetingServiceImpl deleteData: key2
E 08-23 06:20PM 52.029
javax.servlet.ServletContext log: Exception while dispatching incoming RPC call
com.google.gwt.user.server.rpc.UnexpectedException: Service method 'public abstract java.lang.Integer com.appspot.loarsh.client.GreetingService.deleteData(long)' threw an unexpected exception: java.lang.NullPointerException
at com.google.gwt.user.server.rpc.RPC.encodeResponseForFailure(RPC.java:360)
at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:546)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.processCall(RemoteServiceServlet.java:166)
at com.google.gwt.user.server.rpc.RemoteServiceServlet.doPost(RemoteServiceServlet.java:86)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:713)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at com.google.apphosting.runtime.jetty.SaveSessionFilter.doFilter(SaveSessionFilter.java:35)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.runtime.jetty.AppVersionHandlerMap.handle(AppVersionHandlerMap.java:237)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:313)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:830)
at com.google.apphosting.runtime.jetty.RpcRequestParser.parseAvailable(RpcRequestParser.java:76)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
at com.google.apphosting.runtime.jetty.JettyServletEngineAdapter.serviceRequest(JettyServletEngineAdapter.java:139)
at com.google.apphosting.runtime.JavaRuntime.handleRequest(JavaRuntime.java:235)
at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4823)
at com.google.apphosting.base.RuntimePb$EvaluationRuntime$6.handleBlockingRequest(RuntimePb.java:4821)
at com.google.net.rpc.impl.BlockingApplicationHandler.handleRequest(BlockingApplicationHandler.java:24)
at com.google.net.rpc.impl.RpcUtil.runRpcInApplication(RpcUtil.java:359)
at com.google.net.rpc.impl.Server$2.run(Server.java:820)
at com.google.tracing.LocalTraceSpanRunnable.run(LocalTraceSpanRunnable.java:56)
at com.google.tracing.LocalTraceSpanBuilder.internalContinueSpan(LocalTraceSpanBuilder.java:516)
at com.google.net.rpc.impl.Server.startRpc(Server.java:775)
at com.google.net.rpc.impl.Server.processRequest(Server.java:348)
at com.google.net.rpc.impl.ServerConnection.messageReceived(ServerConnection.java:436)
at com.google.net.rpc.impl.RpcConnection.parseMessages(RpcConnection.java:319)
at com.google.net.rpc.impl.RpcConnection.dataReceived(RpcConnection.java:290)
at com.google.net.async.Connection.handleReadEvent(Connection.java:428)
at com.google.net.async.EventDispatcher.processNetworkEvents(EventDispatcher.java:762)
at com.google.net.async.EventDispatcher.internalLoop(EventDispatcher.java:207)
at com.google.net.async.EventDispatcher.loop(EventDispatcher.java:101)
at com.google.net.rpc.RpcService.runUntilServerShutdown(RpcService.java:251)
at com.google.apphosting.runtime.JavaRuntime$RpcRunnable.run(JavaRuntime.java:374)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
at com.appspot.loarsh.server.GreetingServiceImpl.deleteData(GreetingServiceImpl.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.google.apphosting.runtime.security.shared.intercept.java.lang.reflect.Method_$3.run(Method_.java:149)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.apphosting.runtime.security.shared.intercept.java.lang.reflect.Method_.privilegedInvoke(Method_.java:147)
at com.google.apphosting.runtime.security.shared.intercept.java.lang.reflect.Method_.invoke(Method_.java:120)
at com.google.gwt.user.server.rpc.RPC.invokeAndEncodeResponse(RPC.java:527)
... 43 more



下記のようにKeyの定義がLongだとうまくいかないので、
Keyに変えてやってみる。

// @PrimaryKey
// @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
// private Long id;

@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;

その際に、一緒にKey→longの変換

key.getId()

long →からKeyへの変換

Key k = KeyFactory.createKey(MapData.class.getSimpleName(), key);

を行ってやってみてもうまくいかない。

しかし、いろいろ動作させているうちに本日登録したデータに関しては、
うまく動作することがわかった。

もしかすると、昔登録したデータに関しては、正しく動作しないのだろうか。

内部的になんか変わったりしているのかもしれないということで
納得することにする。

ちなみに今回追加したAppEngine側のコードはこんな感じです。
登録ユーザと、現在のユーザを比較して、処理を切り分けております。

public Integer deleteData(long key){
Integer ret =null;
PersistenceManager pm = PMF.get().getPersistenceManager();
try{
UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
Key k = KeyFactory.createKey(MapData.class.getSimpleName(), key);
MapData md = pm.getObjectById(MapData.class,k);
if (md.getAuthor().equals(user)){
pm.deletePersistent(md);
ret = new Integer(0);
}else{
md.addDownVote();
ret = new Integer(1);
}
}finally{
pm.close();
}
return ret;
}


2009年8月22日土曜日

送るのフォルダの場所をDelphiで取得する方法

Windowsの特殊フォルダの情報を取得する方法。
これを取得するためには、

下記のような感じで書けば言いようです。


if SHGetSpecialFolderLocation(0, CSIDL_SENDTO, pidl) = NOERROR then
begin
try
if SHGetPathFromIDList(pidl, PPath) then
Result := PPath;
finally
CoTaskMemFree(pidl);
end;
end;



参考にしたサイトはこちら。
http://www.delphidabbler.com/articles?article=12

SHGetSpecialFolderLocationを利用すれば、Windowsのほかのいろいろな
特殊フォルダの場所を取得できるようです。

こちらを利用して、私も簡単なプログラムを作ってみました。
それが、こちらです。
http://mitools.blogspot.com/2009/08/blog-post.html

2009年8月12日水曜日

DelphiとJavaの連携

Delphiで作ったプログラムをJavaから呼び出す方法で一番いい方法は
何かなと探していたところ、下記のサイトが一番言い感じだった。

http://www.pacifier.com/~mmead/jni/delphi/

このページには、DelphiからJavaのプログラムを呼ぶサンプルと
JavaからDelphiを呼ぶサンプルの2つがある。

JavaからDelphiを呼び出すほうは、JavaクラスからDelphiのプロジェクトファイルを
生成するプログラムがあり、これが便利。
(通常のJNIにおける、Javahコマンドに該当する部分です。)

これを使えば、数秒でスケルトンは作れてしまう。そのツールは、こちら、。
また、DelphiからJavaを呼び出すサンプルはこちら、

Download

このファイルを回答して、javaファイルをコンパイルして、classファイルを作ってから
Delphiを実行すると動作します。

java側にHttpのやり取りのロジックが書かれていて、それをJava、Delphi間で
やり取りしているサンプルです。

2009年7月31日金曜日

GWTでファイルアップロード

現在のGoogle App Engineのアプリケーションにいつか追加したいな
と思っているのが、CSVファイルの取り込み機能。

いままで、ファイルのアップロードと言うロジックは書いたことないので手さぐり状態で
調べてみる。

とりあえず、下記を利用すれば出来ました。
(1)GWT側
FileUploadコンポーネント
http://google-web-toolkit.googlecode.com/svn/javadoc/1.6/com/google/gwt/user/client/ui/FileUpload.html

(2)Google App Engine側
Google App Engine for Javaを使ってみよう!(2)Images Java API の使い方

(1)のサンプルコードの

form.setAction("/myFormHandler");

の部分を(2)で定義してあげたものに替えてあげればOKです。

(2)のサンプルどおりにやるのであれば、この部分は、
form.setAction("/imagetest");

となります。


また、リクエストが帰ってきたときのロジックは、下記の部分の
event.getResults()にサーバの応答がhtmlが帰ってくるので、
ここを替えてあげれば、サーバからの応答も表示することが出来ました、


form.addSubmitCompleteHandler(new FormPanel.SubmitCompleteHandler() {
public void onSubmitComplete(SubmitCompleteEvent event) {
// When the form submission is successfully completed, this event is
// fired. Assuming the service returned a response of type text/html,
// we can get the result text here (see the FormPanel documentation for
// further explanation).
Window.alert(event.getResults());
}
});


ファイルの送信は、 gwtuploadというのもあるみたいなんで、
http://code.google.com/p/gwtupload/
次は、これを試してみようと思う。

2009年7月29日水曜日

地図から検索 マイナー機能追加

私の作成したアップリケーション地図から検索を少しだけ機能改善しました。

しばらく、放置してたので気が向いたら徐々にいろいろな機能を増やしていきたいと
思っています。

検索結果のラベル検索時に

・選択中のラベルの色を変更
・選択したお店を地図と連動

ということをするように修正しました。

この機能により、今まで登録したデータの位置が微妙に正しくない場合があることが
わかったので、徐々に直していきます。

クリックイベントのソースはこんな感じ。

ClickHandler newch = new ClickHandler(){
public void onClick(ClickEvent event) {
clickHandler.onClick(event);
LatLng point = LatLng.newInstance(clientMapData.getLatitude()
,clientMapData.getLongitude());
Marker marker = new Marker(point);
map.addOverlay(marker);
map.setCenter(point);
title.setStyleName("selectedLabel");
}
};


title.setStyleName("selectedLabel");
の部分の引数は、cssファイルへ記述しておく。

今回は適当にこんな感じ
========================================
.normalLabel {
color: black;
background-color: white;
}
.selectedLabel {
color: blue;
background-color:#D7F5FF;
}
========================================

ご意見などあれば、いただけると有難いです。

2009年7月21日火曜日

Google Plugin for Eclipse と  Eclipse 3.5

最近、Eclipse 3.5が出たんだけど、Google Plugin for Eclipseとの相性は
どうなんだろうと入れるのに躊躇していたら、下記のページに記述がありました。

http://code.google.com/intl/ja/appengine/docs/java/tools/eclipse.html

下記の一文があり、

=====================================
Please note that the plugin does not yet support the recently released Eclipse 3.5 (Galileo). In the mean time, you can download Eclipse 3.4 from the Eclipse web site.
=====================================

つまりは、しばらくは、eclipse3.4のほうを使ってねということみたい。

なんで、我が家のeclipseはしばらく、3.4のままにしておくことにする。

2009年7月15日水曜日

Google App Engine for Java がバージョンアップ

Google App Engine for Javaのバージョンが1.2.2になったようです。

Google App Engine Blog: Google App Engine for Java SDK 1.2.2 Released

同時にGoogle Web Toolkit も1.7にVerUpしていました。

What's New in GWT 1.7?

とりあえず、ecliseのsoftware Updateにて更新してみる。
あとは、eclipseプロジェクトの右クリックでgoogleを選択して、バージョンを
替えておけば更新完了。

とりあえず、Google App Engineで目につく目新しい機能としては、
開発環境のデータベース閲覧機能でしょうか。

新しいバージョンに更新後、

http://localhost:8080/_ah/admin/

へアクセスすると、ローカルのデータベースを参照できるようになりました。

これで、テスト用のデータを削除したりすることが簡単にできるようになりました。

その他の新機能についてもこれから読んでみてこれはと思うものがあれば、書き足していきます。

2009年6月29日月曜日

「地図から検索」を公開

ずっと以前から作ってみたいなと思っていたアプリケーションを
作ってみた。

初期版なので、まだまだ機能が弱い部分もあるけど、とりあえず、
公開することにしてみる。

どういうアプリケーションかと言うと、自分の身の回りにある
イベント情報やお得な情報を共有できるようなサイト。
しかも、それは、地図上を探索することによって見つけられる
というようなサイトを作ってみたかった。

本来は、もっと地域情報の共有を図れるようにしたかったのですが、
情報の陳腐化が激しい分、最初は、ハードルが高いかなと言うことで、
まずは、お店のチラシの情報を登録できるというようなアプリケーションにしました。

アプリケーションのURLはこちら。
http://loarsh.appspot.com/

使い方は、イメージをつかむために上記のURLをクリックしたら
「表示」ボタンを押してください。
右側に、この地域の周辺のチラシ情報のリンクが出てきます。

登録する場合には、下のほうから、
下記の項目を入力して「登録」ボタンを押してください。
URL:  チラシのURL
タイトル: お店の名前
住所:   お店の住所を入力後確定ボタンを押してください。
      住所がわからない場合には、近所で検索して、マーカーを移動させても
      OKです。

現状は、画面から削除機能が無いので、誤って登録してしまった場合には、
ご連絡いただければ削除します。
#削除機能は、近々につけようと思います。

なおこのアプリケーションは、Googleの技術を利用して作成しております。

ご意見、ご要望はこちらからコメントしていただければと思います。
ご要望いただいたものを優先的に改善していきたいと思います。

2009年6月24日水曜日

Google App EngineのDatastoreでカラム追加してみる

本日は、既存のデータに対して、プロパティの追加を行ったらどうなるんだろうと
試したくなって試してみた。

データベースで言うところのカラム追加です。

既存のentityに対し、下記のような感じでプロパティを追加してみたところ、

@Persistent
private int updateCount;

ロジック自体は修正していないもののエラーが出るようになったしまった。

null値がうんぬんと書かれていたので、intのようなprimitiveな型は追加できないのかと
思い、Integerというオブジェクト型にしてみたところ、うまく動作するようだった。

直感的な動作どおり、追加前に入っていたデータは、nullとして入っているようです。

つまり、entityのプロパティを追加する場合には、Integerなどのクラスにしなくては
いけないということになるのでしょうか。

2009年6月23日火曜日

GoogleMap(GWT)でDrag後のMarkerの位置取得

昨日の続きで本日は、GWTで作ったGoogleMap上でドラッグしたMarkerの位置を取得してみた。

本日、新たに利用したクラスはこちら。
MarkerDragEndHandler


こんな感じで書いてみたら思ったとおりに動作してくれました。
=======================================

Marker marker = new Marker(point,mo);
marker.addMarkerDragEndHandler(new MarkerDragEndHandler(){
public void onDragEnd(MarkerDragEndEvent event){
Marker mk = event.getSender();
displayLatLng(mk.getLatLng());
}
});


=======================================

毎日、少しずつ進めていきます。

2009年6月22日月曜日

GoogleMap(GWT)で動かせるMarkerを配置する

Google Web Toolkit を使ったGoogleMapにてMarkerを配置する歳に
そのマーカーをドラッグできるようにする方法について書いてみます。

だいたい、大まかには、Markerクラスを生成する時に、MarkerOptionsを指定してあげればよさそうです。
ちなみに下記のような感じで書いたら思ったように動作してくれました。
=========================================

MarkerOptions mo = MarkerOptions.newInstance();
mo.setClickable(true);
mo.setDraggable(true);
Marker marker = new Marker(point,mo);
marker.setDraggingEnabled(true);
map.addOverlay(marker);

=========================================

参考にしたJavadocはこちら。
Marker
MarkerOptions

2009年6月21日日曜日

Google App Engine SDKの更新

最近、GoogleAppEngineの開発環境を起動すると、下記のエラーが出てきて
どうやって直すのかと適当にやってみた。


WARN] ********************************************************
There is a new version of the SDK available.
-----------
Latest SDK:
Release: 1.2.1
Timestamp: Sat May 09 09:49:14 JST 2009
API versions: [1.0]

-----------
Your SDK:
Release: 1.2.0
Timestamp: Sat Apr 04 06:53:20 JST 2009
API versions: [1.0]

-----------
Please visit http://code.google.com/appengine for the latest SDK.
********************************************************



最新のSDKはeclipseのsoftware updateから更新していたので、
プロジェクトのGoogleAppEngineの蘭を右クリックして、propertyをクリックして
そこから最新バージョンを選ぶことにより解消された。

2009年6月18日木曜日

正規表現テストツール

GoogleAppEngineの練習もかねてスクラッチでプログラムを作ってみた。

簡単な、正規表現のチェック用プログラムです。
ちなみに言葉があっているかどうかはわかりませんが、2ヶ国語に対応させて見ました。

昨日書いた「?locale=de」が聞かないというのは、開発環境だけで、
実際のサーバでは正しく動作するようでした。

画面を作るのは、やっぱり大変ですね。
画面開発において、Delphiの簡単さを痛切に感じました。

ちなみにサイトのURLはこちら。
http://gaetooltk.appspot.com/

英語版はこちら
http://gaetooltk.appspot.com/?locale=de

#locale=deというのは、サンプルの影響を受けました。

国際化対応もめんどくさいけど、こんなに簡単にできるのはやっぱり便利ですね。

2009年6月16日火曜日

GWTで多言語対応の方法

以前は、ふ~~ん。こんなのあるんだぁと読み飛ばしていた、
多言語対応の方法について試してみる。

参考にしたページは下記のページ。
Internationalizing a GWT Application

意外に難しいかと思ったら簡単だった。
単純化すると、下記の手順でできる。

1.Constantsを拡張したInterface StockWatcherConstants を作成。
  (デフォルト文字列は、@DefaultStringValueアノテーションをつけておく)
2.同じフォルダにStockWatcherConstants _de.properties
というファイルを作っておく
  (deは言語により変わってくる)

ファイルの内容は、1で作成したInterFaceのメソッドに対応して下記のような
テキストファイルになる

============================
stockWatcher = Aktienbeobachter
symbol = Symbol
price = Kurs
change = Änderung
remove = Entfernen
add = Hinzufügen
============================

3.ソース本文は、下記のように宣言する

private StockWatcherConstants constants = GWT.create(StockWatcherConstants.class);

このインスタンスから、リソースストリングを取得する。

4.StockWatcher.gwt.xmlに下記の部分を追記


<extend-property name="locale" values="de"/>


これで、多言語対応が完了なはず。

ただ、実際に動作してみると、
http://localhost:8888/StockWatcher.html?locale=de
という風にアクセスしても正しく動かなかった。

ただ、もう一つの方法であるHTMLファイルに下記の分を記述する方法


<meta name="gwt:property" content="locale=de">


だとうまく動作してくれた。

バグなのかどうか良くわからないけども、とりあえず1つの方法はうまく動作することが
わかったので、よかった。

これで、多言語対応のアプリケーションも作成できることがわかった。

2009年6月11日木曜日

Google App Engineのデータ設計

GoogleAppEngineのデータストアは、普通のRDBに慣れてしまった人だと、
やや強い制約がある。

制約については、下記に書いてあるとおりになるのだけど、
http://code.google.com/intl/ja/appengine/docs/java/datastore/queriesandindexes.html#Restrictions_on_Queries

簡単に書いておくと下記のような感じ
  • 不等号のWhere条件は、1つのカラムしか指定できない
  • OR条件や否定の条件は利用できない
  • 当然、計算式を含む条件も設定できない

これを回避するためには、データの設計についても

従来のRDBとは異なる設計をしなくてはいけない。

おそらく、下記のようなプロパティを持つオブジェクトが合った時に

・賛成意見

・反対意見

反対意見が50%を超えるものを検索するというようなアプリケーションを作る場合には、

従来のRDBであれば、「反対意見>賛成意見」みたいなWhere節を書けばいいのだろうけど

Google App Engineの場合には、更新時に、平均値も計算して保管しておく必要が

あるのだと思う。

そして、「平均値>50%」みたいな検索をすることになると思う。

実際に、データ型を決めてみたら結構気持ち悪いくらい冗長なデータ型になってしまった

一応、下記のような記事もあったので、メモがてらにリンクしておく。

クラウド環境ではデータベースは「非正規化」して使う?

GWTでGoogleユーザ認証を行う

今までやったところで、とりあえず、自分が描くアプリケーションを
作ってみている。

そこで、一つ、やり方がわからない部分が出てきた。

それは、GWTを使ってかつGoogleのアカウント認証を行うのはどうしたらいいのだろうか。

ちょっと調べてみると、下記のページにサンプルが合ったので、早速やってみた。

http://code.google.com/intl/ja/webtoolkit/tutorials/1.6/appengine.html#user
このサンプルでは、StockWatcherをさらに改良して、ユーザごとに管理できるようにする
というサンプル。

基本的には、リンク先のように、

・ログインを管理するサービスの作成。
 LoginService.java:
 LoginServiceAsync.java
 LoginServiceImpl.java

・GWT-RPCを使いこれらの情報をやり取りするためのクラスの作成。
 LoginInfo.java

あとは、
com.google.gwt.user.client.ui.Anchor
というクラスと使ってサービスから帰ってきたログイン用のURLにリンクを張る

という感じでやると、GWTで作った画面もログインが管理できるようになるらしい。

たぶん、これでやりたいことができるようになってきた。

Eclipseプロジェクトで途中からGoogle App Engine にチェックを入れた場合

最初にプロジェクトを作成する時には、Google App Engine にチェックを入れていなくて
途中でプロパティから変更してチェックを入れてみたら、エラーになってしまった。

これは、不具合なのかもしれないが、とりあえず、
他のプロジェジェクトから下記のファイルをコピーしてあげることにより
動くようになった。

appengine-web.xml
logging.properties

途中からの変更はまぁしないだろうけど、もしした場合には、そうすれば
大丈夫みたいです。

2009年5月28日木曜日

appengine-web.xmlのversionの使い方

本日始めて、Google App Engineを公開できるようになったのだけど、
最初「appengine-web.xml」のversionの記述ってUploadするために
ふやさないとだめなんだと思っていたのだけど、そうではないのですね。

こちらを帰ると、まったく別のところにUploadされ、2つのバージョンを
混在することが出来るための機能のようです。

このバージョンの切り替えは、管理画面より、Versionsというメニューから
切り替えが出来るようです。

やっぱり、よく出来てるなと感心する。

Google App Engineでデータの絞込み

本日は、下記を読みながらGoogle App EngineでIndexが作成される仕組みと
検索条件のつけ方(SQLで言うWhere節の指定の仕方について)読んで見た。

そんでもって、実際に使ってみた。

//最初は、検索対象をクラスで指定する。
Query query = pm.newQuery(Employee.class);
//ここで検索条件の指定。lastNameParamはSQLで言う
//バインドパラメータのようなもの。
query.setFilter("lastName == lastNameParam");
// order by の指定
query.setOrdering("hireDate desc");
//ここで、バインドパラメータの型を宣言する。
query.declareParameters("String lastNameParam");
//実際の検索処理。
List results = (List) query.execute("Smith");

こんな感じです。
インデックスがいつできるかと言うと、このWhere条件やソート条件を
指定したときにどうやら勝手に作成に走るようだ。

これらが、ソースコード上かかれると、裏側で
「datastore-indexes.xml」というファイルが作成され
それでインデックスが作成されるという流れのようです。

ちなみに本日より、ついにGoogleAppEngineForJavaも一般公開されたということで
私もいよいよUploadできるようになりました。

サンプルアプリケーションのゲストブックに今まで試す意味をこめて
データのUpdateをするボタンと自分が書き込みしたものすべてを削除するボタン
をつけてみたものです。

http://takes90.appspot.com/

2009年5月27日水曜日

Google App Engineでデータの更新・削除

本日は、Google App Engineでデータベースの更新・削除をしてみた。
簡単に出来るんですね。

http://code.google.com/intl/ja/appengine/docs/java/datastore/creatinggettinganddeletingdata.html#Keys

まずは、datastoreからデータを取得する。

PersistenceManager pm = PMF.get().getPersistenceManager();
Employee e = pm.getObjectById(Employee.class, user.getEmail());

そして、更新は、普通にオブジェクトを更新。

e.setTitle(newTitle);

そして、下記のメソッドを読んだ瞬間にデータが削除されるようです。

pm.close();

削除は、こんな感じ。

pm.deletePersistent(e);

一通りのデータ操作は、こんな感じだろうか。

2009年5月26日火曜日

GWTでGoogleMapAPIを使ってみる。

下記のページ当たりを参考に、GoogleWebToolkitでGoogleMapを使ってみる。


Google API Libraries for GWT> Maps> GettingStarted

とりあえず、下記の手順でサンプルプログラムが起動できるようになる。



project download pageにてgwt-maps-1.0.4.zipをダウンロードして解凍する。

その中にある「gwt-maps.jar」をクラスパスに追加

XXXXXX.gwt.xmlファイルに下記の2つの行を追加。


============================================
<script src="http://maps.google.com/maps?gwt=1&amp;file=api&amp;v=2" />
<inherits name="com.google.gwt.maps.GoogleMaps">
============================================



#とりあえず、localhostで実行している限りは、GooglmapAPIのkeyは不要のようです。
#公開するときには、おそらくKeyが必要になる。

APIのKEYに関しては、こちらを参照。
http://code.google.com/intl/ja/apis/maps/

とりあえず、これだけ準備して、あとは、下記ページの
http://code.google.com/docreader/#p=gwt-google-apis&s=gwt-google-apis&t=MapsGettingStarted
Add a map object to .java source

のソースをコピーしてあげると、上記リンク先のようなサンプルが実行されるようです。

とりあえず、あとはいろいろなAPIを調べてあげればいろいろ出来るんだろうか。

Google App Engineで保存に使える型

Google App Engineにてデータを保存する場合には、
datastoreという所に入れることになるのだけども、それの
制約などの仕様が書かれているドキュメントのメモ。

http://code.google.com/intl/ja/appengine/docs/java/datastore/dataclasses.html#Core_Value_Types

インデックスのある文字列は、500文字までなどの制約はあるが、
まぁ、普通に使用する分においては、なんら困らない仕様制限である

また、サポートしているCollectionクラスは、下記のリンク先の通りだそうです。
http://code.google.com/intl/ja/appengine/docs/java/datastore/dataclasses.html#Collections

これだけ利用できれば、何不自由なく出来そうである。

2009年5月23日土曜日

Google App EngineでJDOを使う

Google App EngineでJDOを使ってみる。
http://code.google.com/intl/ja/appengine/docs/java/gettingstarted/usingdatastore.html

GoogleAppEngineにおいて、データを保存するための方法の一つなんだと思う。
これも、JDOについて知らなくてもきちんと読めるようにドキュメントは配慮されている。

自分もまったく知らないで読んでみたんだけども、とりあえず、下記のような
ことがわかった。
・とりあえず、クラスを作り、それを保存する仕組み
  (ソースコード上に@Persistentなんかを書くことにより、あとは、このフレームワークが
   勝手にやってくれている)

というような感じで理解できた。

ここでは、大まかには、下記の手順で作成していくことになる。
1.jdoconfig.xml の設定(eclipseで作った場合には、勝手に設定してくれている)
2.保存するデータのGreetingクラスを作成。
3.PMFクラスの作成(javax.jdo.PersistenceManagerFactoryを呼び出すsingletonラッパー)
4.でこれらを利用して、ゲストブックで入力された内容を保存するクラス
   SignGuestbookServlet.javaを作成。

実際の保存するロジックはこんな感じのようです。

Greeting greeting = new Greeting(user, content, date);
PersistenceManager pm = PMF.get().getPersistenceManager();
try {
pm.makePersistent(greeting);
} finally {
pm.close();
}


で読み出すに相当する部分が下記あたり


//クエリの部分
PersistenceManager pm = PMF.get().getPersistenceManager();
String query = "select from " + Greeting.class.getName();
List greetings = (List) pm.newQuery(query).execute();

//データを取り出しの部分
for (Greeting g : greetings) {
       g.getAuthor().getNickname()
       g.getContent()


あとは、このQueryがどんな感じのことができるのかというのをいろいろ試してみたい。
まずは、次は、ここら辺を呼んでいくことにしたいと思う。
Queries and Indexes.

とりあえず、ここら辺までで、簡単なデータの保存と取出しまでは出来るようになった。

Google App EngineでJSPを使う

本日は、GoogleAppEngineにてJSPを使うという下記のページを
やってみる。

http://code.google.com/intl/ja/appengine/docs/java/gettingstarted/usingjsps.html

このページで図ることは、下記のようなもの
・JSPファイルとは何か
・JSPファイルでWebページの作り方
・Google App Engineでのログの出力の仕方
      logging.properties でログレベルなどの設定。

リンク先のように

war直下にguestbook.jsp というファイルを作って、
war/WEB-INF/web.xml にwelcome pageを設定してあげるという流れで完成。

ここまでで、前回は、javaソースで書いていたものをJSPに書き換えるという
部分が完成する。
今までは、JSPなんて書いたこともなかったので動作の仕組みを知らなかったのだけど、
裏側でJavaソースに書き換えコンパイルするというのが発生するのですね。
だから前回はjavacがないと怒られたのか。
(実際は、具estbook_jsp.javaというようなファイルができていてそれが
コンパイルされたものがありました。)

JSPを使うのが初めてという場合でも、きちんと説明が書かれているあたりは、
配慮があっていいです。

Googleのテクノロジに触れるというのはいろいろいい刺激にはなる。

そして、後半では、ゲストブックを作成するために、テキスト欄と送信ボタンを
jspファイルに埋め込んで、この送信ボタンのリクエストを処理する部分を
ログの表示のみ作ってこのページは、完了。

次のページでは、いよいよデータの保存の方法ですね。

2009年5月21日木曜日

Google App EngineでUsers Serviceを使ってみる。

次に、こちらを見ながらユーザサービスを使ってみる。

http://code.google.com/intl/ja/appengine/docs/java/gettingstarted/usingusers.html

これを利用することにより、Googleのアカウントでの認証などのロジックを書くことなく、
ユーザごとの管理ができるようになるみたい。

これも、下記のコードだけで
「ようこそ。XXXXさん」

ということが表示できるのですごいですね。

ちなみに下記のサンプル(上記のリンクのサンプルそのまま)はログインしていない場合には、
ログイン画面に飛ぶというようなロジックになっています。


UserService userService = UserServiceFactory.getUserService();
User user = userService.getCurrentUser();
if (user != null) {
resp.setContentType("text/plain");
resp.getWriter().println("Hello, " + user.getNickname());
} else {
resp.sendRedirect(userService.createLoginURL(req.getRequestURI()));
}

Google App Engine Java でプロジェクトの作成

Eclipseを使ってGoogle App Engine Java でプロジェクトの作成をしてみる。

http://code.google.com/intl/ja/appengine/docs/java/gettingstarted/creating.html

上記のページを見ていけば、Hello,worldという文字を返すサーブレットができる。

ポイントはこんな感じだろうか。

web.xml は普通の記述と同じ。
appengine-web.xml はGoogle App Engine のアプリケーションUploadするときに利用するようです。

これらのファイルは、プロジェクトを作成すると自動的に生成されています。

あとは、eclipseからWebApplicationを選択し、

http://localhost:8080/guestbook

をブラウザで起動すると、出来上がり。

よくできてますね。あまりの手軽さに感心します。

2009年5月19日火曜日

GAEのデモアプリguestbookを動かしてみる。

下記のページを参考に Google App Engineのデモプログラム
である「GuestBook」を動かしてみる。
http://code.google.com/intl/ja/appengine/docs/java/gettingstarted/installing.html

指示通りに下記のコマンドを売ってみると

D:\eclipse\plugins\com.google.appengine.eclipse.sdkbundle_1.2.0.v200904062334>D:\eclipse\plugins\com.google.appengine.eclipse.sdkbundle_1.2.0.v200904062334\appengine-java-sdk-1.2.0\bin\dev_appserver.cmd appengine-java-sdk-1.2.0\demos\guestbook\war


下記のようなエラーになってしまった。


HTTP ERROR: 500Error running javac.exe compiler
RequestURI=/
Caused by:Error running javac.exe compiler
at org.apache.tools.ant.taskdefs.compilers.DefaultCompilerAdapter.executeExternalCompile(DefaultCompilerAdapter.java:473)
at org.apache.tools.ant.taskdefs.compilers.JavacExternal.execute(JavacExternal.java:47)
at org.apache.tools.ant.taskdefs.Javac.compile(Javac.java:931)
at org.apache.tools.ant.taskdefs.Javac.execute(Javac.java:757)
at org.apache.jasper.compiler.Compiler.generateClass(Compiler.java:382)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:472)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:451)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:439)
at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:511)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:295)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
at com.google.appengine.tools.development.PrivilegedJspServlet.access$101(PrivilegedJspServlet.java:23)
at com.google.appengine.tools.development.PrivilegedJspServlet$2.run(PrivilegedJspServlet.java:59)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.appengine.tools.development.PrivilegedJspServlet.service(PrivilegedJspServlet.java:57)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:268)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:126)
at com.google.appengine.tools.development.LocalResourceFileServlet.serveWelcomeFileAsForward(LocalResourceFileServlet.java:324)
at com.google.appengine.tools.development.LocalResourceFileServlet.maybeServeWelcomeFile(LocalResourceFileServlet.java:260)
at com.google.appengine.tools.development.LocalResourceFileServlet.doGet(LocalResourceFileServlet.java:118)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:693)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:306)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:313)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:830)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:514)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:396)
at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)
Caused by: java.io.IOException: Cannot run program "javac.exe": CreateProcess error=2, Žw’?‚?ƒtƒ@ƒ
at java.lang.ProcessBuilder.start(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.tools.ant.taskdefs.Execute$Java13CommandLauncher.exec(Execute.java:834)
at org.apache.tools.ant.taskdefs.Execute.launch(Execute.java:435)
at org.apache.tools.ant.taskdefs.Execute.execute(Execute.java:449)
at org.apache.tools.ant.taskdefs.compilers.DefaultCompilerAdapter.executeExternalCompile(DefaultCompilerAdapter.java:470)
... 51 more
Caused by: java.io.IOException: CreateProcess error=2, Žw’?‚?ƒtƒ@ƒ
at java.lang.ProcessImpl.create(Native Method)
at java.lang.ProcessImpl.(Unknown Source)
at java.lang.ProcessImpl.start(Unknown Source)
... 61 more
--- Nested Exception ---
java.io.IOException: Cannot run program "javac.exe": CreateProcess error=2, Žw’?‚?ƒtƒ@ƒ
at java.lang.ProcessBuilder.start(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.tools.ant.taskdefs.Execute$Java13CommandLauncher.exec(Execute.java:834)
at org.apache.tools.ant.taskdefs.Execute.launch(Execute.java:435)
at org.apache.tools.ant.taskdefs.Execute.execute(Execute.java:449)
at org.apache.tools.ant.taskdefs.compilers.DefaultCompilerAdapter.executeExternalCompile(DefaultCompilerAdapter.java:470)
at org.apache.tools.ant.taskdefs.compilers.JavacExternal.execute(JavacExternal.java:47)
at org.apache.tools.ant.taskdefs.Javac.compile(Javac.java:931)
at org.apache.tools.ant.taskdefs.Javac.execute(Javac.java:757)
at org.apache.jasper.compiler.Compiler.generateClass(Compiler.java:382)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:472)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:451)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:439)
at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:511)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:295)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
at com.google.appengine.tools.development.PrivilegedJspServlet.access$101(PrivilegedJspServlet.java:23)
at com.google.appengine.tools.development.PrivilegedJspServlet$2.run(PrivilegedJspServlet.java:59)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.appengine.tools.development.PrivilegedJspServlet.service(PrivilegedJspServlet.java:57)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:268)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:126)
at com.google.appengine.tools.development.LocalResourceFileServlet.serveWelcomeFileAsForward(LocalResourceFileServlet.java:324)
at com.google.appengine.tools.development.LocalResourceFileServlet.maybeServeWelcomeFile(LocalResourceFileServlet.java:260)
at com.google.appengine.tools.development.LocalResourceFileServlet.doGet(LocalResourceFileServlet.java:118)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:693)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:306)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:313)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:830)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:514)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:396)
at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)
Caused by: java.io.IOException: CreateProcess error=2, Žw’?‚?ƒtƒ@ƒ
at java.lang.ProcessImpl.create(Native Method)
at java.lang.ProcessImpl.(Unknown Source)
at java.lang.ProcessImpl.start(Unknown Source)
... 61 more
Caused by:java.io.IOException: Cannot run program "javac.exe": CreateProcess error=2, Žw’?‚?ƒtƒ@ƒ
at java.lang.ProcessBuilder.start(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.tools.ant.taskdefs.Execute$Java13CommandLauncher.exec(Execute.java:834)
at org.apache.tools.ant.taskdefs.Execute.launch(Execute.java:435)
at org.apache.tools.ant.taskdefs.Execute.execute(Execute.java:449)
at org.apache.tools.ant.taskdefs.compilers.DefaultCompilerAdapter.executeExternalCompile(DefaultCompilerAdapter.java:470)
at org.apache.tools.ant.taskdefs.compilers.JavacExternal.execute(JavacExternal.java:47)
at org.apache.tools.ant.taskdefs.Javac.compile(Javac.java:931)
at org.apache.tools.ant.taskdefs.Javac.execute(Javac.java:757)
at org.apache.jasper.compiler.Compiler.generateClass(Compiler.java:382)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:472)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:451)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:439)
at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:511)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:295)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
at com.google.appengine.tools.development.PrivilegedJspServlet.access$101(PrivilegedJspServlet.java:23)
at com.google.appengine.tools.development.PrivilegedJspServlet$2.run(PrivilegedJspServlet.java:59)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.appengine.tools.development.PrivilegedJspServlet.service(PrivilegedJspServlet.java:57)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:268)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:126)
at com.google.appengine.tools.development.LocalResourceFileServlet.serveWelcomeFileAsForward(LocalResourceFileServlet.java:324)
at com.google.appengine.tools.development.LocalResourceFileServlet.maybeServeWelcomeFile(LocalResourceFileServlet.java:260)
at com.google.appengine.tools.development.LocalResourceFileServlet.doGet(LocalResourceFileServlet.java:118)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:693)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:306)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:313)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:830)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:514)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:396)
at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)
Caused by: java.io.IOException: CreateProcess error=2, Žw’?‚?ƒtƒ@ƒ
at java.lang.ProcessImpl.create(Native Method)
at java.lang.ProcessImpl.(Unknown Source)
at java.lang.ProcessImpl.start(Unknown Source)
... 61 more
Caused by:java.io.IOException: CreateProcess error=2, Žw’?‚?ƒtƒ@ƒ
at java.lang.ProcessImpl.create(Native Method)
at java.lang.ProcessImpl.(Unknown Source)
at java.lang.ProcessImpl.start(Unknown Source)
at java.lang.ProcessBuilder.start(Unknown Source)
at java.lang.Runtime.exec(Unknown Source)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.apache.tools.ant.taskdefs.Execute$Java13CommandLauncher.exec(Execute.java:834)
at org.apache.tools.ant.taskdefs.Execute.launch(Execute.java:435)
at org.apache.tools.ant.taskdefs.Execute.execute(Execute.java:449)
at org.apache.tools.ant.taskdefs.compilers.DefaultCompilerAdapter.executeExternalCompile(DefaultCompilerAdapter.java:470)
at org.apache.tools.ant.taskdefs.compilers.JavacExternal.execute(JavacExternal.java:47)
at org.apache.tools.ant.taskdefs.Javac.compile(Javac.java:931)
at org.apache.tools.ant.taskdefs.Javac.execute(Javac.java:757)
at org.apache.jasper.compiler.Compiler.generateClass(Compiler.java:382)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:472)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:451)
at org.apache.jasper.compiler.Compiler.compile(Compiler.java:439)
at org.apache.jasper.JspCompilationContext.compile(JspCompilationContext.java:511)
at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:295)
at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:292)
at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:236)
at com.google.appengine.tools.development.PrivilegedJspServlet.access$101(PrivilegedJspServlet.java:23)
at com.google.appengine.tools.development.PrivilegedJspServlet$2.run(PrivilegedJspServlet.java:59)
at java.security.AccessController.doPrivileged(Native Method)
at com.google.appengine.tools.development.PrivilegedJspServlet.service(PrivilegedJspServlet.java:57)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:268)
at org.mortbay.jetty.servlet.Dispatcher.forward(Dispatcher.java:126)
at com.google.appengine.tools.development.LocalResourceFileServlet.serveWelcomeFileAsForward(LocalResourceFileServlet.java:324)
at com.google.appengine.tools.development.LocalResourceFileServlet.maybeServeWelcomeFile(LocalResourceFileServlet.java:260)
at com.google.appengine.tools.development.LocalResourceFileServlet.doGet(LocalResourceFileServlet.java:118)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:693)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:806)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1093)
at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:712)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at com.google.apphosting.utils.jetty.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:54)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:306)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:313)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:506)
at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:830)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:514)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:381)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:396)
at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:442)
Powered by Jetty://


エラーメッセージよりjavacがみつからなかったっぽいので、javacへのパスが張られているか
確認してみると張られていなかった。ので、改めて環境変数PATHをセット後、再実行するとうまく
実行できた。

結構りっぱなアプリケーションができそうな感じですね。

実行してみた結果は、こんな感じでした。

GWT RPCを試してみる

本日は、下記のページを参考にしながら、GWT RPCを試してみる。
http://code.google.com/intl/ja/webtoolkit/tutorials/1.6/RPC.html

こちらで、GWT(クライアント側)から簡単にサーバ側のモジュールを
呼び出すことができる。
また、エラー発生時の処理についても詳しく書かれている。

詳細は、上記のページの通りだけど大まかには、下記のような感じで
作成する。

1.StockPriceService interfaceというインターフェースを作成
2.StockPriceServiceImpl classの作成
3.StockPriceServiceAsyncクラスの作成
  (呼び出しの正常終了、異常終了時に呼び出されるイベント)

実際に呼び出すときはこんな感じのコードになる。


//RPC呼び出し用のクラスの作成。
if (stockPriceSvc == null) {
stockPriceSvc = GWT.create(StockPriceService.class);
}

// 非同期呼び出しのためにCallBack用オブジェクトが必要
AsyncCallback callback = new AsyncCallback() {
public void onFailure(Throwable caught) {
// 異常時の処理はここに記述する。
}

public void onSuccess(StockPrice[] result) {
//正常終了時はこれが呼ばれる
     updateTable(result);
}
};

// サーバ側の関数の呼び出し。
stockPriceSvc.getPrices(stocks.toArray(new String[0]), callback);



非常にシンプルで簡単で、きれいな仕組みですね。

異常時のサンプルコードもリンク先にあるので、興味があれば、
リンク先のサイトを読むといいと思います。

2009年4月29日水曜日

ブラウザ時計

昨日、GWTで遊んでみて作ってみた時計もどきをWebにもアップしてみました。

http://www.ac.auone-net.jp/~takes90/StockWatcher/StockWatcher.html

GWTを使えば、こんなアプリケーションなら簡単に作れてしまうということですね。

GWTでTimmerを使ってみる

本日は、下記を読んでいるうちにTimmerクラスを使ってみたくなった。

http://code.google.com/intl/ja/webtoolkit/tutorials/1.6/codeclient.html

これを使ってとりあえず、時計を作ってみる。

本日新たに使ってみたクラスは、

Timer (Google Web Toolkit Javadoc)
これは、定期的に実行するようなことができ、

DateTimeFormat (Google Web Toolkit Javadoc)
これは、日付を文字列に変える事ができ

あと、ついでに

Random

これは、ランダムな数字を生成することができ。

も使ってみる。

とりあえず、自分の作ってみたいイメージどおり物もができた。

ちなみにこんな感じ。
(時計は、もちろんちゃんと動いています。)



こちらのソースコードはこんな感じで書いてみました。

クライアント側の記述の仕方はなんとなくわかってきた感じです。

package com.google.gwt.sample.stockwatcher.client;

import java.util.Date;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.user.client.Command;
import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.ClickListener;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.MenuBar;
import com.google.gwt.user.client.ui.MenuItemSeparator;
import com.google.gwt.user.client.ui.MultiWordSuggestOracle;
import com.google.gwt.user.client.ui.PasswordTextBox;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.SuggestionEvent;
import com.google.gwt.user.client.ui.SuggestionHandler;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
* Entry point classes define onModuleLoad().
*/
public class StockWatcher implements EntryPoint {
/**
* The message displayed to the user when the server cannot be reached or
* returns an error.
*/
private static final String SERVER_ERROR = "An error occurred while "
+ "attempting to contact the server. Please check your network "
+ "connection and try again.";

/**
* Create a remote service proxy to talk to the server-side Greeting service.
*/
private final GreetingServiceAsync greetingService = GWT
.create(GreetingService.class);

Label timeLabel = new Label();
Label randomNumberLabel = new Label();
Timer t = new Timer() {
public void run() {
timeLabel.setText("時刻:"+DateTimeFormat.getFormat("yyyy/MM/dd HH:mm:ss").format(new Date()));
randomNumberLabel.setText("ランダム数字:"+Random.nextInt(1000));
}
};
/**
* This is the entry point method.
*/
public void onModuleLoad() {
Button stopbtn = new Button("停止");
Button startbtn = new Button("開始");
stopbtn.addClickListener(new ClickListener(){
public void onClick(Widget sender) {
// Create a new timer that calls Window.alert().
t.cancel();
}
});
startbtn.addClickListener(new ClickListener(){
public void onClick(Widget sender) {
// Create a new timer that calls Window.alert().
t.run();
t.scheduleRepeating(500);
}
});

RootPanel.get().add(startbtn);
RootPanel.get().add(stopbtn);
RootPanel.get().add(timeLabel);
RootPanel.get().add(randomNumberLabel);
t.scheduleRepeating(1000);
}


}

2009年4月22日水曜日

GWTでMunubarを使ってみる

>
本日は、GWTでMenuBarを作って遊んでみた。

参考にしたドキュメントはこちら、


今回は、日本語のメニューの表示も試してみた。
こちらは、javaのソースコードをUTF-8 で保存するように変更したところ、
正しく表示できるようになった。

おそらく、現状のフレームワークでは、MS-932 の文字コードを正しく処理できないのでしょう。

ちなみに今回のソースはこちらで、



public void onModuleLoad() {
Command cmd = new Command() {
public void execute() {
Window.alert("You selected a menu item!");
}
};
//縦型のメニュー
MenuBar fooMenu = new MenuBar(true);
fooMenu.addItem("保存", cmd);
fooMenu.addItem("読み込み", cmd);
//メニューに線を引く
fooMenu.addSeparator();
fooMenu.addItem("終了", cmd);

MenuBar barMenu = new MenuBar(true);
barMenu.addItem("the", cmd);
barMenu.addItem("bar", cmd);
barMenu.addItem("menu", cmd);

MenuBar bazMenu = new MenuBar(true);
bazMenu.addItem("the", cmd);
bazMenu.addItem("baz", cmd);
bazMenu.addItem("menu", cmd);

MenuBar menu = new MenuBar();
menu.addItem("foo", fooMenu);
menu.addItem("bar", barMenu);
menu.addItem("baz", bazMenu);

RootPanel.get().add(menu); }





で実行した感じが下記のような感じ。
日本語も正しく表示されるようになりました。


いままでやってきたものを組み合わせると、通常の画面でやってるようなことも
ブラウザ化するのは理論上は意外に簡単にできそうな気がしてきた。

2009年4月21日火曜日

GWTでVerticalPanelとHorizontalPanel

本日は、2種類のパネルを試してみる。
VerticalPanelとHorizontalPanelを試してみた。

VerticalPanelは部品が縦に並び、HorizontalPanelは部品が
横に並ぶパネルのようです。

本日は、下記のページのサンプルを元に遊んでみました。

http://google-web-toolkit.googlecode.com/svn/javadoc/1.6/com/google/gwt/user/client/ui/TextBox.html


PasswordTextBox ptb = new PasswordTextBox();
TextBox tb = new TextBox();

// 数字しか入力を許容しないTextBox
tb.addKeyPressHandler(new KeyPressHandler() {
public void onKeyPress(KeyPressEvent event) {
if (!Character.isDigit(event.getCharCode())) {
((TextBox) event.getSource()).cancelKey();
}
}
});

// 横60文字 縦 5文字のTextArea
TextArea ta = new TextArea();
ta.setCharacterWidth(60);
ta.setVisibleLines(5);

// パネルの生成
VerticalPanel vpanel = new VerticalPanel();
HorizontalPanel hvpanel = new HorizontalPanel();
hvpanel.add(tb);
hvpanel.add(ptb);
vpanel.add(hvpanel);
vpanel.add(ta);
RootPanel.get().add(vpanel);




そして実行した結果はこんな感じ。

想像したとおりに結果が得られるのはうれしいもんですね。

2009年4月20日月曜日

GWTでSuggestBoxを使ってみる

本日は、SuggestBoxがどんな風に動くのかを試してみる。

昨日としては、テキストエディットにおいて、候補を表示する機能というところでしょうか。

とりあえず、下記のページを参考に簡単なサンプルを動かしてみた。

http://google-web-toolkit.googlecode.com/svn/javadoc/1.5/com/google/gwt/user/client/ui/SuggestBox.html

コードの記述は下記のとおり、Suggestを表示しながら、それを
選択したら、ダイアログに表示するようなサンプルです。


MultiWordSuggestOracle oracle = new MultiWordSuggestOracle();
oracle.add("Cat");
oracle.add("Dog");
oracle.add("Horse");
oracle.add("Canary");
oracle.add("apple");
oracle.add("assert");
final SuggestBox box = new SuggestBox(oracle);
box.addEventHandler(new SuggestionHandler(){
public void onSuggestionSelected(SuggestionEvent event) {
Window.alert(box.getText() );
}
});
RootPanel.get().add(box);
}



こちらをブラウザで動かしてみると、こんな感じです。



なかなか面白い。
なんとなくつかめてきました。

2009年4月18日土曜日

GWTでFlexTableを使ってみる

今度は、下記のサンプルを参照しながらFlexTableというクラスを使ってみる。
http://google-web-toolkit.googlecode.com/svn/javadoc/1.5/com/google/gwt/user/client/ui/FlexTable.html

普通にテキストをセットしたり、ボタンをセルにセットしたりできるようですね。

setColSpanの意味がわからなかったけど、実際に、下記のようにサンプルを
ちょっと変更して動かした感じでは、こちらはどうやらエクセルで言う
「セルの結合」を意味する関数のようですね。

   public void onModuleLoad() {
// Tables have no explicit size -- they resize automatically on demand.
FlexTable t = new FlexTable();
t.setText(0, 0, "aa");
t.setText(0, 1, "ii");
t.setText(0, 2, "uu");
t.setText(0, 3, "ee");
t.setText(0, 4, "oo");
t.setText(2, 0, "sa");
t.setText(2, 1, "si");
t.setText(2, 2, "su");
t.setText(2, 3, "se");
t.setText(2, 4, "so");

t.setWidget(1, 1, new Button("Wide Button"));
          //セルの(1,0)から3つの列を結合する
t.getFlexCellFormatter().setColSpan(1, 0, 3);

RootPanel.get().add(t);
}



こちらを実行してみるとこんな感じになりました。



GWTでコンポーネントを作る

本日は、

Step 3: Building the User Interface

を読んでいくと、コンポーネントの説明がある、ここでWidget Gallery
画面のユーザインターフェースの基本的な部品がそろっているので、
基本的な画面は問題なく構築できそうである。

ちなみに下記に、画面の実際の動作サンプルがある。
http://gwt.google.com/samples/Showcase/Showcase.html

Button のページに飛んでみると、サンプルコードとJavadocが書かれている。

このサンプルを参考に、ボタンを貼り付けてみる。

ここで、RootPanelというのが、きっと一番の基本となる画面の部分なんでしょう。
基本的には、new Buttonをして、そいつを

RootPanel.get().add(b);

としてやることで画面に部品ができるようですね。


public void onModuleLoad() {
// Make a new button that does something when you click it.
Button b = new Button("hogehoge", new ClickListener() {
public void onClick(Widget sender) {
Window.confirm("Are you ready?");
}
});

// Add it to the root panel.
RootPanel.get().add(b);
}
}


そして、実際に動かしてみた感じがこんな感じ。


サンプルの時と比べると、EDITの部分が変わった感じになるんですね。

ためしに、ボタンの部分を日本語にしてみたら文字化けした。
日本語には、まだ対応していないのか、単に記述が甘いだけなのか
現時点ではよくわからないが、先に進むことにしよう。

2009年4月17日金曜日

Javaでファイルの更新日付の取得&和暦表示

本日は、Javaでファイルの更新日付を取得してみた。

ついでに、イタリア形式の日付の出力をやり、その後に
和暦で日付を表示してみた。

国を変えてみると各国の日付の出力の仕方がわかってなかなか面白い。

下記がサンプルソースです。


import java.io.File;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class FileTimeStampTest {

/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
File file = new File("D:\\Tools\\CSV2\\profile.ini");
long lastModifytime = file.lastModified();
Date date = new Date(lastModifytime);
System.out.println(date.toString());
DateFormat df = DateFormat.getDateInstance();
System.out.println(df.format(date));
df = DateFormat.getDateTimeInstance();
System.out.println(df.format(date));
df = DateFormat.getDateTimeInstance(DateFormat.LONG,DateFormat.LONG, Locale.ITALY);
System.out.println(df.format(date));
DateFormat format = new SimpleDateFormat("GGGGyy年 MMMM d日 a hh 時 mm 分 ss 秒",new Locale("ja", "JP", "JP"));
System.out.println(format.format(date));

}

}

2009年4月15日水曜日

GWTコンパイル

GWTのコンパイルは、antを利用する場合には、

ant build

とやればコンパイルできたが、Eclipseからコンパイルする場合には、

右クリック→Google→GWT Compile

でやるとコンパイルできるようですね。

http://code.google.com/intl/ja/webtoolkit/tutorials/1.6/create.html

とりあえず、上のリンクの昨日の作業で作られた「StockWatcher.html」ファイルを
直接ローカルファイルとしてブラウザで開いてみると、再コンパイルせよ
というようなメッセージが出てきたので、適当に探していたら、それらしき
メニューがあったのでやってみたらコンパイルされ、開けるようになりました。

2009年4月14日火曜日

GWTで生成されるxmlとは

本日は、下記ページの

http://code.google.com/intl/ja/webtoolkit/tutorials/1.6/create.html
The module XML file

あたりを読んでみている。

このxmlファイルには、大きくは、スタイルシートの情報と、
最小に表示されるアプリケーションのエントリーポイントの情報が
書いてあるのか。

なるほど。ふ~~んという感じですね。

とりあえず、今週中くらいにはGetting Startedあたりの内容は一通り読んで、
理解しておきたいなと思っている。

Javaで拡張子の変更

拡張子の変更を行いたいなと思ってちょこっと書いてみた
サンプルプルプログラム

実際これだと、.の入ったファイル名の場合には、誤動作しそうですが、
書いてみるとこんな感じになるのだろうか。

Delphiだと、ChangeFileExtというダイレクトな関数があるのだけど、
Javaだとこんな感じが限界なんだろうか。



import java.io.File;


public class RenameFileTest {
public static void main(String[] args) {
File file = new File(args[0]);
String fileNm= file.getName();
fileNm=file.getParent()+File.separator+fileNm.replaceFirst("\\..*",".csv");
if(file.renameTo(new File(fileNm))){
System.out.println("リネーム成功");
}else{
System.out.println("リネーム失敗");
}
}

}

2009年4月12日日曜日

Google Plugin for Eclipsedでproject作成してみる

Using the Google Plugin for Eclipse - Google App Engine - Google Code
をやっている件の続き

続いてプロジェクトの作成をしてみる。

Eclipseのメニューから

file→new→Web Application Project



を実行すると上記のようなダイアログが出てくるので、入力してFinishボタンを
押すと、先日webAppCreator をコマンドで作ったものと同じものができた。

その後、何もしないで、とりあえず、

Run メニュー → Web Application

とすると実行される。

続いて、下記のページ内の 「Uploading to Google App Engine」を
http://code.google.com/intl/ja/appengine/docs/java/tools/eclipse.html

やってみようと試みたが、Uploadに失敗してしまう。きっと1万人の制限が
あるからかなと思い、この部分はあきらめる。

ちなみにeclipseのコンソールに出てくるログとエラーの内容はこんな感じ


======================================================
Compiling module com.blogspot.ttimez.guestbook.Guestbook
Compiling 5 permutations
Permutation compile succeeded
Linking into war
Link succeeded
Compilation succeeded -- 44.281s
Creating staging directory
Scanning for jsp files.
Scanning files on local disk.
Initiating update.
Unable to upload:
java.io.IOException: Error posting to URL: http://appengine.google.com/api/appversion/create?app_id=takes90&version=1&
400 Bad Request
Invalid runtime specified.

at com.google.appengine.tools.admin.ServerConnection.send(ServerConnection.java:114)
at com.google.appengine.tools.admin.ServerConnection.post(ServerConnection.java:66)
at com.google.appengine.tools.admin.AppVersionUpload.send(AppVersionUpload.java:345)
at com.google.appengine.tools.admin.AppVersionUpload.beginTransaction(AppVersionUpload.java:159)
at com.google.appengine.tools.admin.AppVersionUpload.doUpload(AppVersionUpload.java:68)
at com.google.appengine.tools.admin.AppAdminImpl.update(AppAdminImpl.java:41)
at com.google.appengine.eclipse.core.proxy.AppEngineBridgeImpl.deploy(AppEngineBridgeImpl.java:203)
at com.google.appengine.eclipse.core.deploy.DeployProjectJob.runInWorkspace(DeployProjectJob.java:97)
at org.eclipse.core.internal.resources.InternalWorkspaceJob.run(InternalWorkspaceJob.java:38)
at org.eclipse.core.internal.jobs.Worker.run(Worker.java:55)
java.io.IOException: Error posting to URL: http://appengine.google.com/api/appversion/create?app_id=takes90&version=1&
400 Bad Request
Invalid runtime specified.
======================================================

とりあえず、でもこんな感じで自分のつくったアプリケーションが公開されるのか
というようなイメージはつかめた。

Google Plugin for Eclipseを入れて見る

本日は、下記をやってみようと思う。

Creating an Application from Scratch (with Eclipse)
http://code.google.com/intl/ja/webtoolkit/gettingstarted.html

まず、下記をよんでみると、EclipseプラグインはGoogleAPPとGWTは統合されているようです。
とりあえず、こちらのページを参考にしながらインストールしてみる。
http://code.google.com/intl/ja/appengine/docs/java/tools/eclipse.html

Eclipseを起動する。

1.Help メニュー > Software Updates を選択
2.Available Software を選択
3. [Add site]ボタンを押し、Location欄に「http://dl.google.com/eclipse/plugin/3.4
と入力しOKボタンを押す。(eclipse 3.4の場合)
4.新しく出てきなGoogleのプラグインにチェックを要れInstallボタンを押す。
5.そのまま画面の指示に従い、続行(ライセンスの確認しfinishを押す)
6.eclipseの再起動を促すメッセージが出てくるのでそのままOkを押す。

これでインストールが終わり。

再起動されたeclipseを見ると、file→new→Web Application Project が選択できるように
なっているのでこれでインストールは完了。

2009年4月11日土曜日

Google Web Toolkit

Google Web Toolkitというのは、現在、何かと耳にすることが多いAjAX

アプリケーションを簡単に作成できるというもの。

本日はじめて動かして遊んでみた。


まずは、ここら辺からはじめてみる。




#本ドキュメントは上記ページに沿って行ってみた結果を書いている。


まずは、上記のページにも書いてあるようにインストールから。

家のPCには、antもJdkもまだ入っていなかったのでそこらへんからはじめる。






準備としては、上記のソフトを入れておく必要があるようです。


回答して、早速サンプルプログラムを動かしてみる。


D:\gwt-windows-1.6.4\gwt-windows-1.6.4\samples\Mail>ant hosted


すると、ファイアウォール解除のダイアログが出てくるがそのまま解除すると、

無難に動作する(ここでブロックしてしまうと、使えなくなってしまう)


このページにあるように、ちょっとソースを変更してみる。

このちょっとというのは、Mailの部分を「MyMail」に変更するサンプルのようです。


samples/Mail/src/com/google/gwt/sample/mail/client/Shortcuts.java


の中をドキュメントどおりに変更してみるとて再度antを実行してみると、確かに

再コンパイルされて、この変更も反映されていた。


確かに、javaソースからhtml&JavaScriptが生成されるようです。


次に


Creating an Application from Scratch (without Eclipse)


の部分をやってみる。

これは、最初からGWTアプリケーションを作る際に、ある程度必要なファイルを

自動生成する機能があるらしい。


webAppCreatorというコマンドを用いるようです。


サンプルどおりに入力してみる。


============================================================

D:\gwt-windows-1.6.4\gwt-windows-1.6.4>webAppCreator -out MyApplication com.mycompany.MyApplicationCreated directory MyApplication\srcCreated directory MyApplication\warCreated directory MyApplication\war\WEB-INFCreated directory MyApplication\war\WEB-INF\libCreated directory MyApplication\src\com\mycompanyCreated directory MyApplication\src\com\mycompany\clientCreated directory MyApplication\src\com\mycompany\serverCreated file MyApplication\src\com\mycompany\MyApplication.gwt.xmlCreated file MyApplication\war\MyApplication.htmlCreated file MyApplication\war\MyApplication.cssCreated file MyApplication\war\WEB-INF\web.xmlCreated file MyApplication\src\com\mycompany\client\MyApplication.javaCreated file MyApplication\src\com\mycompany\client\GreetingService.javaCreated file MyApplication\src\com\mycompany\client\GreetingServiceAsync.javaCreated file MyApplication\src\com\mycompany\server\GreetingServiceImpl.javaCreated file MyApplication\build.xmlCreated file MyApplication\README.txtCreated file MyApplication\.projectCreated file MyApplication\.classpathCreated file MyApplication\MyApplication.launchCreated file MyApplication\war\WEB-INF\lib\gwt-servlet.jar

=========================================================


その後、同様に起動してみる。


D:\gwt-windows-1.6.4\gwt-windows-1.6.4\MyApplication>ant hosted


そして、名前を入力してボタンを押すとこんな感じの画面が....



ソースは、あたりに転がっている
MyApplication/src/com/mycompany/client/

D:\gwt-windows-1.6.4\gwt-windows-1.6.4\MyApplication>ant build

と入力するとjavaScriptも再生されるのか下記のようにブラウザでファイルを
開いても閲覧できるようになる。

file:///D:/gwt-windows-1.6.4/gwt-windows-1.6.4/MyApplication/war/MyApplication.html

ただ、この場合には、サーバ側が動作していないので、RPC呼び出しに失敗しているようだが。

こうやって使ってみるとなかなかすごい仕組みだなぁと思う。

Javaの方が普段慣れているので、こちらを本格的に見て行こうかなとも思った。

2009年4月2日木曜日

HelloWorld

Google App Engineにて下記のサイトを参考にしながら
HelloWorldを動かしてみた。

Pythonという言語も初心者なんだけど、地道に身につけていこうかな。

参考にしたページは、こちら。
http://code.google.com/intl/ja/appengine/docs/python/gettingstarted/helloworld.html

ポイントは、helloworld.pyというファイルを作り、app.yaml というファイルにて、この
helloworld.pyというプログラムと、URLを結びつけるというところだろうか。

実際に動作させるには、コマンドライン上から

(GoogleAppのインストール先にあるdev_appserver.py) (今回作成したフォルダ)
google_appengine/dev_appserver.py helloworld/ 


と打つとローカルにサーバが立ち上がるので、

ブラウザから

http://localhost:8080/

へアクセスすると自分の書いたプログラムが動くという感じだった。

サンプルでは、すべての文字列に対して、helloworld.pyが結びつかれているので
実際に動かしてみるとどのようなURLもマッチするようである。

これが、今回のHelloWorldのポイントなのかな。

起動時のDOSイメージ

==============================================
D:\googleapp>"C:\Program Files\Google\google_appengine\dev_appserver.py" hellowo
rld/
C:\Program Files\Google\google_appengine\google\appengine\tools\appcfg.py:40: De
precationWarning: the sha module is deprecated; use the hashlib module instead
import sha
INFO 2009-04-02 13:55:20,250 appcfg.py] Server: appengine.google.com
INFO 2009-04-02 13:55:20,265 appcfg.py] Checking for updates to the SDK.
WARNING 2009-04-02 13:55:21,000 datastore_file_stub.py] Could not read datastor
e data from c:\docume~1\yamana7\locals~1\temp\dev_appserver.datastore
WARNING 2009-04-02 13:55:21,000 datastore_file_stub.py] Could not read datastor
e data from c:\docume~1\yamana7\locals~1\temp\dev_appserver.datastore.history
WARNING 2009-04-02 13:55:21,265 dev_appserver.py] Could not initialize images A
PI; you are likely missing the Python "PIL" module. ImportError: No module named
PIL
INFO 2009-04-02 13:55:21,515 dev_appserver_main.py] Running application hell
oworld on port 8080: http://localhost:8080
====================================================================

ブラウザのイメージ

JAVAで正規表現

最近、正規表現を使って検索するということをやってみた。
Javaだと正規表現の検索が簡単にできるので、



●Stringクラスに対して正規表現で検索する場合
String str;
if (str.matches(".*.xml")){
いわゆる*検索はこんな感じでいけて

●()で囲まれた文字列を検索し、それを表示するプログラムのサンプル
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.StreamTokenizer;
import java.util.StringTokenizer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
class Test{
public static void main(String args[]){
Pattern pattern = Pattern.compile("\\([^\\(\\)]*\\)");
Matcher matcher = pattern.matcher("(aiueo) (aiueo)(aiueo) (kakikukeko)");
while (matcher.find()){
System.out.println(matcher.group());
};
}
}



正規表現の検索がこんな手軽にできるのはやはり便利ですね。

テキストファイルの中からURLだけを抜き出すというのなんかも
正規表現を使ってあげれば一発ですね。

正規表現サンプル集なんかでいろいろな検索ができます。