Blog do projektu Open Source JavaHotel

wtorek, 8 stycznia 2013

Google App Engine and Jython

Introduction
I'm planning to use Jython with Google App Engine for Java. My purpose is to use Jython as a scripting language for Java based solution, not to use Jython for server code development. I was interested to check if I can launch Jython (Python) packages at the server side. It was successful but with several drawbacks. The source code (Java and simple Jython package) is uploaded. The application (simple extension to default Eclipse plugin application) is available here.
Problem, strange behaviour in Development Mode
While running the application in Development Mode the following exception was thrown

Caused by: java.lang.NoClassDefFoundError: java.io.FileOutputStream is a restricted class. Please see the Google  App Engine developer's guide for more details.
 at com.google.appengine.tools.development.agent.runtime.Runtime.reject(Runtime.java:51)
 at org.python.core.io.StreamIO.getOutputFileDescriptor(StreamIO.java:205)
 at org.python.core.io.StreamIO.getOutputFileDescriptor(StreamIO.java:212)
 at org.python.core.io.StreamIO.getOutputFileDescriptor(StreamIO.java:212)
I found that the culprit is the following method in PySystemState.java
 private void initEncoding() {
        String encoding = registry.getProperty(PYTHON_CONSOLE_ENCODING);
        if (encoding == null) {
            return;
        }
        for (PyFile stdStream : new PyFile[] {(PyFile)this.stdin, (PyFile)this.stdout,
                                              (PyFile)this.stderr}) {
            if (stdStream.isatty()) {
                stdStream.encoding = encoding;
            }
        }
    }
The java.io.FileOutputStream is not on the Google App Engine "white list" but the same code is running after deploying to Google App Engine environment. The solution is to remove file.encoding property (although this property is set to not null value in Google App Engine).
  System.getProperties().remove("file.encoding");
Not blocking exception 
The following exception is also thrown
Caused by: java.security.AccessControlException: access denied (java.lang.RuntimePermission modifyThreadGroup)
 at java.security.AccessControlContext.checkPermission(AccessControlContext.java:374)
 at java.security.AccessController.checkPermission(AccessController.java:546)
 at java.lang.SecurityManager.checkPermission(SecurityManager.java:532)
 at com.google.appengine.tools.development.DevAppServerFactory$CustomSecurityManager.checkPermission(DevAppServerFactory.java:289)
 at com.google.appengine.tools.development.DevAppServerFactory$CustomSecurityManager.checkAccess(DevAppServerFactory.java:314)
 at java.lang.ThreadGroup.checkAccess(ThreadGroup.java:299)
 at java.lang.Thread.init(Thread.java:336)
 at java.lang.Thread.(Thread.java:462)
It seems to be related to the fact that threads are not allowed in Google App Engine. But this exceptions seems to be not blocking.
Performance
    static String getrVal() {
        putMessage("Moment 1");
        String encoding = System.getProperty("file.encoding");
        putMessage("Encoding:" + encoding);
        System.getProperties().remove("file.encoding");
        PythonInterpreter interp = new PythonInterpreter();
        URL ur = JythonMeth.class.getClassLoader().getResource("resource");
        String sRe = ur.getFile();

        interp.exec("import sys");
        interp.exec("print sys.path");
        interp.exec("sys.path.append('" + sRe + "')");

        interp.exec("import sys");
        interp.exec("print sys.path");

        putMessage("Moment 2");
        interp.exec("import mypack");
        putMessage("Moment 3");

        interp.exec("from mypack import myprint");
        putMessage("Moment 4");
        interp.exec("myprint.myprint()");
        putMessage("Moment 5");
        interp.exec("GG = myprint.getVal()");
        PyObject sy = interp.get("GG");
        PyString u = (PyString) sy;
        String ss = u.getString();
        putMessage(ss);

        Map<object pyobject="pyobject"> m = new HashMap<object pyobject="pyobject">();
        PyObject keyS = new PyString("value1");
        m.put("key1", keyS);
        keyS = new PyString("value2");
        m.put("key2", keyS);
        keyS = new PyString("value3");
        m.put("key3", keyS);
        PyStringMap pyMap = new PyStringMap(m);
        interp.set("GG", pyMap);
        interp.exec("myprint.myprintMap(GG)");

        return ss;
    }
The performance after deploying to Google App Engine is not satisfactory. But it depends on the machine type set as a host. This time table is related only when server is running the code for the first time, the second and the next are executed in no time. But in case of Google App Engine a request can be redirected to a fresh machine any time, so this problem really matters.
Machine Moment 1-2 (sec) Moment 3-4 (sec)
F1 11 6
F2 7 6
F4 5 3
Desktop 2 4
F1, F2 and F4 are described here. Moment 3-4 is related to the compiling of the junit package and can be improved by precompiling the jython package before deploying. Moment 1-2 is the time consumed by the initialization of the Jython. I do not understand why there is a such difference between local desktop and Google App Engine environment and do not see any solution to that problem.

Brak komentarzy:

Publikowanie komentarza