CommonLisp (ABCL) on GAE

11 月 2nd, 2009 in Java, Lisp users

GAEでLispを動かそうっていうのが少しはやっているみたいだから、便乗してみた。
というか前からやっていたが、放置していた。

方針としてはえらい前にためしたClojureServletとほとんど同じ。
ABCLの公式にもGAEに対応した風なサンプルがあるけど、これはLispでサーブレットを書いてるだけなので、いまいち。やっぱりCGIみたいにlispファイルをそのままロードしてhtmlをprintするほうがLisp on GAEでは自然。他の言語のGAE対応版もそうなってるしね。

で、いきなりサーブレットの実装

package am.ik.cl.servlet;
 
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
 
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.armedbear.lisp.Stream;
import org.armedbear.lisp.Symbol;
 
@SuppressWarnings("serial")
public class AbclServlet extends HttpServlet {
    private String encoding = "UTF-8"; // default
    private String lispDir = "/WEB-INF/lisp"; // default
    private static final String ENCODING_KEY = "encoding";
    private static final String LISP_DIR_KEY = "lisp.dir";
    private final ScriptEngine engine;
    private final String STANDARD_OUTPUT_NAME = "*standard-output*";
    private final String REQUEST_NAME = "*request*";
    private final String RESPONSE_NAME = "*response*";
    private final String ROOT_DIR_NAME = "*web-context-root-dir*";
    private final String LISP_EXTENSION = "lisp";
 
    public AbclServlet() {
        engine = new ScriptEngineManager().getEngineByExtension(LISP_EXTENSION);
    }
 
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        String encoding = config.getInitParameter(ENCODING_KEY);
        String lispDir = config.getInitParameter(LISP_DIR_KEY);
        if (encoding != null && !encoding.isEmpty()) {
            this.encoding = encoding;
        }
        if (lispDir != null && !lispDir.isEmpty()) {
            this.lispDir = lispDir;
        }
    }
 
    @Override
    public void service(HttpServletRequest req, HttpServletResponse res)
            throws ServletException, IOException {
        res.setContentType("text/html; charset=" + encoding);
        String path = req.getServletPath();
        InputStream in = getServletContext()
                .getResourceAsStream(lispDir + path);
        engine.put(STANDARD_OUTPUT_NAME, new Stream(res.getOutputStream(),
                Symbol.CHARACTER, Symbol.internKeyword(encoding)));
        engine.put(REQUEST_NAME, req);
        engine.put(RESPONSE_NAME, res);
        if (lispDir.startsWith("/")) {
            engine.put(ROOT_DIR_NAME, lispDir.substring(1));
        } else {
            engine.put(ROOT_DIR_NAME, lispDir);
        }
        if (in != null) {
            try {
                engine.eval(new InputStreamReader(in));
            } catch (ScriptException e) {
                throw new ServletException(e);
            }
        } else {
            res.sendError(HttpServletResponse.SC_NOT_FOUND);
        }
    }
}

前回と同じように、req.getOutputStreamをLisp側の標準出力Streamにバインディングして、HttpServletRespose, HttpServletRequestを*response*、*request*にバインディングして、スクリプトをロードするだけ。
今回はjavax.scriptに対応している他のエンジンでも使えるようにScriptEngineを使ってみました。
あとweb.xmlに

<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	version="2.5">
	<servlet>
		<servlet-name>cl-servlet</servlet-name>
		<servlet-class>am.ik.cl.servlet.AbclServlet</servlet-class>
		<init-param>
			<param-name>encoding</param-name>
			<param-value>UTF-8</param-value>
		</init-param>
		<init-param>
			<param-name>lisp.dir</param-name>
			<param-value>/WEB-INF/lisp</param-value>
		</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>cl-servlet</servlet-name>
		<url-pattern>*.lisp</url-pattern>
	</servlet-mapping>
	<welcome-file-list>
		<welcome-file>index.lisp</welcome-file>
	</welcome-file-list>
</web-app>

こんな感じの設定をすればおk。
この設定の場合war/WEB-INF/lisp以下にlispファイルをおけば,
webappname/hogehoge.lispでアクセスできる。

スクリプトのルートはwarディレクトリ以下になるので、lispからファイルをロードするときは

(load "WEB-INF/lisp/bar.lisp")

のようにしないといけない。いちおう、*web-contxet-root-dir*にweb.xmlに設定した”WEB-INF/lisp”がバインディングされるようになっている。
クエリパラメータは

(jcall "getParameter" *request* "hoge")

でとれる。

このサーブレットを使って、一応GAEで動作確認できた。
http://aho.appspot.com/index.lisp
表示に使っているlispファイルはこちら

これはEclipseのプロジェクトまるごとなんで、checkoutすればそのまま試せる。

svn co http://cl-server-pages.googlecode.com/svn/trunk/samples/cl-server-pages-gae-sample

ちなみ普通のWTP版サンプルも用意したが、(load “hogehoge”)するとエラーが出てる。調査中。それ以外は動く。

GAEでcl-whoも動くみたいなので、次回はもう少し実用的なサンプルをつかってみる。

Leave a Reply

Recent Posts

よく考えたらこれでいいじゃん http://bit.ly/bsxqE0 MapperとReducer別々にしないとReflection走るな RT @making: multimethodでたくさん書くのが面倒だからこんなマクロ作った http://bit.ly/bsxqE0
* 10年03月11日03時09分

@junkawamoto うお、おれ明日源泉徴収票届く予定w
* 10年03月11日01時55分

@ryushi スプライシングクオートは楽して大量にS式を自動生成したいときに結構使います。よく入力をmapでごにょごにょ加工して~@したり。 単純な例だとこんなことができます http://gist.github.com/328042
* 10年03月11日01時48分

» Twitter

Search

ドミノ・ピザ 5%OFF!

デル株式会社

 iTunes Store(Japan)

 iTunes Store(Japan)

Sony Style(ソニースタイル)

ツートップインターネットショップ(twotop.co.jp)

Recommend

アルゴリズムC++
アルゴリズムC++
¥ 7,980(新品) /¥ 5,100(中古)
データ構造・アルゴリズムの基礎に関して
一通り網羅されている.
一冊机の上に置いておきたい.
C++で書かれているのも珍しい
(古いC++だけど..)

view all

Categories

Tags