読者です 読者をやめる 読者になる 読者になる

G*でGCMを試した時のメモ

ことしの G* Advent Calendar 2012 : ATND
id:orangeclover さんの言ではないけど皆さん気合入ってますね〜*1

みなさんみたいなカッコいいお話も書けないので
ちょっと下調べ的メモのお話を*2

 GaelykというGroovyでGAEを簡単に触るためのライブラリがあります
エントリが雑多したので分割しました

Gaelyk自体の説明は id:ksky さん , id:mottsnite さんのスライドを参照



JGGUGの先生方は既に通った道を後追いしてるだけのはずなのに
スムーズに行かずに唸ってる自分が居ますですねorz


とりあえず先に進めます

     classpath 'org.gradle.api.plugins:gradle-gae-plugin:0.8'
     classpath 'org.gradle.api.plugins:gradle-gaelyk-plugin:0.4'

    def gaeVersion = '1.7.3'

あたり


./gradlew eclipse
./gradlew idea
IDE用の設定ファイル作成

graldeのIDEA設定ファイル系の話は @mike_neckさんの記事を参考に


で、eclipseでプロジェクトをインポートすると


Groovy:Unexpected problem with AST transform: The Spock compiler plugin cannot execute because Spock 0.6.0-groovy-1.8 is not compatible with Groovy 2.0.0. For more information, see http://versioninfo.spockframework.org
なエラーが出るので

な感じで対処。

一応、プロジェクト単位でGroovyCompileの設定で 1.8 な指定があるけど効かないね・・
「設定切り替え & ./eclipse -clean」
で動くようになりましたが・・・
何時も思うけどeclipseの対応甘いような*5

testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'

追記してみて


./gradlew eclipse
してみてもダメ*6

まあココらへんは Gも駆使できるTDDクラスタ
id:irof さん、id:orangeclover さん id:absj31 さん id:kyon_mm さん
あたりならサクッと修正できるんだろうけどなー
とか思いつつ、自分には難しそうなので先に進みます*7



第1段階>
で GCMのでもアプリを動かしてみましょう

でメモった kojiokbさんのスライドより

$ANDROID_HOME/extras/google/gcm/samples
を動かしやすい処にコピーしてきます

gcm-demo-server の方はjettyで動かすことになっていますので
build.gradleファイルをちゃっと作って動かしてみましょう*8

javax.servlet:servlet-api 自体は mavenCentral()に存在はしていますので
libの物を参照しなくてもいいかも・・・

apply plugin : 'jetty'

repositories {
	//mavenCentral()
	flatDir name: 'servlet', dirs: 'lib'
	flatDir name: 'gcm', dirs: 'WebContent/WEB-INF/lib'
}

dependencies {
	compile 'javax.servlet:servlet-api:2.5'
	compile 'com.google.android.gcm.server:gcm-server:'
	compile 'org.json.simple:json_simple:1.1'
}

sourceSets.main.java.srcDirs=['src']
sourceSets.main.output.classesDir = 'WebContent/WEB-INF/classes'

jettyRun {
	contextPath = "gcm-demo"
	webAppSourceDirectory=new File('WebContent')
	httpPort = 9090
}

Google API Consoleから取得したapikeyは
samples/gcm-demo-server/WebContent/WEB-INF/classes
api.key に設定します

gradlew jettyRun

まだこの段階だとローカルアクセスになりますので
jettyを起動するPC と Android を同一Wifi上につなぎます

でJettyを動かしているPCで

ipconfig

あとはSENDER_IDは
https://code.google.com/apis/console/#project:4815162342
だとすると [4815162342]の部分とのお話。

これをgcm-demo-client のAndroidサンプルに転記

public final class CommonUtilities {

    /**
     * Base URL of the Demo Server (such as http://my_host:8080/gcm-demo)
     */
    static final String SERVER_URL = "http://192.168.1.101:9090/gcm-demo";

    /**
     * Google API project id registered to use GCM.
     */
    static final String SENDER_ID = "4815162342";

なイメージ。


第2段階>
で 今度はGaelykで動かしてみましょう(途中)


いちから作るのは面倒なので
gcm/sample/gcm-demo-appengine からファイルをチョピチョピコピーしていきましょう

WebContents/favicon.png => src/main/webapp/images/favicon.png

GCMライブラリのコピー>
WebContents/WEB-INF/lib => src/main/webapp/WEB-INF/lib
gcm-server.jar
json_simple-1.1.jar

=>
この方法は gralde gaeRun タスク時等に 毎度 src/main/webapp/WEB-INF/lib 等も cleanされてしまいますので
libフォルダを作成しその中に
 gcm-server.jar
 json_simple-1.1.jar
を設置します

buildscript {
    repositories {
        mavenCentral()
	flatDir name: 'gcm', dirs: 'lib' //★
    }

    dependencies {
        classpath 'org.gradle.api.plugins:gradle-gae-plugin:0.8'
        classpath 'org.gradle.api.plugins:gradle-gaelyk-plugin:0.4'
        classpath 'eu.appsatori:gradle-fatjar-plugin:0.1.1'
	classpath 'com.google.android.gcm.server:gcm-server:' //★
	classpath 'org.json.simple:json_simple:1.1' //★
    }
}

repositories {
    mavenCentral()
    flatDir name: 'gcm', dirs: 'lib' //★
}

dependencies {
        //略

	compile 'com.google.android.gcm.server:gcm-server:' //★
	compile 'org.json.simple:json_simple:1.1' //★
}


task copyRuntimeLibraries(type: Sync) {
    def webAppLibDirName = 'src/main/webapp/WEB-INF/lib'
    description = "Copies runtime libraries to $webAppLibDirName."
    from configurations.runtime
    into webAppLibDirName
	
	//gcm
	from 'lib'                            //★
	into webAppLibDirName     //★
}


でGroovletに起き直せるServlet
src/main/webapp/WEB-INF/groovy
にコピーして改変

書き直しの情報自体は

や本家のチュートリアル & 上記に上げたスライドを参照

ざっと見る限り
src/main/groovy
src/main/java

src/main/webapp/groovy .. controller と service 用
の構成でよいようです

と思ったのですが、src/main/java に書いている所のコンパイルには
buildscriptの段階でのclasspath参照が必要なようです<でないと参照エラーが出る。

最新版のgaelykだと
src/main/java にライブラリ参照有りの物を置く想定には
なっていないのかもしれません*9



src/main/webapp/WEB-INF/routes.groovy に登録を記載

get "/", forward: "/home"

get "/home", forward: "/HomeServlet.groovy"
//post "/send", forward: "/SendMessageServlet.groovy"
post "/sendAll", forward: "/SendAllMessagesServlet.groovy"
post "/unregister", forward: "/UnregisterServlet.groovy"
post "/register", forward: "/RegisterServlet.groovy"

get "/favicon.ico", redirect: "/images/gaelyk-small-favicon.png"

置き直しが無理なものに関しては
src/main/java
  ApiKeyInitializer.java
  BaseServlet.java
  Datastore.java
  SendMessageServlet.java
にコピー。ついでに api.key もコピー

src/main/webapp/WEB-INF/web.xml に登録します

    <listener>
        <listener-class>groovyx.gaelyk.GaelykServletContextListener</listener-class>
		<!-- //append start-->
        <listener-class>com.google.android.gcm.demo.server.ApiKeyInitializer</listener-class>
		<!-- //append end-->
    </listener>

<!-- //append start-->
  <servlet>
    <servlet-name>SendMessageServlet</servlet-name>
    <servlet-class>
      com.google.android.gcm.demo.server.SendMessageServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  
  <servlet-mapping>
    <servlet-name>SendMessageServlet</servlet-name>
    <url-pattern>/send</url-pattern>
  </servlet-mapping>
<!-- //append end-->


src/main/webapp/WEB-INF/ に
queue.xml もコピーします


で 一般の例にあるような groovletのみのデフォルトの状態のような実装であれば
通常は
ローカル実行は

gradlew gaeRun


アップロードは

gradlew gaeUpdate

で行くはずなのですが、
src/main/java で参照しているGCMのライブラリの方で
「Loggerが見つからないよ!」 と起動時エラーが出てしまいます *10

という形でタイムアウトな感じです。
ここらへんは

  1. デモサンプルのようにライブラリに頼る形ではなく自前で実装する?
  2. ローカル鯖版のように実行、デプロイのみのgradleを作る?
  3. GroovletでRestfulなサービスを作る方法 - TEPPEI STUDIO みたいなgroovletを作る?

の形になるかもしれません


一応PHP等で実装されている方はいらっしゃるようです

groovlet置換で引っかかってるのはキューイングしてGCM飛ばす所だったりするので
そこら辺差っ引いちゃうと楽なのかなと思ったりも

結論として
Gaelykだけでやろうとすると移植が難しいものがあるよ・・・
というお話になってしましました
しまりが悪くて大変残念です〜><


追記)
下記の記述+αで

gradlew gaeRun

までは行くけと

gradlew gaeUpdate

は行かず。。。。すごく残念><

な感じなのかな。。。
Gaelyk対応のお話は書いてあるんだけどね。。
ピンで GitHub - bmuschko/gradle-gae-plugin: Gradle plugin that provides tasks for uploading, running and managing Google App Engine projects は厳しいのかも

要)

  1. src/main/webapp/WEB-INF/lib => lib にjarを退避
  2. 下記のbuild.gradleを作って実行
//apply plugin : 'jetty'
apply plugin : 'gae'

buildscript {
    repositories {
        mavenCentral()
    }

    dependencies {
        classpath 'org.gradle.api.plugins:gradle-gae-plugin:0.8'
        classpath 'eu.appsatori:gradle-fatjar-plugin:0.1.1' //need optimizeWar task
   }
}


repositories {
	mavenCentral()
	flatDir name: 'gcm', dirs: 'lib'
}

dependencies {
	gaeSdk 'com.google.appengine:appengine-java-sdk:1.7.3'

	def gaeVersion = '1.7.3'
	compile "com.google.appengine:appengine-api-1.0-sdk:$gaeVersion",
                     "com.google.appengine:appengine-api-labs:$gaeVersion"

	compile 'javax.servlet:servlet-api:2.5'
	compile 'com.google.android.gcm.server:gcm-server:'
	compile 'org.json.simple:json_simple:1.1'
}

sourceSets.main.java.srcDirs=['src']
sourceSets.main.output.classesDir = 'WebContent/WEB-INF/classes'

gae {
    httpPort = 9090
	webAppSourceDirectory=new File('WebContent')
	optimizeWar = true
	
	appcfg {
        email = E_MAIL
        passIn = true
        //passIn = false
        //password = PASS_WD

        logs {
            severity = 1
            outputFile = new File('mylogs.txt')
        }
		app {
            id = 'gradle-gae-test'
        }
    }
	jvmFlags = ['-Xdebug', '-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000']
	
    downloadSdk = true
    //warDir = file('WebContent')
}


task copyRuntimeLibraries(type: Sync) {
    def webAppLibDirName = 'WebContent/WEB-INF/lib'
    description = "Copies runtime libraries to $webAppLibDirName."
    from configurations.runtime
    into webAppLibDirName
	
	//gcm
	from 'lib'
	into webAppLibDirName
}

gaeRun.dependsOn copyRuntimeLibraries
  • gradle.properties
E_MAIL=XXXXXXX@gmail.com

*1:orange_cloverさんもすごい記事書いてた。さすがGエバンジェリストw

*2:実際はgaelykの話をしたかったけどタイムアウト気味・・

*3:gaeやpluginが更新されていますので

*4:GAEのランタイムに関してはgradleが落としてきます

*5:STSなら効くという落ちなのかな? あれだいぶ拡張されてるらしいし

*6:ちなみにこのeclipseコマンド追記型っぽい ので再実行する場合は .classpath、.project を消してから行うこと

*7:残念ですが1開発者レベル何度で。。。#なごやこわい

*8:ディレクトリ構成がいい加減なのでチョット変速気味な感じですが・・

*9:日本語訳の旧版だと動きそうなお話に読めるのですが・・・

*10:src/main/webapp/WEB-INF/java のようなスコープ参照でlogging.properties が参照できないと無理そう