ラベル GAE/J の投稿を表示しています。 すべての投稿を表示
ラベル GAE/J の投稿を表示しています。 すべての投稿を表示

2015-03-12

Eclipseを起動させるJava VMのバージョンを指定する

GWTやGAE対応のアプリ開発をするときは、EclipseにGPE(Google Plugin for Eclipse)をインストールするのが普通ですが、現段階でのGPEの動作条件は
Java 7(JRE 7) かつ最新のEclipse
となっています。Javaを利用するのがEclipseだけならまだいいですが、すでにJava8がインストールされていた場合、、、わざわざ新しい方を消すというのも勧められません。共存するためには、EclipseだけJava7で動かす必要があります。で、その方法ですが、eclipse.iniファイルにおいて、
-vm
C:\Program Files\Java\jre7\bin\javaw.exe
という記述を追加すればOKです。ここの書き方の注意点は、オプション名と値を必ず2行に分けて記述することです。 また、-vmargsよりも前に書かないとダメです。


2013-02-27

GAE:Java7に対応へ

ようやく、Google App EngineがJava7対応になるようです。
Java 7 Considerations
現在は試験運用のようです。Java6のコードが動かなくなるという意味ではないと思いますが、ただ、「Java 6ベースのアプリがJava7で動くかどうか試しとけ、、」みたいなことは書いてますので、移行に向けて確認をしておくほうがいいでしょう。
この件はGAEのサーバの話ですし、将来的にJava6のサポートを廃止するようですので、我々開発者には「Java7に移行しない」という選択肢はないと考えたほうがいいでしょう。

ちなみに移行時にはいきなりどーんと変わるんでしょうかね?スイッチみたいなのを用意するのでしょうか?気になるところです。






2013-02-22

GAE:本番環境かどうか判断する方法

GAE用のサーバサイドプログラムが動いている環境が、本番環境(appspot)かローカル環境なのかを判断するには、下記のコードでOKです。
String env = System.getProperty("com.google.appengine.runtime.environment");
開発環境ではDevelopmentという文字列が返ってきます。

2012-10-16

Eclipse: GWT+GAE のプロジェクト作成でエラー(/web.xml already exists)

Eclipse でGWT+GAEのプロジェクトを作成しようとした時、
Creation of element failed:
Reason: Resource '/xxx/war/WEB-INF/web.xml' already exists.
というエラーが出て作成できない場合があります。この時は,
  • とりあえず、GAEをOFFにしてプロジェクトを作成し、後から追加
という手順で解決します。

2011-12-16

ObjectifyでRelationShipを利用する

GAEのDataStoreはKVSのデータベースですので、RDBのようなリレーションがないと言われていますが、実際にはRelationshipという所有関係を定義することができます。Objectifyでは比較的容易に設定することができます。

サンプルの設定状況
サンプルプログラムの設定状況は下記の通りになります
  • ユーザを表現するPersonクラス
  • 車を表現するCarクラス
  • Carクラスはユーザ(Person)の情報を持つ
このことを頭にいれて以下を読んでください。

Entityクラスの記述方法
@Parentのアノテーションをつけるのがポイントです。
public class Car
{
    @Id Long id;
    @Parent public Key owner;
    String color;
}

public class Person
{
    @Id Long id;
    String name;
    int grade;
}
リレーションの登録
Keyを割り当てるのがポイントです。
//Personデータを登録し、そのKey情報を得る
Person p = new Person();
p.name="bob"; 
Key pKey = ofy.put(p);

//入手したKey情報を割り当てる
Car car = new Car();
car.id=(long)1002;
car.owner=pKey;
car.color="blue";
リレーションを利用した検索
色が青色の車のユーザを検索する方法は下記のようになります。
Car car = ofy.query(Car.class).filter("color", "blue").get();
Person p = ofy.get(car.owner);
ID情報をベタに管理するよりも簡単に検索することができますね。

2011-11-17

Netbeans:GAEにデプロイしたプログラムが動かない件

NetbeansでGAEへアプリのデプロイする時にちょっとハマったので、ニッチなネタです。

諸事情で、GAEにアップしているアプリの微修正を行なって再度アップするとエラーが発生して動かない。。。エラーを見てみると、
java.lang.UnsupportedClassVersionError: org/apache/jsp/index_jsp : Unsupported major.minor version 51.0
というエラーが。これは、JVMが未対応のバージョンの時に発生するらしく、公式サイトに確認してみると
App Engine では、Java 6 仮想マシン(JVM)を使用して Java アプリケーションを実行します。
と書いてある。あ、今、このマシンにはJava 7が入っているんだった。。。というわけで、慌ててJDK6も入れて設定してみるがそれでも動かず、、、、

結論として、App EngineのSDKが古かった(1.3.3)ので、1.6にすることでとりあえず動きました。JDKは関係なかったのかもしれません(SDKが6用にコンパイルしてくれているのかも)。

2011-07-30

DAOBaseクラスでObjectify-appengineを使いやすくする

Objectify-appengineでは、
ObjectifyService.registerメソッドを記述して、Entityを登録する
という手順が必要となります。これはちょっと面倒なんですが、もっと厄介なのは
同じクラスを登録するとエラーが発生する
という仕様になっている点です。クラスの情報はスタティックな領域に記録されているので、registerメソッドで同じものを登録しないように気を付けなければなりません。その解は、公式サイトのBestPracticeに書いてあります。DAOBaseクラスを使えと、、、
public class DAO extends DAOBase
{
    static {
        ObjectifyService.register(ここに利用するEntityを記述);
     }

  //DAOとしてデータベース周りのラッパーメソッドを以下に書いていけば良い
}
基本的に上述のようなDAOクラスを継承したクラスを作っておけば、あとは下記のように呼び出せばOK。
DAO dao = new DAO();
dao.ofy().find(........);
dao.ofy().put(......);

ただこのようにfindやputを呼び出すよりも、実際は、DAOクラスに関連するラッパーメソッドを実装して呼び出すようにするのがいいですね。

2011-07-11

GAEでJCacheを利用する

前記事でmemcacheについて書きましたが、JCacheについても載せておきます。
try {
            CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
            cache = cacheFactory.createCache(Collections.emptyMap());
          // 登録
            cache.put("name", "おちらぼ");

          // 検索
            value = cache.get(name);


        } catch (CacheException e) {
            // ...
        }
どちらを使うべきかですが、Googleの公式サイトではMemcache Java APIにおいてJCacheを優先的に書いています。GAEにおいてはmemcacheは低レベルAPIであるため、JCacheのほうが使いやすいかもしれません(ほとんど記述は変わりませんが)。ただ、

  • JCacheは開発中のライブラリであり、実装されてない機能がある場合がある
  • より多くの機能を利用するなら memcache API
  • JCacheはJava標準であるため記述に汎用性がある。
という認識はもっておいてください。


GAEでMemcacheを利用する

Datastoreに頻繁にアクセスすると、システムの動作が遅くなったりサーバの負荷がかかってくるようなので、そんな時はMemcacheを用いるとよい。Memcacheは、いわゆるハッシュテーブル(マップ)みたいなもの。キーとバリューの組を格納していくだけ。GAEではデータを共有できるようになっているのが特徴だが、いろいろなシステムで使っているとキーの衝突も起こりうる。そこで、NameSpaceで区別できるようになっている。
//TEST1というネームスペースで設定
MemcacheService memcache = MemcacheServiceFactory.getMemcacheService("TEST1");
memcache.put("name", "おち");
String result = memcache.get("name");
基本はこれだけ。GAEを使っているとCPUの負荷等が気になるが、Memcacheを利用するとその減少に効果があるらしい。Datastoreとの使い分けについては

  • 頻繁にアクセスするデータはDatastoreを何回も見に行くのではなく、Memchacheの値を取り出すようにする
  • Memcacheに値がない場合は、DatastoreにアクセスしMamcacheに保存しておく
というのが無難でしょう。Memcacheはあくまでも一時的なデータ保存領域なので。ただ、この使い分けをどうするかは、設計者の腕の見せどころだと思います。

なお、JCacheというJavaの標準の方も利用できるようです。このあたりの使い分けもちょっと調べてみます。


2011-06-25

Objectify-appengineでGAEデータストアを操作する

GWTプログラミングにおいては、GWT-RPCを利用することはしばしばあります。この場合、サーバークライアント間でのデータのやりとりは、
シリアライズ可能なPureなデータクラスを用意する
のが前提になります。ここで、データベースを絡めてくると厄介な問題がおきます。例えば、GAEのDatastoreを利用する場合、DatastoreとのやりとりはJPAやJDOのフレームワークを使いますが、この場合のEntityクラスには、それら特有の記述(アノテーション)が必要となります。このEntityクラスは、GWTで利用可能なシリアライズ化されず、GWT-RPCでは受けつけられません。よって、PureデータクラスをDTOとして中身の入れ替え作業が必要になります。その手間は面倒です。

objectify-appengineというライブラリ
この問題を解決する方法として、objectify-appengineと呼ばれるGAEのデータストアに対応したライブラリがあります。これを利用することで、GWTーRPCで利用したデータクラスをそのままデータストアに渡すことができます。本ラボでは現在まだ試行中ですが、JDOと同じような感覚で利用できるのがポイントです。

ライブラリの準備
まず、公式サイトからライブラリを入手して下さい。最近、3.0のバージョンが出たようです。3.0でどう変わったのかはちょっと不明です。ライブラリにパスを通したあと、GWTの設定ファイルに以下の記述を追記して下さい。
<inherits name="com.googlecode.objectify.Objectify" />
javax.persistanceのアノテーションを利用しますので、
ejb3-persistance.jar 
をクラスパスに記述してください。

Entityクラスの記述方法
下記に示すとおり、記述はシンプルになります。

  • idには@Idを追記
  • getter/setterはなくても良い(書いておいたほうがいいでしょう)
  • @Transient String doNotPersistがいるらしい(調査中、不要かも)

import javax.persistence.Id; 
import javax.persistence.Transient;

public class Car
{
     @Id Long id;
    String vin;
    int color;
    @Transient String doNotPersist;

    public Car() {}
    
    public Car(String vin, int color)
    {
        this.vin = vin;
        this.color = color;
    }
}


以下にとりあえず基本的な記述の仕方を載せます。

クラスの登録
ここはJDOなどとちょっと違うところです。ObjectifyはどのクラスがEntityクラスに相当するのか、コードで明示的に記述する必要があります。
ObjectifyService.register(Car.class);//該当するクラスを登録
Objectify ofy = ObjectifyService.begin(); //サービスのインスタンスを生成
データの追加・修正
ofy.put(car);
削除
ofy.delete(car);

検索
//IDによる検索
Car fetched1 = ofy.get(new Key(Car.class, porsche.id));
Car fetched2 = ofy.get(Car.class, porsche.id); 


//クエリによる検索(結果が1つの場合)
Car car = ofy.query(Car.class).filter("vin", "123456789").get();

//クエリによる検索(結果が複数ある場合)
Query q = ofy.query(Car.class).filter("vin >", "123456789");
for (Car car: q) {
    System.out.println(car.toString());
}
リファレンスをみてみるといろいろ強力な処理ができるようで、GAEのデータストアを利用する際のフレームワークの候補として挙げてみて良いと思います。

2011-06-02

GAE/J on Eclipseでのライブラリの設定について

EclipseでGAE/Jアプリを開発するとき、各種ライブラリ(jarファイル)は、

  • war/WEB-INF-/lib
においておく必要がある。

実はこれ、Javaのウェブアプリケーション開発の「常識」なわけだけど、今日はこれに躓いてしまった。なぜならNetbeansではこれを意識することなく、コンパイル時のライブラリパスが実行時のコンテナでのライブラリパスと同じになるようになっていたから。こんな昔のネタに今更であるとわ。こんなことをやらないとダメなの?というEclipseにちょっと幻滅だが、使わざるを得ないのでもう慣れるしかない。というわけで、とりあえずメモ書き。


EclipseでのGAE/Jアプリ開発はじめの一歩 ~Jettyでの実行~

Web Applicationプロジェクトでは、サーバはJettyと呼ばれるものが用意されており、GPEについてきます。特にインストールをする必要はありません。

実行方法
プロジェクトのRun as においてGoogleのアイコンの付いたWeb Applicationを選択してください。WTPでは「Run On Server」だと思いますが、GPEではJettyです。


再実行・再デプロイ時の注意事項
実はここで躓きました。プログラムを修正してもう1度実行させても修正が反映されない。どういうことなのかと、、、、どうやらGPEでは実行ボタンを押すたびにJettyのインスタンスを新たに起動しようとします。再起動をさせることで新しく生成されたクラスがデプロイされるらしいので、どこにそんなボタンがあるのかと、、、



答えは上記の写真のように画面下部の「Development Mode」のタブにJetttyを制御するボタンがあります。
  • 赤    ・・・一時停止?
  • 灰色× ・・・完全停止
  • 黄色   ・・・ 再起動

とりあえず、黄色を押すことで再起動し、デプロイされます。

2011-06-01

EclipseでのGAE/Jアプリ開発はじめの一歩 ~WTPと併用する~

EclipseでのGAE/Jアプリの開発のための各種設定メモ書きです(ちょっとNetbeansユーザ的な視点が入ってます)。

どのパッケージを入れるべきか
NetbeansユーザがEclipseを使い始めるときに最初に悩むのは、Eclipseは様々ななパッケージスタイルが提供されているということ。Eclipseはプラグインでどんどんカスタマイズしていくのが利点なので、それはまあ文化の違いとして、実際GAE/J開発をしたいときは、
  • Eclipse IDE for Java EE Developers
  • Eclipse IDE for Java Developers
のどちらかを選ぶ。前者のほうがウェブ関係のプラグインが入っているのでやりやすいかもしれません。後者でもあとでプラグインの追加をすればOKです。

GPEのインストール
当然のこととして、Google Plugin for Eclipseはインストールする必要があります。それは、Eclipseのプラグインインストールのやり方に従い、【HELP】→【Install NewSoftware】を選んで、下記の公式サイト
に書いてある「Update sites」のURLを追加することでGPEの項目が出てくる。なおGWTに関係するプラグインも一緒になってるので同時にインストールしておこう。

Web Application Projectでプロジェクト作成
GAE/Jのアプリを作成するプロジェクトは、「Web Application Project」と呼ばれるもので、上記のGPEをインストールすることで作成できるようになります。Googleのアイコンがあるのでお間違いなく。これで、Jettyがサーバとして使えるようになります。また、デフォルトでGWTのプログラムが実装されます(ウィザードで取り消すことは可能)。

上記のEclipseでGAE/Jのアプリを作り始めたときに最初に違和感を感じるのが、サーブレットの作成方法について。サーブレットプログラムを動かすには、
  • HttpServletを継承したクラス
  • web.xmlによるサーブレットの登録
が必要なわけですが、デフォルトの状態だとこれを自動的にやってくれない。Netbeansなら自動作成してくれるのに、、、全部手書きでするとかちょっと面倒です。

WTPのインストール
Eclipseには、ウェブアプリの作成を支援するWTPというプラグインが用意されています。これを利用することで、ちょっとだけマシになります。まず、現在使っているEclipseのバージョンによって対処の方法が少し異なります。
【Eclipse IDE for Java EE Developersの場合】
すでにインストールされていますので、あとは有効化するだけです。
【Eclipse IDE for Java Developers】の場合
プラグインを追加して下さい。【HELP】→【Install NewSoftware】を選んで、Eclipseのサイトを選択すると
  • Web,XML and JavaEE Development
というカテゴリの中をすべて選んでインストールして下さい。

WTPの有効化
以上により、WTPが使える状態になりました。が、インストールするだけではだめ。GAE/Jアプリのためのプロジェクト「Web Application Project」をにおいて、WTPが有効になるようにしなければなりません。
有効化の方法は、【Project】→【Properties】→【Project Facets】を選びます。










そうすると最初は設定されてないという画面がでますので、それを押します。
すると以下の画面がでます。ここで、有効にしたいFacetを選ぶわけで、サーブレット作成に最低限必要なのは
  • Dynamic Web Module
なので、これを選びます。


Dynamic Web Moduleの設定上の注意点(20110602追記)
ここは重要です!!プロジェクトを作成する最初にやっておかないとダメですので、必ずこの設定をして下さい(あとから変更できません)。
(1)DynamicWebModuleのバージョン
WTPのバージョンはデフォルトではVersionが3.0になってます。GAE/Jでは、ServletAPIの2.4ないし2.5相当に準拠しているので、バージョンを下げないといけません。ここで実際下げてみると、2.5ではエラーがでますので、2.4にしましょう。
(2)コンテンツディレクトリ設定
WTPでは、コンテンツのルートディレクトリをWebContentというフォルダにしようとします。しかし、GPEでのコンテンツディレクトリは warフォルダです。よって、上記の「Dynamic Web Module」を選択した際に、下部に「Futher configuration」というリンクがあるので、これをクリックします。そこで、Content Directoryを「war」 に変更してください。



以上の設定により、サーブレットを作成するというウィザードが有効になります。これで、Servlet関連のファイルを自動生成できます。。この設定をしておかないと、web.xmlでのマッピング記述を自動化してくれませんので注意です。


以上、Nebeansユーザからすると、めんどうだなぁと思いつつ、これさえクリアすれば、スムーズに開発できる気がしてます。


2011-04-21

GWTでChannelAPIクライアントを実装する

昨日に引き続いて、Channel APIの話題です。ライブラリを使って意外と簡単にGWTで実装できましたので、取り急ぎ報告します。あ、まだGAE上では試してません。

gwt-gae-channelライブラリを使う
gwt-gae-channelプロジェクトというのがありますので、これを使いました。まだバージョン0.3αですがいちおう動くようです。なお、gwt.xmlファイルへの記述は、
  • <inherits name='com.google.gwt.appengine.channel.Channel' />
となります。
Tokenの入手
これは、前回の記事を参考にして、まずはTokenを入手してください。入手方法はお好きなように、、、まあ、GWTユーザならGWT-RPCを使うのが普通でしょう。
Channelの接続
ここで、gwt-gae-channelのライブラリを使います。以下のような記述でOK。
ChannelFactory.createChannel(token, new ChannelCreatedCallback() {
            @Override
            public void onChannelCreated(Channel channel) {
                channel.open(new SocketListener() {
                    @Override
                    public void onOpen() {
                        Window.alert("Channel opened!");
                    }
                    @Override
                    public void onMessage(String message) {
                        Window.alert("Received: " + message);
                    }

                    @Override
                    public void onError(SocketError error) {
                        Window.alert("Error: " + error.getDescription());
                    }

                    @Override
                    public void onClose() {
                        Window.alert("Channel closed!");
                    }
                });
            }
        });
この記述は、Tokenを入手した直後にするのが無難でしょう。接続が確立すると、onOpenメソッドが反応します。この処理を終えることで、サーバとのcomet接続が維持されます。

Pushの呼び出し
上記の処理が終えた後、サーバー側でpushをする処理(前日の記事を参照)を実行させれば、上記のonMessageが反応します。push処理の呼び出し方は、サーブレットでもいいし、GWT-RPCでもいいです。

正直、なんでこれでpushされてくるのかイマイチがところはあります(笑)。サンプルとか殆どないのでわかりにくいですが、cometのことがわかっていれば理解可能だと思います。

2011-04-20

GAEのChannelAPIを理解する ~サーバ編~

GAEで、1.4から採用されたChannel APIについてちょっとわかってきたので簡単に報告します。

ChannelAPIとは
これは俗にいうCometの処理に相当します。チャットのようなPushするプログラミングを作成する際に、GAEのリソースを利用して実装できるというのは大きな魅力でしょう。

ChannelAPIにおいて理解しておくべき最低限の用語2つ
  • Token ・・・ ユーザとコネクションを貼るためのトークン。サーバーは最初の接続要求の時に、このTokenの値をクライアントに渡す必要があります。
  • channelKey ・・・接続チャンネル。ユーザごとに区別するような方法が一般的らしい。
最初の接続処理Tokenの生成部分
ChannelService channelService = ChannelServiceFactory.getChannelService();
String token = channelService.createChannel(channelKey);

//ここで生成されたtokenをクライアントに渡すこと


プッシュ処理(ユーザへの送信)部分
String message="なにか来ました"
ChannelService channelService = ChannelServiceFactory.getChannelService();
channelService.sendMessage(new ChannelMessage(channelKey, message));

とまあ、驚くほど簡単にできたりします。

ちょっとchannelKeyの設定の仕方はいろいろあるようですが、例えば1つに固定にしておくとそのchannelKeyで接続したユーザ全てに同じメッセージを送ることができました。単純にブロードキャストするだけでしたら、そういった方法もいいかもしれません。個別にプッシュ対応する場合は、該当するchannelKeyに対してのみ、sendMessageメソッドを呼び出せば良いのでしょう。

なお、GAE上で本格的に稼働させたわけではないので、どれぐらいの負荷がかかるのかは不明です。

クライアント編については、また後日。。。

2010-11-26

GAE/JでAmazon Product Advertising APIを使い始める際の注意事項

Amazon Product Advertising APIで遊んでいるわけですが、ちょっと注意することがあったのでメモ。このAPIについては、認証シグネチャーを要求するようになって、プログラム的にめんどくさそうな感じはしてるが、実際はサンプルプログラムに同梱されているSignedRequestHelperクラスを利用すれば問題ない。。。。はずなんですが、それでも認証のエラーが出ることがあります。これはBASE64エンコードの処理でトラブルらしいのですが、いろいろ情報が錯綜しているようなので,整理してみます。

【GAE/J上で動作させる場合】

  • commons-codec-1.3を利用するとOK
  • 最新版であるcommons-codec-1.4を利用するとエラーになります。

参考までに、

【GAE/J以外で動作させる場合(例えばGlassfishの場合)】

  • commons-codec-1.4での動作OK

ということらしいです。

また、いろいろ検索して出てくる

Base64 encoder = new Base64(); を Base64 encoder = new Base64(0); に修正する

というのもやらなくても動きました。(逆に0を追記するとエラーになりました。1.4では)これは古い情報なのでしょうか?