クエリストリングの取得と cl-who(ABLC で Google app engine)
前回 ABCL で Google app engine が動いたので、今回はクエリスティングの取得と cl-who の使用をやってみた。
Sevlet クラスで currentThread.execute するときに req と resp を JavaObject でくるんでわたしてやる。
package abcl_ae;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.armedbear.lisp.ConditionThrowable;
import org.armedbear.lisp.JavaObject;
import org.armedbear.lisp.Lisp;
import org.armedbear.lisp.LispThread;
import org.armedbear.lisp.SpecialBinding;
import org.armedbear.lisp.Symbol;
@SuppressWarnings("serial")
public class NextServlet extends HttpServlet {
static private Symbol doGet2 = null;
public void init() throws ServletException {
AbclInit.init();
try {
doGet2 = Lisp.internInPackage("DO-GET2", "FIRST-SERVLET");
} catch (ConditionThrowable ct) {
}
}
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws IOException {
LispThread currentThread = LispThread.currentThread();
SpecialBinding lastSpecialBinding = currentThread.lastSpecialBinding;
currentThread.bindSpecial(Symbol.STANDARD_OUTPUT,
new org.armedbear.lisp.Stream(resp.getOutputStream(),
Symbol.CHARACTER, Symbol.internKeyword("UTF-8")));
resp.setContentType("text/html; charset=utf-8");
try {
currentThread.execute(doGet2, new JavaObject(req), new JavaObject(resp));
} catch (ConditionThrowable condition) {
resp.setContentType("text/plain");
resp.getWriter().println(condition.toString());
} finally {
currentThread.lastSpecialBinding = lastSpecialBinding;
}
}
}
lisp ファイルの方は関数(go-get2)に引数を2つ追加。 java:jcall で getParameter メソッドを呼び出せばクエリストリングが取得できる。
あと cl-who を使うために asdf を rquire し、fasls/cl-who/ を asdf:*central-registry*
に追加。 (asdf:oos 'asdf:load-op :cl-who) で cl-who が使えるようになる。
(require 'asdf)
(pushnew "fasls/cl-who/" asdf:*central-registry* :test #'equal)
(asdf:oos 'asdf:load-op :cl-who)
(defun do-get2 (request response)
(declare (ignore response))
(let ((foo (java:jcall "getParameter" request "foo"))
(bar (java:jcall "getParameter" request "bar")))
(cl-who:with-html-output (*standard-output*)
(:html (:head (:title "cl-who"))
(:body (:h1 "CL-WHO")
(:form :method :get :action "next"
(:div "foo " (:input :type :text :name "foo"))
(:div "bar " (:input :type :text :name "bar"))
(:input :type :submit :value "クリック"))
(:div (cl-who:esc (format nil "foo => ~a" foo)))
(:div (cl-who:esc (format nil "bar => ~a" bar))))))
(force-output)))
cl-who はあらかじめ ABCL でコンパイルしておいて、*.asd と *.abcl
を war/fasls/cl-who にコピーしておく必要がある。これがうまい方法かどうかわまだ分からないけど。そのための build.xml を書いた(コピペした)。
<project basedir="." default="all">
<property name="sdk.dir" location="/home/ancient/local/opt/appengine-java-sdk" />
<property name="clbuild.dir" location="/home/ancient/letter/lisp/clbuild/source" />
<import file="${sdk.dir}/config/user/ant-macros.xml" />
<path id="project.classpath">
<pathelement path="war/WEB-INF/classes" />
<fileset dir="war/WEB-INF/lib">
<include name="**/*.jar" />
</fileset>
<fileset dir="${sdk.dir}/lib">
<include name="shared/**/*.jar" />
</fileset>
</path>
<target name="all" depends="clean,copy-files" />
<target name="clean">
<delete dir="war/fasls" />
</target>
<target name="copy-files">
<copy todir="war/fasls">
<fileset dir="src/lisp">
<include name="**/*.abcl"/>
</fileset>
</copy>
<copy todir="war/fasls/cl-who">
<fileset dir="${clbuild.dir}/cl-who">
<exclude name="**/_darcs/**"/>
<include name="**/*.abcl"/>
<include name="**/*.asd"/>
</fileset>
</copy>
</target>
<target name="devserver" description="run local dev appserver" depends="all">
<dev_appserver war="war" />
</target>
<target name="deploy" description="deploy to appspot" depends="all">
<appcfg action="update" war="war" />
</target>
</project>
けっこういける気がしてきた。まだ Servlet とのつながり(レスポンスやポストとか)とかいろいろ問題ありそうだけど。あと開発サイクルとかも。ソース修正のたびに開発サーバ再起動はきつい。でも解決方法はある気がする。
MOP で Google app engine のデータストアうまく扱えないかしらん。どうせならちゃんと Common Lisp っぽくいきたいよね。