2013年5月12日日曜日

[Scala] AppEngine で Scala を使う

Eclipse + App Engine で Scala を使ってみる。

以前、既存 Java プロジェクトで Scala を使えるようにする方法は確認したので、 Google Web Application プロジェクトを作って、 そこで Scala が使えるようにする方法で行く。


準備


まず Google App Engine の管理コンソールからこのテスト用に Application を作成。
Project Properties から Application ID を設定し Deploy して動作確認。
OK。動いている。


Google Web Application プロジェクトの Scala 化


やることは前回と同じ。Google Web Application プロジェクトをクローズして、.project ファイルと .classpath を編集する。詳しくは上述の記事を参照。

.project : buildCommand の javabuilder を scalabuilder に差し替えて、natures に scalanature を追加する。

...
  <buildSpec>
    <buildCommand>
      <name>org.scala-ide.sdt.core.scalabuilder</name>
      <arguments>
      </arguments>
    </buildCommand>
    <buildCommand>
      <name>org.eclipse.wst.common.project.facet.core.builder</name>
      <arguments>
      </arguments>
    </buildCommand>
...
  <natures>
    <nature>org.scala-ide.sdt.core.scalanature</nature>
    <nature>org.eclipse.jdt.core.javanature</nature>
...
  </natures>
</projectDescription>

.classpath : classpath に SCALA_CONTAINER を追加。

<?xml version="1.0" encoding="UTF-8"?>
<classpath>
  <classpathentry kind="src" path="src"/>
  <classpathentry kind="con" path="com.google.appengine.eclipse.core.GAE_CONTAINER"/>
  <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
  <classpathentry kind="con" path="org.scala-ide.sdt.launching.SCALA_CONTAINER"/>
  <classpathentry kind="output" path="war/WEB-INF/classes"/>
</classpath>



enhancerbuilder の除去


プロジェクトが Scala 化したので Java に加えて Scala ファイルを使えるようになる。
しかし、Scala クラスを追加するとビルド時に以下のようなエラーが出るようになった。

DataNucleus Enhancer (version 1.1.4) : Enhancement of classes
...
org.datanucleus.exceptions.ClassNotResolvedException: 
    Class "xawa.appengine.scalatest.Hoge" was not found in the CLASSPATH. 
    Please check your specification and your CLASSPATH.
...
  at com.google.appengine.tools.enhancer.Enhance.main(Enhance.java:51)

JDO のエンハンサがエラーになる。エンハンサはコンパイルされたクラスに JDO の機能を付加するためのツール。追加した Scala クラスは特に JDO のアノテーションがついているわけではないのだがエラーになってしまうようだ。

ググっていろいろ調べたのだが、やはりエンハンサを動かなくしてしまうしかなさそう。
もちろんエンハンサを除去すると JDO は動かなくなる。
さらば JDO。こんにちは Low Level API。

.project ファイルを編集して BuildSpec から enhancerbuilder を除去する。

...
  <buildSpec>
<!--
    <buildCommand>
      <name>com.google.appengine.eclipse.core.enhancerbuilder</name>
      <arguments>
      </arguments>
    </buildCommand>
-->
  </buildSpec>
  <natures>
...



scala-library を追加


このままデプロイして実行すると以下のエラーになる。

java.lang.NoClassDefFoundError: scala/ScalaObject
  at com.google.appengine.runtime.Request.process-698812e72e5425e1(Request.java)
  ...

Scala 関連の ライブラリがサーバーにアップロードされていないのが原因。

Scala IDE で標準で組み込まれるライブラリは scala-library.jar、scala-dbc.jar、scala-swing.jar の3つ。 App Engine の制約で Swing は使用できないので、scala-swing は入れるだけ無駄。 scala-dbc はJDBCのラッパーなのだが、App Engine 環境で Scala の DBC を使うことはないのでこれもいらない。
scala-library.jar だけ war に含めることにする。

war/WEB-INF/lib に、scala-library.jar をコピーしてデプロイ。
動いた。


JSP


念のため、JSPを使ってみたが問題なく動く。
テストに使ったコードは以下の通り。

AppEngineScalaTestServlet.scala:

package xawa.appengine.scalatest

import javax.servlet.http.HttpServlet
import javax.servlet.http.HttpServletRequest
import javax.servlet.http.HttpServletResponse
import javax.servlet.RequestDispatcher

class AppEngineScalaTestServlet extends HttpServlet {
  override def doGet(req : HttpServletRequest , resp : HttpServletResponse) {
    val hoge = new Hoge;
    req.setAttribute("hoge", hoge);
    val rd = getServletContext().getRequestDispatcher(
           "/jsp/AppEngineScalaTest.jsp");
    rd.forward(req, resp);
  }
}

class Hoge {
  def test() : String = "This is Scala's Hoge."; 
}

AppEngineScalaTestServlet.jsp:

<%@ page import="java.util.*" contentType="text/html; charset=utf-8" %>
<jsp:useBean id="message" class="java.lang.String" scope="request"/>
<%@ page import="xawa.appengine.scalatest.Hoge" %>
 <HTML><BODY>
 message: <%= ((Hoge)request.getAttribute("hoge")).test() %>
</BODY> </HTML>



まとめ


まとめておこう。

  • .project
    • buildCommand の javabuilder を scalabuilder に差し替え
    • natures に scalanature を追加
    • JDO の enhancerbuilder を除去 ( JDO は使えない )
  • .classpath に com.google.appengine.eclipse.core.GAE_CONTAINER を追加
  • war/WEB-INF/lib に scala-library.jar をコピー。



0 件のコメント:

コメントを投稿