Hi Andi,

Thanks for the help, now I was able to run the java and loaded
PythonVM. I then built the python egg, after a bit of fiddling with
parameters, it seems ok. I can import the jcc wrapped python class and
call it:

In [1]: from solrpie_java import emql

In [2]: em = emql.Emql()

In [3]: em.javaTestPrint()
java is printing

In [4]: em.pythonTestPrint()
just a test

But I haven't found out how to call the same from java.

The egg is built fine, it is named solrpie_java and contains one python module:

==============

from solrpie_java import initVM, CLASSPATH, EMQL

initVM(CLASSPATH)


class Emql(EMQL):
    '''
    classdocs
    '''

    def __init__(self):
        super(Emql, self).__init__()
        print '__init__'


    def init(self, me):
        print self, me
        return 'init'
    def emql_refresh(self, tid, type):
        print self, tid, type
        return 'refresh'
    def emql_status(self):
        return "some status"

    def pythonTestPrint(self):
        print 'just a test'

========
The corresponding java class looks like this:


public class EMQL {

           private long pythonObject;

           public EMQL()
           {
           }

           public void pythonExtension(long pythonObject)
           {
               this.pythonObject = pythonObject;
           }
           public long pythonExtension()
           {
               return this.pythonObject;
           }
        
           public void finalize()
               throws Throwable
           {
               pythonDecRef();
           }
        
           public void javaTestPrint() {
                   System.out.println("java is printing");
           }

           public native void pythonDecRef();

           // the methods implemented in python
           public native String init(EMQL me);
           public native String emql_refresh(String tid, String type);
           public native String emql_status();
        
           public native void pythonTestPrint();
        
                
}

=======

I tried running it as:

                PythonVM vm = PythonVM.start("sorlpie_java");
                EMQL em = new EMQL();
                em.javaTestPrint();
                em.pythonTestPrint();

I get this:

java is printing
Exception in thread "main" java.lang.UnsatisfiedLinkError:
rca.pythonvm.EMQL.pythonTestPrint()V
        at rca.pythonvm.EMQL.pythonTestPrint(Native Method)
        at rca.solr.JettyRunnerPythonVM.start(JettyRunnerPythonVM.java:60)
        at rca.solr.JettyRunnerPythonVM.main(JettyRunnerPythonVM.java:148)

I understand that java cannot find the linked c++ method, but I don't
know how to fix that.
If i try:

PythonVM vm = PythonVM.start("sorlpie_java");
Object m = vm.instantiate("emql", "Emql");

I get:

org.apache.jcc.PythonException: No module named emql
ImportError: No module named emql

        at org.apache.jcc.PythonVM.instantiate(Native Method)
        at rca.solr.JettyRunnerPythonVM.start(JettyRunnerPythonVM.java:56)
        at rca.solr.JettyRunnerPythonVM.main(JettyRunnerPythonVM.java:148)

I tried various combinations of instanatiation, and setting the
classpatt or -Djava.library.path
But no success. What am I doing wrong?

Thank you,

  roman



On Wed, Jan 12, 2011 at 7:55 PM, Andi Vajda <va...@apache.org> wrote:
>
> On Wed, 12 Jan 2011, Roman Chyla wrote:
>
>> Hi Andi, all,
>>
>> I tried to implement the PythonVM wrapping on Mac 10.6, with JDK
>> 1.6.22, jcc is freshly built, in shared mode, v. 2.6. The python is
>> the standard Python distributed with MacOsX
>>
>> When I try to run the java, it throws an error when it gets to:
>>
>> static {
>>       System.loadLibrary("jcc");
>>   }
>>
>> I am getting this error:
>>
>> Exception in thread "main" java.lang.UnsatisfiedLinkError:
>>
>> /Library/Python/2.6/site-packages/JCC-2.6-py2.6-macosx-10.6-universal.egg/libjcc.dylib:
>> Symbol not found: _PyExc_RuntimeError   Referenced from:
>
> That's because Python's shared library wasn't found. The reason is that, by
> default, Python's shared lib not on JCC's link line because normally JCC is
> loaded into a Python process and the dynamic linker thus finds the symbols
> needed inside the process.
>
> Here, since you're not starting inside a Python process, you need to add
> '-framework Python' to JCC's LFLAGS in setup.py so that the dynamic linker
> can find the Python VM shared lib and load it.
>
> Andi..
>
>>
>> /Library/Python/2.6/site-packages/JCC-2.6-py2.6-macosx-10.6-universal.egg/libjcc.dylib
>>  Expected in: flat namespace  in
>>
>> /Library/Python/2.6/site-packages/JCC-2.6-py2.6-macosx-10.6-universal.egg/libjcc.dylib
>>        at java.lang.ClassLoader$NativeLibrary.load(Native Method)
>>        at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1823)
>>        at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1746)
>>        at java.lang.Runtime.loadLibrary0(Runtime.java:823)
>>        at java.lang.System.loadLibrary(System.java:1045)
>>        at org.apache.jcc.PythonVM.<clinit>(PythonVM.java:23)
>>        at rca.solr.JettyRunnerPythonVM.start(JettyRunnerPythonVM.java:53)
>>        at rca.solr.JettyRunnerPythonVM.main(JettyRunnerPythonVM.java:139)
>>
>>
>> MacBeth:JCC-2.6-py2.6-macosx-10.6-universal.egg rca$ nm libjcc.dylib |
>> grep Exc
>>                U _PyExc_RuntimeError
>>                U _PyExc_TypeError
>>                U _PyExc_ValueError
>> 0000000000003442 T __ZNK6JCCEnv15reportExceptionEv
>> 00000000000021f0 T __ZNK6JCCEnv23getPythonExceptionClassEv
>>
>>
>> Any pointers what I could do wrong? Note, I haven't built any emql.egg
>> yet, I just run my java program and try to start PythonVM() and see if
>> that works.
>>
>> Thanks,
>>
>>  roman
>>
>>
>>
>> On Wed, Jan 12, 2011 at 11:05 AM, Roman Chyla <roman.ch...@gmail.com>
>> wrote:
>>>
>>> Hi Andi,
>>>
>>> I think I will give it a try, if only because I am curious. Please see
>>> one remaining question below.
>>>
>>>
>>> On Tue, Jan 11, 2011 at 10:37 PM, Andi Vajda <va...@apache.org> wrote:
>>>>
>>>>
>>>> On Tue, 11 Jan 2011, Roman Chyla wrote:
>>>>
>>>>> Hi Andy,
>>>>>
>>>>> This is much more than I could have hoped! Just yesterday, I was
>>>>> looking for ways how to embed Python VM in Jetty, as that would be
>>>>> more natural, but found only jepp.sourceforge.net and off-putting was
>>>>> the necessity to compile it against the newly built python. I could
>>>>> not want it from the guys who may need my extension. And I realize
>>>>> only now, that embedding Python in Java is even documented on the
>>>>> website, but honestly i would not know how to do it without your
>>>>> detailed examples.
>>>>>
>>>>> Now to the questions, I apologize, some of them or all must seem very
>>>>> stupid to you
>>>>>
>>>>> - pylucene is used on many platforms and with jcc always worked as
>>>>> expected (i love it!), but is it as reliable in the opposite
>>>>> direction? The PythonVM.java loads "jcc" library, so I wonder if in
>>>>> principle there is any difference in the directionality - but I am not
>>>>> sure. To rephrase my convoluted question: would you expect this
>>>>> wrapping be as reliable as wrapping java inside python is now?
>>>>
>>>> I've been using this for over two years, in production.
>>>> My main worry was memory leaks because a server process is expected to
>>>> stay
>>>> up and running for weeks at a time and it's been very stable on that
>>>> front
>>>> too. Of course, when there is a bug somewhere that causes your Python VM
>>>> to
>>>> crash, the entire server crashes. Just like when the JVM crashes (which
>>>> is
>>>> normally rare). In other words, this isn't any less reliable than a
>>>> standalone Python VM process. It can be tricky, but is possible, to run
>>>> gdb,
>>>> pdb and jdb together to step through the three languages involved,
>>>> python,
>>>> java and C++. I've had to do this a few times but not in a long time.
>>>>
>>>>> - in the past, i built jcc libraries on one host and distributed them
>>>>> on
>>>>> various machines. As long the family OS and the python main version
>>>>> were the
>>>>> same, it worked on Win/Lin/Mac just fine. As far as I can tell, this
>>>>> does
>>>>> not change, or will it be dependent on the python against which the egg
>>>>> was
>>>>> built?
>>>>
>>>> Distributing binaries is risky. The same caveats apply. I wouldn't do
>>>> it,
>>>> even in the simple PyLucene case.
>>>
>>> unfortunately, I don't have that many choices left - this is not for
>>> some client-software scenario, we are running the jobs on the grid,
>>> and there I cannot compile the binaries. So, if previously the
>>> location of the python interpreter or python minor version did not
>>> cause problems, now perhaps it will be different. But that wasn't for
>>> the Solr, wrapping Solr is not meant for the grid.
>>>
>>>>
>>>>> - now a little tricky issue; when I wrap jetty inside python, I hoped
>>>>> to build it in a shared mode with lucene to be able to do some
>>>>> low-level lucene indexing tasks from inside Python. If I do the
>>>>> opposite and wrap Python VM in Java, I would still like to access the
>>>>> lucene (which is possible, as I see well from your examples) But on
>>>>> the python side, you are calling initVM() - will the initVM() call
>>>>> create a new Java VM or will it access the parent Java VM which
>>>>> started it?
>>>>
>>>> No, initVM() in this case just initializes your egg and adds its stuff
>>>> to
>>>> the CLASSPATH. No Java VM init is done. As with any shared-mode
>>>> JCC-built
>>>> extension, all calls to initVM() but the first one just do that.
>>>> The first call to initVM() in the embedding Python case is like that too
>>>> because there already is a Java VM running when PythonVM is instantiated
>>>> and
>>>> called.
>>>
>>> And if in the python, I will do:
>>>
>>> import lucene
>>> import lucene.initVM(lucene.CLASSPATH)
>>>
>>> Will it work in this case? Giving access to the java classes from
>>> inside python. Or I will have to forget pylucene, and prepare some
>>> extra java classes? (the jcc in reverse trick, as you put it)
>>>
>>>>
>>>>> - you say that threads are not managed by the Python VM, does that
>>>>> mean there is no Python GIL?
>>>>
>>>> No, there is a Pythonn GIL (and that is the Achille's Heel of this setup
>>>> if
>>>> you expect high concurrent servlet performance from your server calling
>>>> Python). That Python GIL is connected to this thread state I was
>>>> mentioning
>>>> earlier. Because the thread is not managed by Python, when Python is
>>>> called
>>>> (by way of the code generated by JCC) it doesn't find a thread state for
>>>> the
>>>> thread and creates one. When the call completes, the thread state is
>>>> destroyed because its refcount goes to zero. My TerminatingThread class
>>>> acquires a Python thread state and keeps it for the life of the thread,
>>>> thereby working this problem around.
>>>
>>> OK, this then looks like a normal Python - which is somehow making me
>>> less worried :) I wanted to use multiprocessing inside python to deal
>>> with GIL, and I see no reason why it should not work in this case.
>>>
>>> Thank you very much.
>>> Cheers,
>>>
>>>  roman
>>>
>>>>
>>>>> - I don't really know what is exactly in the python thread local
>>>>> storage, could that somehow negatively affect the Python process if
>>>>> acquireThreadState/releaseThreadState are not called?
>>>>
>>>> Yes, if you depend on thread-local storage, it would get lost between
>>>> calls
>>>> and cause confusion and bugs, defeating its purpose. Python's
>>>> thread-local
>>>> storage support is documented here:
>>>> http://docs.python.org/library/threading.html, look for threading.local.
>>>>
>>>> Andi..
>>>>
>>>>>
>>>>> Thank you.
>>>>>
>>>>> Cheers,
>>>>>
>>>>>  roman
>>>>>
>>>>>
>>>>> On Tue, Jan 11, 2011 at 8:13 PM, Andi Vajda <va...@apache.org> wrote:
>>>>>>
>>>>>>  Hi Roman,
>>>>>>
>>>>>> On Tue, 11 Jan 2011, Roman Chyla wrote:
>>>>>>
>>>>>>> I have recently wrapped solr inside jetty with JCC (we need to access
>>>>>>> very big result sets quickly, via JNI, but also keep solr running as
>>>>>>> normal) and was wondering what strategies do you guys use to speak
>>>>>>> *from inside* Java towards the Python end.
>>>>>>>
>>>>>>> So far, I was able to think about these:
>>>>>>>
>>>>>>> - raise exceptions in java and catch in python (I think I have seen
>>>>>>> this in some posts from Bill Jansen)
>>>>>>> - communicate via sockets
>>>>>>> - wait passively - call some java method and wait for its return
>>>>>>> - monitor actively - in python check in loop some java object
>>>>>>>
>>>>>>> Is there something else?
>>>>>>
>>>>>> I'm not sure I completely understand your questions but if what you're
>>>>>> asking is how to run Python code from inside a Java servlet container,
>>>>>> that
>>>>>> I've done with Tomcat and Lucene.
>>>>>>
>>>>>> Basically, instead of embedding a JVM inside a Python VM - as is done
>>>>>> for
>>>>>> PyLucene - you do the opposite, you embed a Python VM inside a JVM.
>>>>>>
>>>>>> For that purpose, see the org.apache.jcc.PythonVM class available in
>>>>>> JCC's
>>>>>> java tree. This class must be instantiated from the main thread at
>>>>>> Java
>>>>>> servlet engine startup time. In Tomcat, I patched some startup code,
>>>>>> in
>>>>>> BootStrap.java (see patches below) for this purpose.
>>>>>>
>>>>>> Then, to make some Python code accessible from Java, use the usual way
>>>>>> of
>>>>>> writing "extensions", the so-called JCC in reverse trick. Define a
>>>>>> Java
>>>>>> class
>>>>>> with some native methods implemented in Python; define a Python class
>>>>>> that
>>>>>> "extends" it; build the Java class into a JAR; include it into a
>>>>>> JCC-built
>>>>>> egg; install the egg into Python's env (site-packages, PYTHONPATH,
>>>>>> whatever);
>>>>>> Then, write servlet code in Java that imports your Java class and
>>>>>> calls
>>>>>> it.
>>>>>>
>>>>>> As you can see, this sounds simple but the devil is in the details. Of
>>>>>> course,
>>>>>> bending Jetty for this may have different requirements but the code
>>>>>> snippets
>>>>>> below should give you a good idea about what's required.
>>>>>>
>>>>>> This approach has been in production running the freebase.com's search
>>>>>> server
>>>>>> for over two years now.
>>>>>>
>>>>>> If you have questions, of course, please ask.
>>>>>> Good luck !
>>>>>>
>>>>>> Andi..
>>>>>>
>>>>>> ----------------------
>>>>>> Patch to Bootstrap.java to use JCC's PythonVM (which initializes the
>>>>>> embedded
>>>>>> Python VM)
>>>>>>
>>>>>> ---
>>>>>>
>>>>>> apache-tomcat-6.0.29-src/java/org/apache/catalina/startup/Bootstrap.java
>>>>>>    2010-07-19 06:02:32.000000000 -0700
>>>>>> +++
>>>>>>
>>>>>>
>>>>>> apache-tomcat-6.0.29-src/java/org/apache/catalina/startup/Bootstrap.java.patched
>>>>>>    2010-08-04 08:49:05.000000000 -0700
>>>>>> @@ -30,16 +30,18 @@
>>>>>>  import javax.management.MBeanServer;
>>>>>>  import javax.management.MBeanServerFactory;
>>>>>>  import javax.management.ObjectName;
>>>>>>
>>>>>>  import org.apache.catalina.security.SecurityClassLoad;
>>>>>>  import org.apache.juli.logging.Log;
>>>>>>  import org.apache.juli.logging.LogFactory;
>>>>>>
>>>>>> +import org.apache.jcc.PythonVM;
>>>>>> +
>>>>>>
>>>>>>  /**
>>>>>>  * Boostrap loader for Catalina.  This application constructs a class
>>>>>> loader
>>>>>>  * for use in loading the Catalina internal classes (by accumulating
>>>>>> all
>>>>>> of
>>>>>> the
>>>>>>  * JAR files found in the "server" directory under "catalina.home"),
>>>>>> and
>>>>>>  * starts the regular execution of the container.  The purpose of this
>>>>>>  * roundabout approach is to keep the Catalina internal classes (and
>>>>>> any
>>>>>>  * other classes they depend on, such as an XML parser) out of the
>>>>>> system
>>>>>> @@ -398,22 +400,24 @@
>>>>>>         try {
>>>>>>             String command = "start";
>>>>>>             if (args.length > 0) {
>>>>>>                 command = args[args.length - 1];
>>>>>>             }
>>>>>>
>>>>>>             if (command.equals("startd")) {
>>>>>>                 args[args.length - 1] = "start";
>>>>>> +                PythonVM.start("mql");
>>>>>>                 daemon.load(args);
>>>>>>                 daemon.start();
>>>>>>             } else if (command.equals("stopd")) {
>>>>>>                 args[args.length - 1] = "stop";
>>>>>>                 daemon.stop();
>>>>>>             } else if (command.equals("start")) {
>>>>>> +                PythonVM.start("mql");
>>>>>>                 daemon.setAwait(true);
>>>>>>                 daemon.load(args);
>>>>>>                 daemon.start();
>>>>>>             } else if (command.equals("stop")) {
>>>>>>                 daemon.stopServer(args);
>>>>>>             } else {
>>>>>>                 log.warn("Bootstrap: command \"" + command + "\" does
>>>>>> not
>>>>>> exist.");
>>>>>>             }
>>>>>>
>>>>>> -----------------------------------------
>>>>>> Define a Java class:
>>>>>>
>>>>>> package ....
>>>>>>
>>>>>> public class EMQL {
>>>>>>
>>>>>>    private long pythonObject;
>>>>>>
>>>>>>    public EMQL()
>>>>>>    {
>>>>>>    }
>>>>>>
>>>>>>    public void pythonExtension(long pythonObject)
>>>>>>    {
>>>>>>        this.pythonObject = pythonObject;
>>>>>>    }
>>>>>>    public long pythonExtension()
>>>>>>    {
>>>>>>        return this.pythonObject;
>>>>>>    }
>>>>>>
>>>>>>    public void finalize()
>>>>>>        throws Throwable
>>>>>>    {
>>>>>>        pythonDecRef();
>>>>>>    }
>>>>>>
>>>>>>    public native void pythonDecRef();
>>>>>>
>>>>>>    // the methods implemented in python
>>>>>>    public native String init(ME me);
>>>>>>    public native String emql_refresh(String tid, String type);
>>>>>>    public native String emql_status();
>>>>>>
>>>>>>    etc .......... etc
>>>>>>
>>>>>> ------------------------------------
>>>>>> The corresponding Python class
>>>>>>
>>>>>> import ......
>>>>>>
>>>>>> from jemql import initVM, CLASSPATH, EMQL
>>>>>>
>>>>>> initVM(CLASSPATH)
>>>>>>
>>>>>> class emql(EMQL):
>>>>>>
>>>>>>    def __init__(self):
>>>>>>        super(emql, self).__init__()
>>>>>>
>>>>>>    def init(self, me):
>>>>>>     ...........
>>>>>>    def emql_refresh(self, tid, type):
>>>>>>     ...........
>>>>>>    def emql_status(self):
>>>>>>     ...........
>>>>>>       return "some status"
>>>>>>
>>>>>>    etc ...... etc
>>>>>>
>>>>>> ------------------------------------
>>>>>> Makefile rules to build this via JCC (the jemql.egg file is just an
>>>>>> empty
>>>>>> target file for Makefile, it's not used for anything else):
>>>>>>
>>>>>> default: jemql.egg
>>>>>>
>>>>>> jemql.jar: java/org/blah/blah/EMQL.java
>>>>>>        mkdir -p classes
>>>>>>        javac -classpath $(CLASSPATH):$(MORE_CLASSPATH):$(etc..etc) -d
>>>>>> classes $(JAVAC_FLAGS) $<
>>>>>>        jar -cvf $@ -C classes .
>>>>>>
>>>>>> jemql.egg: jemql.jar $(JMQL_JAR) emql.py
>>>>>>        $(JCC) --version 1.0 --jar $< \
>>>>>>               --classpath $(CLASSPATH):$(JME_JAR):$(JMQL_JAR) \
>>>>>>               org.blah.blah.me.ME \
>>>>>>               --package java.lang \
>>>>>>               --python jemql --build $(DBG_FLAGS) \
>>>>>>               --install \
>>>>>>               --module emql
>>>>>>        touch $@
>>>>>> ------------------------------------
>>>>>> Patch to Tomcat's build.xml ANT script to add JCC's classes (like
>>>>>> PythonVM)
>>>>>> to
>>>>>> the build classpath.
>>>>>>
>>>>>> --- apache-tomcat-6.0.29-src/build.xml  2010-07-19 06:02:31.000000000
>>>>>> -0700
>>>>>> +++ apache-tomcat-6.0.29-src/build.xml.patched  2010-08-04
>>>>>> 09:30:24.000000000 -0700
>>>>>> @@ -95,16 +95,17 @@
>>>>>>   <property name="jasper-jdt.jar"
>>>>>> value="${jasper-jdt.home}/jasper-jdt.jar"/>
>>>>>>   <available property="tomcat-dbcp.present" file="${tomcat-dbcp.jar}"
>>>>>> />
>>>>>>   <available property="jdk16.present"
>>>>>> classname="javax.sql.StatementEvent"
>>>>>> />
>>>>>>
>>>>>>   <!-- Classpath -->
>>>>>>   <path id="tomcat.classpath">
>>>>>>     <pathelement location="${ant.jar}"/>
>>>>>>     <pathelement location="${jdt.jar}"/>
>>>>>> +    <pathelement location="${jcc.egg}/jcc/classes"/>
>>>>>>   </path>
>>>>>>
>>>>>>   <!-- Version info filter set -->
>>>>>>   <tstamp>
>>>>>>     <format property="TODAY" pattern="MMM d yyyy" locale="en"/>
>>>>>>     <format property="TSTAMP" pattern="hh:mm:ss"/>
>>>>>>   </tstamp>
>>>>>>   <filterset id="version.filters">
>>>>>> @@ -148,16 +149,25 @@
>>>>>>            excludes="**/CVS/**,**/.svn/**"
>>>>>>            encoding="ISO-8859-1">
>>>>>>  <!-- Comment this in to show unchecked warnings:
>>>>>>       <compilerarg value="-Xlint:unchecked"/>
>>>>>>  -->
>>>>>>       <classpath refid="tomcat.classpath" />
>>>>>>       <exclude name="org/apache/naming/factory/webservices/**" />
>>>>>>     </javac>
>>>>>> +    <javac srcdir="${extras.path}" destdir="${tomcat.classes}"
>>>>>> +           debug="${compile.debug}"
>>>>>> +           deprecation="${compile.deprecation}"
>>>>>> +           source="${compile.source}"
>>>>>> +           optimize="${compile.optimize}"
>>>>>> +           excludes="**/CVS/**,**/.svn/**">
>>>>>> +<!-- Comment this in to show unchecked warnings:     <compilerarg
>>>>>> value="-Xlint:unchecked"/> -->
>>>>>> +      <classpath refid="tomcat.classpath" />
>>>>>> +    </javac>
>>>>>>     <!-- Copy static resource files -->
>>>>>>     <copy todir="${tomcat.classes}" encoding="ISO-8859-1">
>>>>>>       <filterset refid="version.filters"/>
>>>>>>       <fileset dir="java">
>>>>>>         <include name="**/*.properties"/>
>>>>>>         <include name="**/*.dtd"/>
>>>>>>         <include name="**/*.tasks"/>
>>>>>>         <include name="**/*.xsd"/>
>>>>>>
>>>>>> -----------------------------------------------
>>>>>> Patch to catalina.sh, the Tomcat startup script to add JCC to LIBPATH
>>>>>> and
>>>>>> CLASSPATH
>>>>>>
>>>>>> --- apache-tomcat-6.0.29-src/output/build/bin/catalina.sh
>>>>>> 2010-08-04
>>>>>> 09:57:27.000000000 -0700
>>>>>> +++ apache-tomcat-6.0.29-src/output/build/bin/catalina.sh.patched
>>>>>> 2010-08-04 09:57:47.000000000 -0700
>>>>>> @@ -162,16 +162,30 @@
>>>>>>     exit 1
>>>>>>   fi
>>>>>>  fi
>>>>>>
>>>>>>  if [ -z "$CATALINA_BASE" ] ; then
>>>>>>   CATALINA_BASE="$CATALINA_HOME"
>>>>>>  fi
>>>>>>
>>>>>> +if [ -n "$JCC_EGG" ]; then
>>>>>> +  CLASSPATH="$CLASSPATH":"$JCC_EGG"/jcc/classes
>>>>>> +  JAVA_LIB_PATH=$JCC_EGG
>>>>>> +fi
>>>>>> +if [ -n "$TOMCAT_APR_LIB_PATH" ]; then
>>>>>> +  JAVA_LIB_PATH=$JAVA_LIB_PATH:$TOMCAT_APR_LIB_PATH
>>>>>> +fi
>>>>>> +if [ -n "$JAVA_LIB_PATH" ]; then
>>>>>> +  JAVA_OPTS="$JAVA_OPTS -Djava.library.path=$JAVA_LIB_PATH"
>>>>>> +fi
>>>>>> +if [ -n "EXTRA_CLASSPATH" ]; then
>>>>>> +  CLASSPATH="$CLASSPATH":"$EXTRA_CLASSPATH"
>>>>>> +fi
>>>>>> +
>>>>>>  # Add tomcat-juli.jar and bootstrap.jar to classpath
>>>>>>  # tomcat-juli.jar can be over-ridden per instance
>>>>>>  if [ ! -z "$CLASSPATH" ] ; then
>>>>>>   CLASSPATH="$CLASSPATH":
>>>>>>  fi
>>>>>>  if [ "$CATALINA_BASE" != "$CATALINA_HOME" ] && [ -r
>>>>>> "$CATALINA_BASE/bin/tomcat-juli.jar" ] ; then
>>>>>>
>>>>>>
>>>>>>
>>>>>> CLASSPATH="$CLASSPATH""$CATALINA_BASE"/bin/tomcat-juli.jar:"$CATALINA_HOME"/bin/bootstrap.jar
>>>>>>  else
>>>>>>
>>>>>> These EGG paths are long, complicated and OS-specific, the trick below
>>>>>> generates them programmatically (from inside a Makefile):
>>>>>>
>>>>>> JCC_EGG:=$(shell $(PYTHON) -c "import os, jcc; print
>>>>>> os.path.dirname(os.path.dirname(jcc.__file__))")
>>>>>> JEMQL_EGG:=$(shell $(PYTHON) -c "import os, jemql; print
>>>>>> os.path.dirname(os.path.dirname(jemql.__file__))")
>>>>>>
>>>>>> Then, the CLASSPATH addition during _build_ time:
>>>>>>  CLASSPATH = $(CLASSPATH):$(JEMQL_EGG)/jemql/jemql.jar
>>>>>> and so on...
>>>>>> At runtime, JCC takes care of adding your eggs to the startup
>>>>>> CLASSPATH.
>>>>>>
>>>>>> ----------------------------------------------
>>>>>> Last but not least, if you use Python's thread local storage in your
>>>>>> threads, Python threads when embedded inside a JVM are 'dummy', that
>>>>>> is,
>>>>>> while they're
>>>>>> backed by the actual Java thread (a pthread), the Python VM is not
>>>>>> managing
>>>>>> them and a thread state object is created each and every time a Python
>>>>>> thread
>>>>>> is entered and released when exited back to the JVM. This has two
>>>>>> problems:
>>>>>>  1. it's a bit wasteful
>>>>>>  2. python thread local storage gets lost
>>>>>>
>>>>>> The Java class below works this around by incrementing the refcount
>>>>>> that
>>>>>> controls this:
>>>>>>
>>>>>> package org.apache.catalina.core;
>>>>>>
>>>>>> import org.apache.jcc.PythonVM;
>>>>>>
>>>>>> public class TerminatingThread extends Thread {
>>>>>>    protected Runnable runnable;
>>>>>>
>>>>>>    public TerminatingThread(ThreadGroup group, Runnable runnable,
>>>>>> String
>>>>>> name)
>>>>>>    {
>>>>>>        super(group, name);
>>>>>>        this.runnable = runnable;
>>>>>>    }
>>>>>>
>>>>>>    public void run()
>>>>>>    {
>>>>>>        PythonVM vm = PythonVM.get();
>>>>>>
>>>>>>        try {
>>>>>>            vm.acquireThreadState();
>>>>>>            runnable.run();
>>>>>>        } finally {
>>>>>>            vm.releaseThreadState();
>>>>>>        }
>>>>>>    }
>>>>>> }
>>>>>>
>>>>>> Then, there is some trickery to get Tomcat to use this class for its
>>>>>> threads
>>>>>> instead of the default one:
>>>>>>
>>>>>> ---
>>>>>>
>>>>>>
>>>>>> apache-tomcat-6.0.29-src/java/org/apache/catalina/core/StandardThreadExecutor.java
>>>>>>  2010-07-19 06:02:32.000000000 -0700
>>>>>> +++
>>>>>>
>>>>>>
>>>>>> apache-tomcat-6.0.29-src/java/org/apache/catalina/core/StandardThreadExecutor.java.patched
>>>>>>  2010-08-04 08:56:02.000000000 -0700
>>>>>> @@ -44,17 +44,17 @@
>>>>>>     protected int minSpareThreads = 25;
>>>>>>
>>>>>>     protected int maxIdleTime = 60000;
>>>>>>
>>>>>>     protected ThreadPoolExecutor executor = null;
>>>>>>
>>>>>>     protected String name;
>>>>>>
>>>>>> -    private LifecycleSupport lifecycle = new LifecycleSupport(this);
>>>>>> +    protected LifecycleSupport lifecycle = new
>>>>>> LifecycleSupport(this);
>>>>>>     // ---------------------------------------------- Constructors
>>>>>>     public StandardThreadExecutor() {
>>>>>>         //empty constructor for the digester
>>>>>>     }
>>>>>>
>>>>>>
>>>>>>
>>>>>>     // ---------------------------------------------- Public Methods
>>>>>>
>>>>>>
>>>>>> In Tomcat's server.xml, use this executor (and code below for it)
>>>>>>    <Executor name="relThreadPool"
>>>>>>
>>>>>>  className="org.apache.catalina.core.TerminatingThreadExecutor"
>>>>>>              namePrefix="rel-exec-"
>>>>>>              maxIdleTime="3600000"
>>>>>>              minSpareThreads="2"
>>>>>>              maxThreads="2" />
>>>>>>
>>>>>>
>>>>>> package org.apache.catalina.core;
>>>>>>
>>>>>> import java.util.concurrent.ThreadPoolExecutor;
>>>>>> import java.util.concurrent.TimeUnit;
>>>>>> import org.apache.catalina.LifecycleException;
>>>>>>
>>>>>>
>>>>>> public class TerminatingThreadExecutor extends StandardThreadExecutor
>>>>>> {
>>>>>>
>>>>>>    public void start()
>>>>>>        throws LifecycleException
>>>>>>    {
>>>>>>        lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
>>>>>>
>>>>>>        TaskQueue taskqueue = new TaskQueue();
>>>>>>        TaskThreadFactory tf = new
>>>>>> TerminatingTaskThreadFactory(namePrefix);
>>>>>>
>>>>>>        lifecycle.fireLifecycleEvent(START_EVENT, null);
>>>>>>        executor = new ThreadPoolExecutor(getMinSpareThreads(),
>>>>>> getMaxThreads(),
>>>>>>                                          maxIdleTime,
>>>>>> TimeUnit.MILLISECONDS,
>>>>>>                                          taskqueue, tf);
>>>>>>        taskqueue.setParent(executor);
>>>>>>        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
>>>>>>    }
>>>>>>
>>>>>>    protected class TerminatingTaskThreadFactory
>>>>>>        extends StandardThreadExecutor.TaskThreadFactory {
>>>>>>
>>>>>>        protected TerminatingTaskThreadFactory(String namePrefix)
>>>>>>        {
>>>>>>            super(namePrefix);
>>>>>>        }
>>>>>>
>>>>>>        public Thread newThread(Runnable runnable)
>>>>>>        {
>>>>>>            Thread t = new TerminatingThread(group, runnable,
>>>>>> namePrefix +
>>>>>> threadNumber.getAndIncrement());
>>>>>>
>>>>>>            t.setDaemon(daemon);
>>>>>>            t.setPriority(getThreadPriority());
>>>>>>
>>>>>>            return t;
>>>>>>        }
>>>>>>    }
>>>>>> }
>>>>>>
>>>>
>>>
>

Reply via email to