火曜日, 5月 26, 2009

【Google App Engine】 開発で嵌らないためのTIPS このエントリーを含むはてなブックマーク


1.Eclipseでプロジェクト名を変更した場合は作業ディレクトリも変更する



2.Systemプロパティはappengine-web.xmlに記述する



3.DataNucleus Enhancerでエンハンスされているか常に気にしておく



4.LocalのDataStoreは掃除する



5.Localでは実行できるのにサーバにDeployできない場合はサーバのデータをClean upする



6.Logを参照することでサーバ上の動作確認をする

土曜日, 5月 23, 2009

【Google App Engine】 JDOから直接JSON、XML このエントリーを含むはてなブックマーク


GAEに対応したReflex Coreを公開

  Entityとトランザクションでも触れたが、GAE対応したReflex Resource Mapperを公開したいと思う。Reflex Resource Mapperは、XML/JSON⇔JavaBeanのバインディングツールで、JDOと直接マッピングできる点がウリだ。デモサイトを見てもらうとわかるが、ブラウザからJSONを受け取ってJDOに変換してDatastoreに直接保存できる。この処理は以下の2行で書ける。


 loginnew = (Login) mapper.fromJSON(req.getParameter("json"));
JdoUtils.insert(loginnew);


 デモではJSONを受け取っているが、mapper.fromXML()とすることで同じ構造をしたXMLも受け取れる。
 設定も簡単で、4つのjarファイルをGAEのアプリケーションに追加するだけですぐに使うことができる。また、特別な設定ファイルなどは必要ない。

Reflex Core Sample
デモサイト
SVN (Google code)

 Reflexでは、RESTfulな新3層アーキテクチャや、APIをやめデータ構造に着目するなどでも説明しているとおり、Entityの設計に重きを置き、その構造のままEntityをCRUD(HTTPでGET/POST/PUT/DELETE)するといったRESTfulな設計を目指す。また、これを容易にするために、reflexentityeditorといったツールや、トランザクション処理に対応したReflexContainerなどを準備している。

JDO設計における注意点


 私も嵌ったが親子関係をもつJDOの設計には注意が必要である。以下のようにBeanは基本的にEmbededでない限り、@PersistenceCapableと@PrimaryKeyの定義が必要である。(これは”おまじない”と思った方がいい)


@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Content {
・・・
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
・・・
}


さらに、1対多の場合は、子(Content)に親(Login)のプロパティを定義する必要がある。

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Content {
・・・
@Persistent
private Login login;
・・・
}

<関連情報>

JDO problem with owned one-to-many relationships and superclasses


同一型の子Entityを持つと、子Entityの判断がつかない


GAE対応する際に苦労した点


 ReflexをGAEに対応させるためにやったことは次のとおり。

 1.Making XStream compatible with the Google App Engineを参考に、NoClassDefFoundErrorやExceptionInInitializerErrorをcatchして握りつぶす行を追加。
try {
registerConverter(new PropertiesConverter(), PRIORITY_NORMAL);
} catch (NoClassDefFoundError e) {
} catch (ExceptionInInitializerError e) {
}
 2.sun.reflect.ReflectionFactoryを使ったクラスSun14ReflectionProvider.javaからPureJavaReflectionProvider.javaを使うように変更
 3.一旦、JDOに保存されたものを取り出すと、java.util.ArrayListオブジェクトがorg.datanucleus.sco.backed.Listに勝手に変わるのでinstance ofが使えない。これはクラス名を指定することで使えるように修正した。


<関連>
JDOから直接SOAP、ATOM。それからDeep Copy
AJAX CRUDサンプルとJDO代替ライブラリ
Pagingをどうやって実現するか
RESTfulアプリのCRUDサンプル -Servlet編-
RESTfulアプリのCRUDサンプル -Modeling編-

金曜日, 5月 22, 2009

【Reflex】 段階的にScale可能なPDFサービス このエントリーを含むはてなブックマーク


 最近、Amazonのクラウドサービスがすごい。Amazonクラウド、大規模データをHDD郵送で受け入れなんて、Amazonならではの強みを生かしたサービスといえよう。特に目をひいたのは、Amazon CloudWatch(インスタンス監視サービス)、Amazon Elastic Loadbalancer(ロードバランサー), Amazon AutoScaling(自動スケールアウト機構)などの機能で、これらを利用することで、負荷に応じて自動でマシンを起動する、AutoScalingという仕組みを作れるようになる。
 ということで、Reflex itextとAutoScalingを使って、Scalable PDF Serviceというものを構築することにした。





 前面にGAEを置いてバックエンドのEC2にディスパッチしている。GAEでデータの作成およびキャッシュ機能を持たせることにすることで、余分な負荷をなくすことができ、また懸案のレイテンシーも問題にならずにすむ。Amazon EC2は北米と欧州にあるので、どうしても「もっさり感」が出てしまうがGAEであればサクサクとレスポンスが返ってくる。GAEは制約が多くて使いづらい面も多いが、EC2と組み合わせることで、それぞれの強みを生かした非常によいサービスを提供できるようになる。

 ( Reflex itextも当初はGAE上で構築することを考えていたが、java.awt.*パッケージが使えないことで断念した。No Graphics?

月曜日, 5月 11, 2009

【Google App Engine】 BigTableのJDBCラッパー jiql このエントリーを含むはてなブックマーク


GAE/JでSQLをどうしても使いたい方に朗報。jiqlというものを使えば、jdbc clientとしてBigTableに実際に保存されたデータにアクセスできるようになる。



これを使えるようにするには、jiqlのページから、jiql.jarとjiql.jspをダウンロードして、GAEアプリケーションに配置すればよい。それぞれ、WEB-INF/lib/の下と、./に置く。
ただし、jiql.jspにはBugがあり、jspコンパイル時にエラーとなるため、以下のように修正する。(try catchのスコープ外でString sql=""を定義する)

 jiql testpage

jiql testpageでは、hostやuser、password、datasourcenameを入れる箇所があるが、とりあえず何も入れないで、exampleのsqlを入れてqueryボタンを押すだけで実行結果が見れる。

ただ、JOINが使えないのを見ればわかるように、まだクラウドでSQLを使うのは無理があるように思う。将来使えるようになったとしても、トランザクションやパフォーマンスのことを考慮すると、結局クラウドの作法に立ち戻るはめになるだろう。個人的には、トランザクションプロセッシングを司るアプリからはSQLを無理に使うべきでないと思うし、使ったところで結局はO/Rマッパが必要となるので嬉しくない。
 SQLが真価を発揮するのは情報系データベースである。これは別システムとして立てることで、クラウドからデータを受け渡すようにすればよいと思う。



・・・
ResultSet result = null;

Connection Conn = null;


String status = "";
String url = "jdbc:jiql://local";
String host = "";
String password = "";
String user = "";
String dsName = "";
String sql ="";

if (request.getParameter("query") != null){

try{
sql = request.getParameter("sql");
if (sql == null || sql.length() < 1)
throw new SQLException("Please Enter a valid SQL Statement!");

Properties props = new Properties();
props.put("user",user);
props.put("password",password);

Class clazz = Class.forName("org.jiql.jdbc.Driver");
Driver driver = (Driver) clazz.newInstance();

Conn = driver.connect(url,props);


Statement Stmt = Conn.createStatement();
Stmt.execute(sql);
result = Stmt.getResultSet();
status = sql + "
SQL COMPLETED SUCESSFULLY";
}catch (Exception ex){
status = "" + sql + "
SQL FAILED " + ex.toString() + "
";
ex.printStackTrace(response.getWriter());

}
//Conn.close();
}
・・・
以下同じ

 
© 2006-2015 Virtual Technology
当サイトではGoogle Analyticsを使ってウェブサイトのトラフィック情報を収集しています。詳しくは、プライバシーポリシーを参照してください。