├── .coveragerc ├── .github └── workflows │ └── python-publish.yml ├── .gitignore ├── .travis.yml ├── LICENSE ├── MANIFEST.in ├── README.rst ├── _javabridge.pyx ├── _javabridge_mac.pxd ├── _javabridge_mac.pyx ├── _javabridge_nomac.pxd ├── _javabridge_nomac.pyx ├── _javabridge_osspecific.pxd ├── demo ├── demo_awtonly.py ├── demo_nogui.py ├── demo_nogui_with_stmt.py ├── demo_uicallback.py ├── demo_uicallback_noqueue.py └── demo_wxandawt.py ├── docs ├── Makefile ├── conf.py ├── developers.rst ├── hello.rst ├── highlevel.rst ├── index.rst ├── installation.rst ├── java2python.rst ├── javascript.rst ├── lowlevel.rst ├── make.bat ├── start_kill.rst └── unittesting.rst ├── java ├── org │ └── cellprofiler │ │ ├── findlibjvm.java │ │ ├── javabridge │ │ ├── CPython.java │ │ ├── CPythonInvocationHandler.java │ │ └── test │ │ │ ├── RealRect.java │ │ │ └── TestCPython.java │ │ └── runnablequeue │ │ ├── RunnableQueue.java │ │ └── TestRunnableQueue.java ├── org_cellprofiler_javabridge_CPython.c └── org_cellprofiler_javabridge_CPython.h ├── javabridge ├── __init__.py ├── jars │ └── rhino-1.7R4.jar ├── jutil.py ├── locate.py ├── noseplugin.py ├── tests │ ├── __init__.py │ ├── test_cpython.py │ ├── test_javabridge.py │ ├── test_jutil.py │ └── test_wrappers.py └── wrappers.py ├── jenkins ├── build.sh ├── docker │ ├── centos_javabridge │ │ └── Dockerfile │ ├── centos_javabridge_build │ │ ├── Dockerfile │ │ └── get-pip.py │ ├── ensure_image.sh │ ├── ubuntu_javabridge │ │ └── Dockerfile │ └── ubuntu_javabridge_build │ │ └── Dockerfile └── test.sh ├── jvm.def ├── mac_javabridge_utils.c ├── mac_javabridge_utils.h ├── requirements.txt ├── setup.cfg ├── setup.py └── strtoull.c /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | branch = True 3 | [report] 4 | exclude_lines = 5 | # Ignore continue statement in code as it can't be detected as covered 6 | # due to an optimization by the Python interpreter. See coverage issue 7 | # ( https://bitbucket.org/ned/coveragepy/issue/198/continue-marked-as-not-covered ) 8 | # and Python issue ( http://bugs.python.org/issue2506 ). 9 | continue 10 | 11 | # Ignore coverage of code that requires the module to be executed. 12 | if __name__ == .__main__.: 13 | omit = 14 | */python?.?/* 15 | */site-packages/* 16 | *tests/* 17 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflows will upload a Python Package using Twine when a release is created 2 | # For more information see: https://help.github.com/en/actions/language-and-framework-guides/using-python-with-github-actions#publishing-to-package-registries 3 | 4 | name: Upload Python Package 5 | 6 | on: 7 | release: 8 | types: [created] 9 | 10 | jobs: 11 | deploy: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: actions/checkout@v2 17 | - name: Set up Python 18 | uses: actions/setup-python@v2 19 | with: 20 | python-version: '3.x' 21 | - name: Install dependencies 22 | run: | 23 | python -m pip install --upgrade pip 24 | pip install setuptools wheel twine 25 | - name: Build and publish 26 | env: 27 | TWINE_USERNAME: ${{ secrets.PYPI_USERNAME }} 28 | TWINE_PASSWORD: ${{ secrets.PYPI_PASSWORD }} 29 | run: | 30 | python -m build 31 | pip install dist/*.whl 32 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /_javabridge.c 3 | /_javabridge_mac.c 4 | /_javabridge_nomac.c 5 | *.pyc 6 | *.pyd 7 | /javabridge/jars/*java2cpython.* 8 | /javabridge/*.so 9 | /python_javabridge.egg-info 10 | /docs/_build 11 | *.class 12 | /javabridge/jars/cpython.jar 13 | /javabridge/jars/findlibjvm.jar 14 | /javabridge/jars/runnablequeue.jar 15 | /javabridge/jars/test.jar 16 | /dist 17 | /docs/build 18 | /javabridge.egg-info 19 | /javabridge/_version.py 20 | .coverage -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | env: 3 | - PYTHON_VERSION="3.6" 4 | jdk: 5 | - oraclejdk9 6 | - oraclejdk11 7 | - openjdk8 8 | - openjdk11 9 | before_install: 10 | # Get the tag if it wasn't provided. Travis doesn't provide this if it isn't a tagged build. 11 | - if [ -z $TRAVIS_TAG ]; then TRAVIS_TAG=`git tag --contains` ; fi 12 | - echo $TRAVIS_TAG 13 | # Move out of git directory to build root. 14 | - cd ../.. 15 | - pwd 16 | install: 17 | # Download and configure conda. 18 | - wget http://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh 19 | - bash miniconda.sh -b -p $HOME/miniconda 20 | - export PATH="$HOME/miniconda/bin:$PATH" 21 | - conda config --set always_yes yes 22 | - conda config --set show_channel_urls True 23 | - source activate root 24 | # Install basic conda dependencies. 25 | - touch $HOME/miniconda/conda-meta/pinned 26 | - echo "conda-build ==1.16.0" >> $HOME/miniconda/conda-meta/pinned 27 | - conda update --all 28 | - conda install conda-build 29 | # Setup environment for testing and install all dependencies and our package. 30 | - cd $TRAVIS_REPO_SLUG 31 | - conda create --use-local -n testenv python=$PYTHON_VERSION 32 | - source activate testenv 33 | - python setup.py develop 34 | # Install sphinx and friends to build documentation. 35 | # (LEEK) travis install of sphinx on Python 3.5 crashed 36 | - pip install sphinx==1.7.2 37 | # Install coverage and coveralls to generate and submit test coverage results for coveralls.io. 38 | - echo "coverage 3.*" >> $HOME/miniconda/envs/testenv/conda-meta/pinned 39 | - conda install nose 40 | - conda install coverage 41 | - pip install coveralls 42 | # Clean up downloads as there are quite a few and they waste space/memory. 43 | - conda clean -tipsy 44 | - rm -rfv $HOME/.cache/pip 45 | script: 46 | # Run tests. 47 | - python setup.py nosetests 48 | # Build docs. 49 | - cd docs 50 | - make html 51 | - cd .. 52 | after_success: 53 | # Submit results to coveralls.io. 54 | - coveralls 55 | # Use container format for TravisCI for quicker startup and builds. 56 | sudo: false 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 2 | Copyright (c) 2009-2013 Broad Institute 3 | All rights reserved. 4 | 5 | Redistribution and use in source and binary forms, with or without 6 | modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright 9 | notice, this list of conditions and the following disclaimer. 10 | 11 | * Redistributions in binary form must reproduce the above 12 | copyright notice, this list of conditions and the following 13 | disclaimer in the documentation and/or other materials provided 14 | with the distribution. 15 | 16 | * Neither the name of the Massachusetts Institute of Technology 17 | nor the Broad Institute nor the names of its contributors may be 18 | used to endorse or promote products derived from this software 19 | without specific prior written permission. 20 | 21 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MASSACHUSETTS 25 | INSTITUTE OF TECHNOLOGY OR THE BROAD INSTITUTE BE LIABLE FOR ANY 26 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 28 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 30 | IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 31 | OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 32 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include java *.java 2 | include mac_javabridge_utils.c 3 | include mac_javabridge_utils.h 4 | include strtoull.c 5 | include _javabridge.c 6 | include _javabridge_mac.c 7 | include _javabridge_nomac.c 8 | include java/org_cellprofiler_javabridge_CPython.c 9 | include java/org_cellprofiler_javabridge_CPython.h 10 | recursive-include javabridge/tests *.py 11 | recursive-include javabridge/jars *.jar 12 | prune *.pyx 13 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | |Travis CI Status| 2 | 3 | ----------------------------------------------------------------------------------------------------- 4 | 5 | The javabridge Python package makes it easy to start a Java virtual 6 | machine (JVM) from Python and interact with it. Python code can 7 | interact with the JVM using a low-level API or a more convenient 8 | high-level API. 9 | 10 | PyPI record: https://pypi.python.org/pypi/javabridge 11 | 12 | Documentation: http://pythonhosted.org/javabridge/ 13 | 14 | GitHub repository: https://github.com/CellProfiler/python-javabridge 15 | 16 | Report bugs here: https://github.com/CellProfiler/python-javabridge/issues 17 | 18 | python-javabridge is licensed under the BSD license. See the 19 | accompanying file LICENSE for details. 20 | 21 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 22 | Copyright (c) 2009-2013 Broad Institute 23 | All rights reserved. 24 | 25 | 26 | .. |Travis CI Status| image:: https://travis-ci.org/LeeKamentsky/python-javabridge.svg?branch=master 27 | :target: https://travis-ci.org/LeeKamentsky/python-javabridge 28 | -------------------------------------------------------------------------------- /_javabridge_mac.pxd: -------------------------------------------------------------------------------- 1 | 2 | cdef extern from "jni.h": 3 | ctypedef long jint 4 | ctypedef unsigned char jboolean 5 | 6 | ctypedef struct JNIInvokeInterface_ 7 | 8 | ctypedef JNIInvokeInterface_ *JavaVM 9 | 10 | 11 | cdef extern void StopVM(JavaVM *vm) 12 | cdef extern int CreateJavaVM(JavaVM **pvm, void **pEnv, void *args) -------------------------------------------------------------------------------- /_javabridge_mac.pyx: -------------------------------------------------------------------------------- 1 | cimport _javabridge_osspecific 2 | 3 | cdef extern from "jni.h": 4 | ctypedef long jint 5 | ctypedef unsigned char jboolean 6 | 7 | ctypedef struct JNIInvokeInterface_ 8 | 9 | ctypedef JNIInvokeInterface_ *JavaVM 10 | 11 | struct JavaVMOption: 12 | char *optionString 13 | void *extraInfo 14 | ctypedef JavaVMOption JavaVMOption 15 | 16 | struct JavaVMInitArgs: 17 | jint version 18 | jint nOptions 19 | JavaVMOption *options 20 | jboolean ignoreUnrecognized 21 | ctypedef JavaVMInitArgs JavaVMInitArgs 22 | 23 | 24 | cdef extern from "mac_javabridge_utils.h": 25 | int MacStartVM(JavaVM **, JavaVMInitArgs *pVMArgs, char *class_name, char *path_to_libjvm) nogil 26 | void MacStopVM() nogil 27 | void MacRunLoopInit() nogil 28 | void MacRunLoopRun() nogil 29 | void MacRunLoopStop() nogil 30 | void MacRunLoopReset() nogil 31 | int MacIsMainThread() nogil 32 | void MacRunLoopRunInMode(double) nogil 33 | 34 | cdef void StopVM(JavaVM *vm) noexcept: 35 | MacStopVM() 36 | 37 | # 38 | # Unused stub in Mac 39 | # 40 | cdef int CreateJavaVM(JavaVM **pvm, void **pEnv, void *args) noexcept: 41 | return -1 42 | -------------------------------------------------------------------------------- /_javabridge_nomac.pxd: -------------------------------------------------------------------------------- 1 | 2 | cdef extern from "jni.h": 3 | ctypedef long jint 4 | ctypedef unsigned char jboolean 5 | 6 | ctypedef struct JNIInvokeInterface_ 7 | 8 | ctypedef JNIInvokeInterface_ *JavaVM 9 | 10 | struct JavaVMInitArgs: 11 | jint version 12 | jint nOptions 13 | JavaVMOption *options 14 | jboolean ignoreUnrecognized 15 | ctypedef JavaVMInitArgs JavaVMInitArgs 16 | 17 | struct JavaVMOption: 18 | char *optionString 19 | void *extraInfo 20 | ctypedef JavaVMOption JavaVMOption 21 | 22 | cdef extern int MacStartVM(JavaVM **pvm, JavaVMInitArgs *pVMArgs, char *class_name) nogil 23 | 24 | cdef extern void StopVM(JavaVM *vm) nogil 25 | 26 | cdef extern int CreateJavaVM(JavaVM **pvm, void **pEnv, void *args) nogil 27 | 28 | cdef extern void MacRunLoopInit() nogil 29 | 30 | cdef extern void MacRunLoopRun() nogil 31 | 32 | cdef extern void MacRunLoopStop() nogil 33 | 34 | cdef extern void MacRunLoopReset() nogil 35 | 36 | cdef extern int MacIsMainThread() nogil 37 | 38 | cdef extern void MacRunLoopRunInMode(double timeout) nogil -------------------------------------------------------------------------------- /_javabridge_nomac.pyx: -------------------------------------------------------------------------------- 1 | import _javabridge_osspecific 2 | 3 | cdef extern from "jni.h": 4 | ctypedef long jint 5 | ctypedef unsigned char jboolean 6 | 7 | ctypedef struct JNIInvokeInterface_ 8 | 9 | ctypedef JNIInvokeInterface_ *JavaVM 10 | 11 | ctypedef struct JNIInvokeInterface_: 12 | jint (*DestroyJavaVM)(JavaVM *vm) noexcept nogil 13 | jint (*AttachCurrentThread)(JavaVM *vm, void **penv, void *args) noexcept nogil 14 | jint (*DetachCurrentThread)(JavaVM *vm) noexcept nogil 15 | jint (*GetEnv)(JavaVM *vm, void **penv, jint version) noexcept nogil 16 | jint (*AttachCurrentThreadAsDaemon)(JavaVM *vm, void *penv, void *args) noexcept nogil 17 | jint JNI_CreateJavaVM(JavaVM **pvm, void **penv, void *args) noexcept nogil 18 | 19 | cdef int MacStartVM(JavaVM **pvm, JavaVMInitArgs *pVMArgs, char *class_name) noexcept nogil: 20 | return -1 21 | 22 | cdef void StopVM(JavaVM *vm) noexcept nogil: 23 | vm[0].DestroyJavaVM(vm) 24 | 25 | cdef void MacRunLoopInit() noexcept nogil: 26 | pass 27 | 28 | cdef void MacRunLoopRun() noexcept nogil: 29 | pass 30 | 31 | cdef void MacRunLoopStop() noexcept nogil: 32 | pass 33 | 34 | cdef void MacRunLoopReset() noexcept nogil: 35 | pass 36 | 37 | cdef int MacIsMainThread() noexcept nogil: 38 | return 0 39 | 40 | cdef void MacRunLoopRunInMode(double timeout) noexcept nogil: 41 | pass 42 | 43 | cdef int CreateJavaVM(JavaVM **pvm, void **pEnv, void *args) noexcept nogil: 44 | return JNI_CreateJavaVM(pvm, pEnv, args) 45 | 46 | -------------------------------------------------------------------------------- /_javabridge_osspecific.pxd: -------------------------------------------------------------------------------- 1 | cdef extern from "jni.h": 2 | ctypedef long jint 3 | ctypedef unsigned char jboolean 4 | 5 | ctypedef struct JNIInvokeInterface_ 6 | 7 | ctypedef JNIInvokeInterface_ *JavaVM 8 | 9 | struct JavaVMOption: 10 | char *optionString 11 | void *extraInfo 12 | ctypedef JavaVMOption JavaVMOption 13 | 14 | struct JavaVMInitArgs: 15 | jint version 16 | jint nOptions 17 | JavaVMOption *options 18 | jboolean ignoreUnrecognized 19 | ctypedef JavaVMInitArgs JavaVMInitArgs 20 | 21 | 22 | cdef extern from "mac_javabridge_utils.h": 23 | int MacStartVM(JavaVM **, JavaVMInitArgs *pVMArgs, char *class_name) nogil 24 | void MacStopVM() nogil 25 | void MacRunLoopInit() nogil 26 | void MacRunLoopRun() nogil 27 | void MacRunLoopStop() nogil 28 | void MacRunLoopReset() nogil 29 | int MacIsMainThread() nogil 30 | void MacRunLoopRunInMode(double) nogil 31 | 32 | cdef extern void StopVM(JavaVM *vm) 33 | cdef extern int CreateJavaVM(JavaVM **pvm, void **pEnv, void *args) 34 | -------------------------------------------------------------------------------- /demo/demo_awtonly.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """demo_awtonly.py - show how to start the Javabridge with only a Java GUI 4 | 5 | python-javabridge is licensed under the BSD license. See the 6 | accompanying file LICENSE for details. 7 | 8 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 9 | Copyright (c) 2009-2013 Broad Institute 10 | All rights reserved. 11 | 12 | """ 13 | 14 | import os 15 | import wx 16 | import javabridge 17 | 18 | javabridge.start_vm() 19 | 20 | class EmptyApp(wx.App): 21 | def OnInit(self): 22 | javabridge.activate_awt() 23 | return True 24 | 25 | try: 26 | 27 | app = EmptyApp(False) 28 | 29 | # Must exist (perhaps the app needs to have a top-level window?), but 30 | # does not have to be shown. 31 | frame = wx.Frame(None) 32 | 33 | javabridge.execute_runnable_in_main_thread(javabridge.run_script(""" 34 | new java.lang.Runnable() { 35 | run: function() { 36 | with(JavaImporter(java.awt.Frame)) Frame().setVisible(true); 37 | } 38 | };""")) 39 | 40 | app.MainLoop() 41 | 42 | finally: 43 | 44 | javabridge.kill_vm() 45 | -------------------------------------------------------------------------------- /demo/demo_nogui.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """demo_nogui.py - show how to start the Javabridge without a GUI 4 | 5 | python-javabridge is licensed under the BSD license. See the 6 | accompanying file LICENSE for details. 7 | 8 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 9 | Copyright (c) 2009-2013 Broad Institute 10 | All rights reserved. 11 | 12 | """ 13 | 14 | from __future__ import print_function 15 | import os 16 | import javabridge 17 | 18 | javabridge.start_vm(run_headless=True) 19 | try: 20 | print(javabridge.run_script('java.lang.String.format("Hello, %s!", greetee);', 21 | dict(greetee='world'))) 22 | finally: 23 | javabridge.kill_vm() 24 | -------------------------------------------------------------------------------- /demo/demo_nogui_with_stmt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """demo_nogui.py - show how to start the Javabridge without a GUI 4 | 5 | python-javabridge is licensed under the BSD license. See the 6 | accompanying file LICENSE for details. 7 | 8 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 9 | Copyright (c) 2009-2013 Broad Institute 10 | All rights reserved. 11 | 12 | """ 13 | 14 | import os 15 | import javabridge 16 | 17 | with javabridge.vm(run_headless=True): 18 | print(javabridge.run_script('java.lang.String.format("Hello, %s!", greetee);', 19 | dict(greetee='world'))) 20 | -------------------------------------------------------------------------------- /demo/demo_uicallback.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """demo_uicallback.py - An application that executes Python code from a Java UI 4 | 5 | It would be handy to have a Java class that called Python through the Javabridge, 6 | perhaps something like:: 7 | 8 | public class PythonEnv { 9 | public native void exec(String script); 10 | public native String eval(String script); 11 | }; 12 | 13 | but there are myriad difficulties - a Python stack uses Javabridge to 14 | create a Java stack which then uses JNI to execute Python on... what stack? 15 | 16 | The easiest strategy is to use a Python thread dedicated to executing or 17 | evaluating scripts sent from Java, using that thread's local context to 18 | hold variables. The Python thread communicates with Java in this example using 19 | two SynchronousQueue objects, one to transmit messages from Java to Python 20 | and another to go in the reverse direction. This example shows how a Java UI 21 | can use ActionListener anonymous classes to talk through the queues to Python. 22 | 23 | python-javabridge is licensed under the BSD license. See the 24 | accompanying file LICENSE for details. 25 | 26 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 27 | Copyright (c) 2009-2013 Broad Institute 28 | All rights reserved. 29 | 30 | """ 31 | import javabridge 32 | import sys 33 | import traceback 34 | 35 | def main(args): 36 | javabridge.activate_awt() 37 | script = """ 38 | //-------------------------------------- 39 | // 40 | // The anonymous callable runs on the thread 41 | // that started Java - that's the rule with AWT. 42 | // 43 | // The callable returns a Java Map whose keys 44 | // have the labels of objects like "qUp" for 45 | // the upward queue. Python can then fetch 46 | // whichever ones it wants and do Java stuff 47 | // with them. 48 | // 49 | //-------------------------------------- 50 | new java.util.concurrent.Callable() { 51 | call: function() { 52 | importClass(javax.swing.SpringLayout); 53 | importClass(javax.swing.JFrame); 54 | importClass(javax.swing.JTextField); 55 | importClass(javax.swing.JButton); 56 | importClass(javax.swing.JScrollPane); 57 | importClass(javax.swing.JTextArea); 58 | importClass(java.util.Hashtable); 59 | importClass(java.awt.event.ActionListener); 60 | importClass(java.awt.event.WindowAdapter); 61 | importClass(java.util.concurrent.SynchronousQueue); 62 | 63 | d = new Hashtable(); 64 | frame = new JFrame("Callbacks in Java"); 65 | d.put("frame", frame); 66 | contentPane = frame.getContentPane(); 67 | layout = new SpringLayout(); 68 | contentPane.setLayout(layout); 69 | 70 | textField = new JTextField("'Hello, world.'", 60); 71 | d.put("textField", textField); 72 | contentPane.add(textField); 73 | 74 | execButton = new JButton("Exec"); 75 | contentPane.add(execButton); 76 | 77 | evalButton = new JButton("Eval"); 78 | contentPane.add(evalButton); 79 | 80 | result = new JTextArea("None"); 81 | scrollPane = new JScrollPane(result) 82 | contentPane.add(scrollPane); 83 | d.put("result", result); 84 | 85 | //----------------------------------------------------- 86 | // 87 | // The layout is: 88 | // 89 | // [ textField] [execButton] [evalButton] 90 | // [ scrollPane ] 91 | // 92 | //----------------------------------------------------- 93 | 94 | layout.putConstraint(SpringLayout.WEST, textField, 95 | 5, SpringLayout.WEST, contentPane); 96 | layout.putConstraint(SpringLayout.NORTH, textField, 97 | 5, SpringLayout.NORTH, contentPane); 98 | 99 | layout.putConstraint(SpringLayout.WEST, execButton, 100 | 5, SpringLayout.EAST, textField); 101 | layout.putConstraint(SpringLayout.NORTH, execButton, 102 | 0, SpringLayout.NORTH, textField); 103 | 104 | layout.putConstraint(SpringLayout.WEST, evalButton, 105 | 5, SpringLayout.EAST, execButton); 106 | layout.putConstraint(SpringLayout.NORTH, evalButton, 107 | 0, SpringLayout.NORTH, textField); 108 | 109 | layout.putConstraint(SpringLayout.NORTH, scrollPane, 110 | 5, SpringLayout.SOUTH, textField); 111 | layout.putConstraint(SpringLayout.WEST, scrollPane, 112 | 0, SpringLayout.WEST, textField); 113 | layout.putConstraint(SpringLayout.EAST, scrollPane, 114 | 0, SpringLayout.EAST, evalButton); 115 | 116 | layout.putConstraint(SpringLayout.EAST, contentPane, 117 | 5, SpringLayout.EAST, evalButton); 118 | layout.putConstraint(SpringLayout.SOUTH, contentPane, 119 | 20, SpringLayout.SOUTH, scrollPane); 120 | 121 | //------------------------------------------------ 122 | // 123 | // qUp sends messages from Java to Python 124 | // qDown sends messages from Python to Java 125 | // 126 | // The communications protocol is that qUp sends 127 | // a command. For Exec and Eval commands, qUp sends 128 | // text and qDown must send a reply to continue. 129 | // For the Exit command, qUp sends the command and 130 | // Python must dispose of Java 131 | // 132 | //------------------------------------------------- 133 | 134 | qUp = new SynchronousQueue(); 135 | qDown = new SynchronousQueue(); 136 | d.put("qUp", qUp); 137 | d.put("qDown", qDown); 138 | 139 | //----------------------------------------------- 140 | // 141 | // Create an action listener that binds the execButton 142 | // action to a function that instructs Python to 143 | // execute the contents of the text field. 144 | // 145 | //----------------------------------------------- 146 | alExec = new ActionListener() { 147 | actionPerformed: function(e) { 148 | qUp.put("Exec"); 149 | qUp.put(textField.getText()); 150 | result.setText(qDown.take()); 151 | } 152 | }; 153 | execButton.addActionListener(alExec); 154 | 155 | //----------------------------------------------- 156 | // 157 | // Create an action listener that binds the evalButton 158 | // action to a function that instructs Python to 159 | // evaluate the contents of the text field. 160 | // 161 | //----------------------------------------------- 162 | alEval = new ActionListener() { 163 | actionPerformed: function(e) { 164 | qUp.put("Eval"); 165 | qUp.put(textField.getText()); 166 | result.setText(qDown.take()); 167 | } 168 | }; 169 | evalButton.addActionListener(alEval); 170 | 171 | //----------------------------------------------- 172 | // 173 | // Create a window listener that binds the frame's 174 | // windowClosing action to a function that instructs 175 | // Python to exit. 176 | // 177 | //----------------------------------------------- 178 | wl = new WindowAdapter() { 179 | windowClosing: function(e) { 180 | qUp.put("Exit"); 181 | } 182 | }; 183 | 184 | frame.addWindowListener(wl); 185 | 186 | frame.pack(); 187 | frame.setVisible(true); 188 | return d; 189 | } 190 | };""" 191 | c = javabridge.run_script(script); 192 | f = javabridge.make_future_task(c) 193 | d = javabridge.execute_future_in_main_thread(f); 194 | d = javabridge.get_map_wrapper(d) 195 | qUp = d["qUp"] 196 | qDown = d["qDown"] 197 | frame = d["frame"] 198 | while True: 199 | cmd = javabridge.run_script("qUp.take();", dict(qUp=qUp)) 200 | if cmd == "Exit": 201 | break 202 | text = javabridge.run_script("qUp.take();", dict(qUp=qUp)) 203 | if cmd == "Eval": 204 | try: 205 | result = eval(text, globals(), locals()) 206 | except Exception as e: 207 | result = "%s\n%s" % (str(e), traceback.format_exc()) 208 | except: 209 | result = "What happened?" 210 | else: 211 | try: 212 | exec(text, globals(), locals()) 213 | result = "Operation succeeded" 214 | except Exception as e: 215 | result = "%s\n%s" % (str(e), traceback.format_exc()) 216 | except: 217 | result = "What happened?" 218 | 219 | javabridge.run_script("qDown.put(result);", 220 | dict(qDown=qDown, result = str(result))) 221 | javabridge.run_script("frame.dispose();", dict(frame=frame)) 222 | 223 | if __name__=="__main__": 224 | javabridge.start_vm() 225 | if sys.platform == 'darwin': 226 | # 227 | # For Mac, we need to start an event loop 228 | # on the main thread and run the UI code 229 | # on a worker thread. 230 | # 231 | import threading 232 | javabridge.mac_run_loop_init() 233 | class Runme(threading.Thread): 234 | def run(self): 235 | javabridge.attach() 236 | try: 237 | main(sys.argv) 238 | finally: 239 | javabridge.detach() 240 | t = Runme() 241 | t.start() 242 | javabridge.mac_enter_run_loop() 243 | else: 244 | # 245 | # For everyone else, the event loop 246 | # is run by Java and we do everything 247 | # on the main thread. 248 | # 249 | main(sys.argv) 250 | javabridge.deactivate_awt() 251 | javabridge.kill_vm() 252 | -------------------------------------------------------------------------------- /demo/demo_uicallback_noqueue.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """demo_uicallback_noqueue.py - An application that executes Python code in a UI from Java 4 | 5 | This example uses org.cellprofiler.javabridge.CPython to execute 6 | Python code from within a Java callback. 7 | 8 | python-javabridge is licensed under the BSD license. See the 9 | accompanying file LICENSE for details. 10 | 11 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 12 | Copyright (c) 2009-2013 Broad Institute 13 | All rights reserved. 14 | 15 | """ 16 | import javabridge 17 | import sys 18 | import traceback 19 | 20 | def main(args): 21 | javabridge.activate_awt() 22 | cpython = javabridge.make_instance( 23 | "org/cellprofiler/javabridge/CPython", "()V") 24 | script = """ 25 | //-------------------------------------- 26 | // 27 | // The anonymous callable runs on the thread 28 | // that started Java - that's the rule with AWT. 29 | // 30 | // The callable returns a Java Map whose keys 31 | // have the labels of objects like "qUp" for 32 | // the upward queue. Python can then fetch 33 | // whichever ones it wants and do Java stuff 34 | // with them. 35 | // 36 | //-------------------------------------- 37 | new java.util.concurrent.Callable() { 38 | call: function() { 39 | importClass(javax.swing.SpringLayout); 40 | importClass(javax.swing.JFrame); 41 | importClass(javax.swing.JTextField); 42 | importClass(javax.swing.JButton); 43 | importClass(javax.swing.JScrollPane); 44 | importClass(javax.swing.JTextArea); 45 | importClass(java.util.Hashtable); 46 | importClass(java.util.ArrayList); 47 | importClass(java.util.concurrent.CountDownLatch); 48 | importClass(java.awt.event.ActionListener); 49 | importClass(java.awt.event.WindowAdapter); 50 | 51 | d = new Hashtable(); 52 | signal = new CountDownLatch(1); 53 | d.put("signal", signal); 54 | frame = new JFrame("Callbacks in Java"); 55 | d.put("frame", frame); 56 | contentPane = frame.getContentPane(); 57 | layout = new SpringLayout(); 58 | contentPane.setLayout(layout); 59 | 60 | textField = new JTextField("'Hello, world.'", 60); 61 | d.put("textField", textField); 62 | contentPane.add(textField); 63 | 64 | execButton = new JButton("Exec"); 65 | contentPane.add(execButton); 66 | 67 | evalButton = new JButton("Eval"); 68 | contentPane.add(evalButton); 69 | 70 | result = new JTextArea("None"); 71 | scrollPane = new JScrollPane(result) 72 | contentPane.add(scrollPane); 73 | d.put("result", result); 74 | 75 | //----------------------------------------------------- 76 | // 77 | // The layout is: 78 | // 79 | // [ textField] [execButton] [evalButton] 80 | // [ scrollPane ] 81 | // 82 | //----------------------------------------------------- 83 | 84 | layout.putConstraint(SpringLayout.WEST, textField, 85 | 5, SpringLayout.WEST, contentPane); 86 | layout.putConstraint(SpringLayout.NORTH, textField, 87 | 5, SpringLayout.NORTH, contentPane); 88 | 89 | layout.putConstraint(SpringLayout.WEST, execButton, 90 | 5, SpringLayout.EAST, textField); 91 | layout.putConstraint(SpringLayout.NORTH, execButton, 92 | 0, SpringLayout.NORTH, textField); 93 | 94 | layout.putConstraint(SpringLayout.WEST, evalButton, 95 | 5, SpringLayout.EAST, execButton); 96 | layout.putConstraint(SpringLayout.NORTH, evalButton, 97 | 0, SpringLayout.NORTH, textField); 98 | 99 | layout.putConstraint(SpringLayout.NORTH, scrollPane, 100 | 5, SpringLayout.SOUTH, textField); 101 | layout.putConstraint(SpringLayout.WEST, scrollPane, 102 | 0, SpringLayout.WEST, textField); 103 | layout.putConstraint(SpringLayout.EAST, scrollPane, 104 | 0, SpringLayout.EAST, evalButton); 105 | 106 | layout.putConstraint(SpringLayout.EAST, contentPane, 107 | 5, SpringLayout.EAST, evalButton); 108 | layout.putConstraint(SpringLayout.SOUTH, contentPane, 109 | 20, SpringLayout.SOUTH, scrollPane); 110 | 111 | //----------------------------------------------- 112 | // 113 | // Create an action listener that binds the execButton 114 | // action to a function that instructs Python to 115 | // execute the contents of the text field. 116 | // 117 | //----------------------------------------------- 118 | alExec = new ActionListener() { 119 | actionPerformed: function(e) { 120 | try { 121 | cpython.exec(textField.getText()); 122 | result.setText("OK"); 123 | } catch(err) { 124 | result.setText(err.message); 125 | } 126 | } 127 | }; 128 | execButton.addActionListener(alExec); 129 | 130 | //----------------------------------------------- 131 | // 132 | // Create an action listener that binds the evalButton 133 | // action to a function that instructs Python to 134 | // evaluate the contents of the text field. 135 | // 136 | //----------------------------------------------- 137 | alEval = new ActionListener() { 138 | actionPerformed: function(e) { 139 | try { 140 | locals = new Hashtable(); 141 | jresult = new ArrayList(); 142 | locals.put("script", textField.getText()); 143 | locals.put("jresult", jresult); 144 | script = "import javabridge\\n" + 145 | "result=eval(javabridge.to_string(script))\\n" + 146 | "jwresult=javabridge.JWrapper(jresult)\\n" + 147 | "jwresult.add(str(result))" 148 | cpython.exec(script, locals, null); 149 | result.setText(jresult.get(0)); 150 | } catch(err) { 151 | result.setText(err.message); 152 | } 153 | } 154 | }; 155 | evalButton.addActionListener(alEval); 156 | 157 | //----------------------------------------------- 158 | // 159 | // Create a window listener that binds the frame's 160 | // windowClosing action to a function that instructs 161 | // Python to exit. 162 | // 163 | //----------------------------------------------- 164 | wl = new WindowAdapter() { 165 | windowClosing: function(e) { 166 | signal.countDown(); 167 | } 168 | }; 169 | 170 | frame.addWindowListener(wl); 171 | 172 | frame.pack(); 173 | frame.setVisible(true); 174 | return d; 175 | } 176 | };""" 177 | c = javabridge.run_script(script, dict(cpython=cpython)); 178 | f = javabridge.make_future_task(c) 179 | d = javabridge.execute_future_in_main_thread(f); 180 | d = javabridge.get_map_wrapper(d) 181 | frame = javabridge.JWrapper(d["frame"]) 182 | signal = javabridge.JWrapper(d["signal"]); 183 | signal.await(); 184 | frame.dispose(); 185 | 186 | if __name__=="__main__": 187 | javabridge.start_vm() 188 | if sys.platform == 'darwin': 189 | # 190 | # For Mac, we need to start an event loop 191 | # on the main thread and run the UI code 192 | # on a worker thread. 193 | # 194 | import threading 195 | javabridge.mac_run_loop_init() 196 | class Runme(threading.Thread): 197 | def run(self): 198 | javabridge.attach() 199 | try: 200 | main(sys.argv) 201 | finally: 202 | javabridge.detach() 203 | t = Runme() 204 | t.start() 205 | javabridge.mac_enter_run_loop() 206 | else: 207 | # 208 | # For everyone else, the event loop 209 | # is run by Java and we do everything 210 | # on the main thread. 211 | # 212 | main(sys.argv) 213 | javabridge.deactivate_awt() 214 | javabridge.kill_vm() 215 | -------------------------------------------------------------------------------- /demo/demo_wxandawt.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """demo_wxandawt.py - show how to start the Javabridge with wxPython and AWT 4 | 5 | python-javabridge is licensed under the BSD license. See the 6 | accompanying file LICENSE for details. 7 | 8 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 9 | Copyright (c) 2009-2013 Broad Institute 10 | All rights reserved. 11 | 12 | """ 13 | 14 | import os 15 | import wx 16 | import javabridge 17 | 18 | class EmptyApp(wx.PySimpleApp): 19 | def OnInit(self): 20 | javabridge.activate_awt() 21 | 22 | return True 23 | 24 | javabridge.start_vm() 25 | 26 | try: 27 | app = EmptyApp(False) 28 | 29 | frame = wx.Frame(None) 30 | frame.Sizer = wx.BoxSizer(wx.HORIZONTAL) 31 | launch_button = wx.Button(frame, label="Launch AWT frame") 32 | frame.Sizer.Add(launch_button, 1, wx.ALIGN_CENTER_HORIZONTAL) 33 | 34 | def fn_launch_frame(event): 35 | javabridge.execute_runnable_in_main_thread(javabridge.run_script(""" 36 | new java.lang.Runnable() { 37 | run: function() { 38 | with(JavaImporter(java.awt.Frame)) Frame().setVisible(true); 39 | } 40 | };""")) 41 | launch_button.Bind(wx.EVT_BUTTON, fn_launch_frame) 42 | 43 | frame.Layout() 44 | frame.Show() 45 | app.MainLoop() 46 | 47 | finally: 48 | 49 | javabridge.kill_vm() 50 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/python-javabridge.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/python-javabridge.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/python-javabridge" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/python-javabridge" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # python-javabridge documentation build configuration file, created by 4 | # sphinx-quickstart on Thu Aug 1 12:45:16 2013. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | sys.path.insert(0, os.path.abspath('..')) 20 | 21 | # -- General configuration ----------------------------------------------------- 22 | 23 | # If your documentation needs a minimal Sphinx version, state it here. 24 | #needs_sphinx = '1.0' 25 | 26 | # Add any Sphinx extension module names here, as strings. They can be extensions 27 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 28 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.intersphinx', 'sphinx.ext.coverage', 'sphinx.ext.viewcode'] 29 | 30 | # Add any paths that contain templates here, relative to this directory. 31 | templates_path = ['_templates'] 32 | 33 | # The suffix of source filenames. 34 | source_suffix = '.rst' 35 | 36 | # The encoding of source files. 37 | #source_encoding = 'utf-8-sig' 38 | 39 | # The master toctree document. 40 | master_doc = 'index' 41 | 42 | # General information about the project. 43 | project = u'python-javabridge' 44 | copyright = u'2013, Broad Institute of MIT and Harvard' 45 | 46 | def get_version(): 47 | version_file = os.path.join(os.path.dirname(__file__), '..', 'javabridge', 48 | '_version.py') 49 | if os.path.exists(version_file): 50 | with open(version_file) as f: 51 | cached_version_line = f.read().strip() 52 | try: 53 | import re 54 | # From http://stackoverflow.com/a/3619714/17498 55 | cached_version = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", 56 | cached_version_line, re.M).group(1) 57 | except: 58 | raise RuntimeError("Unable to find version in %s" % version_file) 59 | split_version = cached_version.split('.') 60 | return '.'.join(split_version[:2]), cached_version 61 | else: 62 | return '0.0', '0.0.0' 63 | 64 | # The version info for the project you're documenting, acts as replacement for 65 | # |version| and |release|, also used in various other places throughout the 66 | # built documents. 67 | # 68 | # version: The short X.Y version. 69 | # release: The full version, including alpha/beta/rc tags. 70 | version, release = get_version() 71 | 72 | # The language for content autogenerated by Sphinx. Refer to documentation 73 | # for a list of supported languages. 74 | #language = None 75 | 76 | # There are two options for replacing |today|: either, you set today to some 77 | # non-false value, then it is used: 78 | #today = '' 79 | # Else, today_fmt is used as the format for a strftime call. 80 | #today_fmt = '%B %d, %Y' 81 | 82 | # List of patterns, relative to source directory, that match files and 83 | # directories to ignore when looking for source files. 84 | exclude_patterns = ['_build'] 85 | 86 | # The reST default role (used for this markup: `text`) to use for all documents. 87 | #default_role = None 88 | 89 | # If true, '()' will be appended to :func: etc. cross-reference text. 90 | #add_function_parentheses = True 91 | 92 | # If true, the current module name will be prepended to all description 93 | # unit titles (such as .. function::). 94 | #add_module_names = True 95 | 96 | # If true, sectionauthor and moduleauthor directives will be shown in the 97 | # output. They are ignored by default. 98 | #show_authors = False 99 | 100 | # The name of the Pygments (syntax highlighting) style to use. 101 | pygments_style = 'sphinx' 102 | 103 | # A list of ignored prefixes for module index sorting. 104 | #modindex_common_prefix = [] 105 | 106 | # If true, keep warnings as "system message" paragraphs in the built documents. 107 | #keep_warnings = False 108 | 109 | 110 | # -- Options for HTML output --------------------------------------------------- 111 | 112 | # The theme to use for HTML and HTML Help pages. See the documentation for 113 | # a list of builtin themes. 114 | html_theme = 'default' 115 | 116 | # Theme options are theme-specific and customize the look and feel of a theme 117 | # further. For a list of options available for each theme, see the 118 | # documentation. 119 | #html_theme_options = {} 120 | 121 | # Add any paths that contain custom themes here, relative to this directory. 122 | #html_theme_path = [] 123 | 124 | # The name for this set of Sphinx documents. If None, it defaults to 125 | # " v documentation". 126 | #html_title = None 127 | 128 | # A shorter title for the navigation bar. Default is the same as html_title. 129 | #html_short_title = None 130 | 131 | # The name of an image file (relative to this directory) to place at the top 132 | # of the sidebar. 133 | #html_logo = None 134 | 135 | # The name of an image file (within the static path) to use as favicon of the 136 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 137 | # pixels large. 138 | #html_favicon = None 139 | 140 | # Add any paths that contain custom static files (such as style sheets) here, 141 | # relative to this directory. They are copied after the builtin static files, 142 | # so a file named "default.css" will overwrite the builtin "default.css". 143 | html_static_path = ['_static'] 144 | 145 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 146 | # using the given strftime format. 147 | #html_last_updated_fmt = '%b %d, %Y' 148 | 149 | # If true, SmartyPants will be used to convert quotes and dashes to 150 | # typographically correct entities. 151 | #html_use_smartypants = True 152 | 153 | # Custom sidebar templates, maps document names to template names. 154 | #html_sidebars = {} 155 | 156 | # Additional templates that should be rendered to pages, maps page names to 157 | # template names. 158 | #html_additional_pages = {} 159 | 160 | # If false, no module index is generated. 161 | #html_domain_indices = True 162 | 163 | # If false, no index is generated. 164 | #html_use_index = True 165 | 166 | # If true, the index is split into individual pages for each letter. 167 | #html_split_index = False 168 | 169 | # If true, links to the reST sources are added to the pages. 170 | #html_show_sourcelink = True 171 | 172 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 173 | #html_show_sphinx = True 174 | 175 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 176 | #html_show_copyright = True 177 | 178 | # If true, an OpenSearch description file will be output, and all pages will 179 | # contain a tag referring to it. The value of this option must be the 180 | # base URL from which the finished HTML is served. 181 | #html_use_opensearch = '' 182 | 183 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 184 | #html_file_suffix = None 185 | 186 | # Output file base name for HTML help builder. 187 | htmlhelp_basename = 'python-javabridgedoc' 188 | 189 | 190 | # -- Options for LaTeX output -------------------------------------------------- 191 | 192 | latex_elements = { 193 | # The paper size ('letterpaper' or 'a4paper'). 194 | #'papersize': 'letterpaper', 195 | 196 | # The font size ('10pt', '11pt' or '12pt'). 197 | #'pointsize': '10pt', 198 | 199 | # Additional stuff for the LaTeX preamble. 200 | #'preamble': '', 201 | } 202 | 203 | # Grouping the document tree into LaTeX files. List of tuples 204 | # (source start file, target name, title, author, documentclass [howto/manual]). 205 | latex_documents = [ 206 | ('index', 'python-javabridge.tex', u'python-javabridge Documentation', 207 | u'Lee Kamentsky, Vebjorn Ljosa', 'manual'), 208 | ] 209 | 210 | # The name of an image file (relative to this directory) to place at the top of 211 | # the title page. 212 | #latex_logo = None 213 | 214 | # For "manual" documents, if this is true, then toplevel headings are parts, 215 | # not chapters. 216 | #latex_use_parts = False 217 | 218 | # If true, show page references after internal links. 219 | #latex_show_pagerefs = False 220 | 221 | # If true, show URL addresses after external links. 222 | #latex_show_urls = False 223 | 224 | # Documents to append as an appendix to all manuals. 225 | #latex_appendices = [] 226 | 227 | # If false, no module index is generated. 228 | #latex_domain_indices = True 229 | 230 | 231 | # -- Options for manual page output -------------------------------------------- 232 | 233 | # One entry per manual page. List of tuples 234 | # (source start file, name, description, authors, manual section). 235 | man_pages = [ 236 | ('index', 'python-javabridge', u'python-javabridge Documentation', 237 | [u'Lee Kamentsky, Vebjorn Ljosa'], 1) 238 | ] 239 | 240 | # If true, show URL addresses after external links. 241 | #man_show_urls = False 242 | 243 | 244 | # -- Options for Texinfo output ------------------------------------------------ 245 | 246 | # Grouping the document tree into Texinfo files. List of tuples 247 | # (source start file, target name, title, author, 248 | # dir menu entry, description, category) 249 | texinfo_documents = [ 250 | ('index', 'python-javabridge', u'python-javabridge Documentation', 251 | u'Lee Kamentsky, Vebjorn Ljosa', 'python-javabridge', 'One line description of project.', 252 | 'Miscellaneous'), 253 | ] 254 | 255 | # Documents to append as an appendix to all manuals. 256 | #texinfo_appendices = [] 257 | 258 | # If false, no module index is generated. 259 | #texinfo_domain_indices = True 260 | 261 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 262 | #texinfo_show_urls = 'footnote' 263 | 264 | # If true, do not generate a @detailmenu in the "Top" node's menu. 265 | #texinfo_no_detailmenu = False 266 | 267 | 268 | # Example configuration for intersphinx: refer to the Python standard library. 269 | intersphinx_mapping = {'http://docs.python.org/': None} 270 | -------------------------------------------------------------------------------- /docs/developers.rst: -------------------------------------------------------------------------------- 1 | For Javabridge developers 2 | ========================= 3 | 4 | Build from git repository 5 | ------------------------- 6 | 7 | :: 8 | 9 | git clone git@github.com:CellProfiler/python-javabridge.git 10 | cd python-javabridge 11 | cython *.pyx 12 | python setup.py build 13 | python setup.py install 14 | 15 | Make source distribution and publish 16 | ------------------------------------ 17 | 18 | :: 19 | 20 | git tag -a -m 'A commit message' '1.0.0pr11' 21 | git push --tags # Not necessary, but you'll want to do it at some point 22 | git clean -fdx 23 | python setup.py develop 24 | python setup.py sdist upload 25 | python setup.py build_sphinx 26 | python setup.py upload_sphinx 27 | 28 | Upload source distribution built by Jenkins 29 | ------------------------------------------- 30 | 31 | :: 32 | 33 | git tag -a -m 'A commit message' '1.0.4' 34 | git push --tags # Not necessary, but you'll want to do it at some point 35 | # Kick off a new Jenkins build manually, wait for it, and download. 36 | twine upload javabridge-1.0.4.tar.gz 37 | python setup.py build_sphinx 38 | python setup.py upload_sphinx 39 | -------------------------------------------------------------------------------- /docs/hello.rst: -------------------------------------------------------------------------------- 1 | Hello world 2 | =========== 3 | 4 | Without a GUI:: 5 | 6 | import os 7 | import javabridge 8 | 9 | javabridge.start_vm(run_headless=True) 10 | try: 11 | print javabridge.run_script('java.lang.String.format("Hello, %s!", greetee);', 12 | dict(greetee='world')) 13 | finally: 14 | javabridge.kill_vm() 15 | 16 | You can also use a with block:: 17 | 18 | import os 19 | import javabridge 20 | 21 | with javabridge.vm(run_headless=True) 22 | print javabridge.run_script('java.lang.String.format("Hello, %s!", greetee);', 23 | dict(greetee='world')) 24 | 25 | With only a Java AWT GUI:: 26 | 27 | import os 28 | import wx 29 | import javabridge 30 | 31 | javabridge.start_vm() 32 | 33 | class EmptyApp(wx.App): 34 | def OnInit(self): 35 | javabridge.activate_awt() 36 | return True 37 | 38 | try: 39 | 40 | app = EmptyApp(False) 41 | 42 | # Must exist (perhaps the app needs to have a top-level window?), but 43 | # does not have to be shown. 44 | frame = wx.Frame(None) 45 | 46 | javabridge.execute_runnable_in_main_thread(javabridge.run_script(""" 47 | new java.lang.Runnable() { 48 | run: function() { 49 | with(JavaImporter(java.awt.Frame)) Frame().setVisible(true); 50 | } 51 | };""")) 52 | 53 | app.MainLoop() 54 | 55 | finally: 56 | 57 | javabridge.kill_vm() 58 | 59 | Mixing wxPython and Java AWT GUIs:: 60 | 61 | import os 62 | import wx 63 | import javabridge 64 | 65 | class EmptyApp(wx.PySimpleApp): 66 | def OnInit(self): 67 | javabridge.activate_awt() 68 | 69 | return True 70 | 71 | javabridge.start_vm() 72 | 73 | try: 74 | app = EmptyApp(False) 75 | 76 | frame = wx.Frame(None) 77 | frame.Sizer = wx.BoxSizer(wx.HORIZONTAL) 78 | launch_button = wx.Button(frame, label="Launch AWT frame") 79 | frame.Sizer.Add(launch_button, 1, wx.ALIGN_CENTER_HORIZONTAL) 80 | 81 | def fn_launch_frame(event): 82 | javabridge.execute_runnable_in_main_thread(javabridge.run_script(""" 83 | new java.lang.Runnable() { 84 | run: function() { 85 | with(JavaImporter(java.awt.Frame)) Frame().setVisible(true); 86 | } 87 | };""")) 88 | launch_button.Bind(wx.EVT_BUTTON, fn_launch_frame) 89 | 90 | frame.Layout() 91 | frame.Show() 92 | app.MainLoop() 93 | 94 | finally: 95 | 96 | javabridge.kill_vm() 97 | -------------------------------------------------------------------------------- /docs/highlevel.rst: -------------------------------------------------------------------------------- 1 | .. -*- visual-line-mode -*- 2 | 3 | High-level API 4 | =============== 5 | 6 | The high-level API can wrap a Java object or class so that its methods and fields 7 | can be referenced by dot syntax. It also has functions that offload some 8 | of the burden of exception handling and type conversion, thus providing a 9 | mid-level compromise between ease of use and performance. 10 | 11 | Signatures 12 | ---------- 13 | 14 | Javabridge uses method signatures when it uses the JNI method lookup APIs. 15 | The method signatures are also used to convert between Python and Java 16 | primitives and objects. If you use the high-level API, as opposed to scripting, 17 | you will need to learn how to construct a signature for a class method. For example, 18 | java.lang.String has the following three methods: 19 | :: 20 | 21 | public char charAt(int index) 22 | public int indexOf(String str) 23 | public byte [] getString(String charsetName) 24 | 25 | charAt has the signature, "(I)C", because it takes one integer argument (I) and 26 | its return value is a char (C). 27 | 28 | indexOf has the signature, "(Ljava/lang/String;)I", "L" and ";" bracket a 29 | class name which is represented as a path instead of with the dotted syntax. 30 | 31 | getString has the signature, "(Ljava/lang/String;)[B. "[B" uses "[" to indicate 32 | that an array will be returned and "B" indicates that the array is of type, byte. 33 | 34 | The signature syntax is described in `JNI Types and Data Structures `_. An example: “(ILjava/lang/String;)[I” takes an integer and string as parameters and returns an array of integers. 35 | 36 | Cheat sheet: 37 | 38 | Z 39 | boolean 40 | B 41 | byte 42 | C 43 | char 44 | S 45 | short 46 | I 47 | int 48 | J 49 | long 50 | F 51 | float 52 | D 53 | double 54 | L 55 | class (e.g., Lmy/class;) 56 | \[ 57 | array of (e.g., [B = byte array) 58 | 59 | 60 | The signatures are difficult, but you can cheat: the JDK has a 61 | Java class file disassembler called ``javap`` that prints out the 62 | signatures of everything in a class. 63 | 64 | Wrapping Java objects using reflection 65 | -------------------------------------- 66 | .. autoclass:: javabridge.JWrapper(o) 67 | .. autoclass:: javabridge.JClassWrapper(class_name) 68 | .. autoclass:: javabridge.JProxy(class_name) 69 | 70 | Operations on Java objects 71 | -------------------------- 72 | .. autofunction:: javabridge.call 73 | .. autofunction:: javabridge.make_call 74 | .. autofunction:: javabridge.get_field 75 | .. autofunction:: javabridge.set_field 76 | .. autofunction:: javabridge.get_static_field 77 | .. autofunction:: javabridge.static_call 78 | .. autofunction:: javabridge.make_static_call 79 | .. autofunction:: javabridge.is_instance_of 80 | .. autofunction:: javabridge.make_instance 81 | .. autofunction:: javabridge.set_static_field 82 | .. autofunction:: javabridge.to_string 83 | .. autofunction:: javabridge.get_nice_arg 84 | 85 | Hand-coding Python objects that wrap Java objects 86 | ------------------------------------------------- 87 | The functions ``make_new`` and ``make_method`` create Python methods that wrap Java constructors and methods, respectively. The function can be used to create Python wrapper classes for Java classes. Example:: 88 | 89 | >>> class Integer: 90 | new_fn = javabridge.make_new("java/lang/Integer", "(I)V") 91 | def __init__(self, i): 92 | self.new_fn(i) 93 | intValue = javabridge.make_method("intValue", "()I", "Retrieve the integer value") 94 | >>> i = Integer(435) 95 | >>> i.intValue() 96 | 435 97 | 98 | .. autofunction:: javabridge.make_new 99 | .. autofunction:: javabridge.make_method 100 | 101 | Useful collection wrappers 102 | -------------------------- 103 | The collection wrappers take a Java object that implements some interface 104 | and return a corresponding Python object that wraps the interface's methods 105 | and in addition provide Python-style access to the Java object. The Java 106 | object itself is, by convention, saved as self.o in the Python object. 107 | 108 | .. autofunction:: javabridge.get_collection_wrapper 109 | .. autofunction:: javabridge.get_dictionary_wrapper 110 | .. autofunction:: javabridge.get_enumeration_wrapper 111 | .. autofunction:: javabridge.jdictionary_to_string_dictionary 112 | .. autofunction:: javabridge.jenumeration_to_string_list 113 | .. autofunction:: javabridge.iterate_collection 114 | .. autofunction:: javabridge.iterate_java 115 | .. autofunction:: javabridge.make_list 116 | .. autofunction:: javabridge.get_map_wrapper 117 | .. autofunction:: javabridge.make_map 118 | 119 | Reflection 120 | ---------- 121 | These functions make class wrappers suitable for introspection. These wrappers are examples of the kinds of wrappers that you can build yourself using ``make_method`` and ``make_new``. 122 | 123 | .. autofunction:: javabridge.get_class_wrapper 124 | .. autofunction:: javabridge.get_field_wrapper 125 | .. autofunction:: javabridge.class_for_name 126 | .. autofunction:: javabridge.get_constructor_wrapper 127 | .. autofunction:: javabridge.get_method_wrapper 128 | 129 | Executing in the correct thread 130 | ------------------------------- 131 | Ensure that callables, runnables and futures that use AWT run in 132 | the AWT main thread, which is not accessible from Python for some operating 133 | systems. 134 | 135 | .. autofunction:: javabridge.make_future_task 136 | .. autofunction:: javabridge.execute_runnable_in_main_thread 137 | .. autofunction:: javabridge.execute_future_in_main_thread 138 | .. autofunction:: javabridge.execute_callable_in_main_thread 139 | .. autofunction:: javabridge.get_future_wrapper 140 | 141 | Exceptions 142 | ---------- 143 | 144 | .. autoexception:: javabridge.JavaError 145 | .. autoexception:: javabridge.JavaException 146 | .. autoexception:: javabridge.JVMNotFoundError 147 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | =================================================================== 2 | javabridge: running and interacting with the JVM from Python 3 | =================================================================== 4 | 5 | The javabridge Python package makes it easy to start a Java virtual machine (JVM) from Python and interact with it. Python code can interact with the JVM using a low-level API or a more convenient high-level API. 6 | 7 | The javabridge was developed for `CellProfiler 8 | `_, where it is used together with `python-bioformats `_ to interface to various Java code, including `Bio-Formats `_ and `ImageJ `_. 9 | 10 | `PyPI record `_ 11 | 12 | `Documentation `_ 13 | 14 | `GitHub repository `_ 15 | 16 | `Bug reports `_ 17 | 18 | Contents: 19 | 20 | .. toctree:: 21 | :maxdepth: 2 22 | 23 | installation 24 | hello 25 | start_kill 26 | javascript 27 | highlevel 28 | lowlevel 29 | java2python 30 | unittesting 31 | developers 32 | 33 | 34 | Indices and tables 35 | ================== 36 | 37 | * :ref:`genindex` 38 | * :ref:`search` 39 | 40 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | Installation and testing 2 | ======================== 3 | 4 | Install using pip 5 | ----------------- 6 | 7 | :: 8 | 9 | pip install numpy 10 | pip install javabridge 11 | 12 | 13 | Install without pip 14 | ------------------- 15 | 16 | :: 17 | 18 | # Make sure numpy is installed 19 | python setup.py install 20 | 21 | 22 | Dependencies 23 | ------------ 24 | 25 | The Javabridge requires Python 2.6 or above, NumPy, the Java 26 | Development Kit (JDK), and a C compiler. 27 | 28 | Linux 29 | ^^^^^ 30 | 31 | On CentOS 6, the dependencies can be installed as follows:: 32 | 33 | yum install gcc numpy python-devel java-1.6.0-openjdk-devel 34 | curl -O https://raw.github.com/pypa/pip/master/contrib/get-pip.py 35 | python get-pip.py 36 | 37 | On Fedora 19, the dependencies can be installed as follows:: 38 | 39 | yum install gcc numpy python-devel java-1.7.0-openjdk-devel python-pip openssl 40 | 41 | On Ubuntu 13 and Debian 7, the dependencies can be installed as follows:: 42 | 43 | apt-get install openjdk-6-jdk python-pip python-numpy python-dev 44 | 45 | On Ubuntu 14, the dependencies can be installed as follows:: 46 | 47 | apt-get install openjdk-7-jdk python-pip python-numpy python-dev 48 | 49 | On Arch Linux, the dependencies can be installed as follows:: 50 | 51 | pacman -S jdk7-openjdk python2-pip python2-numpy base-devel 52 | 53 | MacOS X 54 | ^^^^^^^ 55 | 56 | 1. Install the Xcode command-line tools. There are two ways: 57 | 58 | A. Install Xcode from the Mac App Store. (You can also download it 59 | from Apple's Mac Dev Center, but that may require membership in 60 | the Apple Developer Program.) Install the Xcode command-line 61 | tools by starting Xcode, going to Preferences, click on 62 | "Downloads" in the toolbar, and click the "Install" button on 63 | the line "Command Line Tools." For MacOS 10.9 and Xcode 5 and 64 | above, you may have to install the command-line tools by typing 65 | ``xcode-select --install`` and following the prompts. 66 | 67 | B. Download the Xcode command-line tools from Apple's Mac Dev 68 | Center and install. This may require membership in the Apple 69 | Developer Program. 70 | 71 | 2. Create and activate a `virtualenv` virtual environment if you don't 72 | want to clutter up your system-wide python installation with new 73 | packages. 74 | 75 | 3. ``pip install numpy`` 76 | 77 | 4. ``pip install javabridge`` 78 | 79 | 80 | Windows 81 | ^^^^^^^ 82 | 83 | If you do not have a C compiler installed, you can install Microsoft Visual C++ Build Tools to perform the compile steps. The compiler installation can be found in https://visualstudio.microsoft.com/visual-cpp-build-tools/. 84 | 85 | You should install a Java Development Kit (JDK) appropriate for your 86 | Java project. The Windows build is tested with the Oracle JDK 1.7. You 87 | also need to install the Java Runtime Environment (JRE). Note that 88 | the bitness needs to match your python: if you use a 32-bit Python, 89 | then you need a 32-bit JDK; if you use a 64-bit Python, then you need 90 | a 64-bit JDK. 91 | 92 | The paths to PIP and Python should be in your PATH (``set 93 | PATH=%PATH%;c:\\Python27;c:\\Python27\\scripts`` if Python and PIP 94 | installed to the default locations). The following steps should 95 | perform the install: 96 | 97 | 1. Run Command Prompt as administrator. Set the path to Python and PIP if needed. 98 | 99 | 2. Issue the command:: 100 | 101 | pip install javabridge 102 | 103 | 104 | Running the unit tests 105 | ---------------------- 106 | 107 | Running the unit tests requires Nose. Some of the tests require Python 108 | 2.7 or above. 109 | 110 | 1. Build and install in the source code tree so that the unit tests can run:: 111 | 112 | python setup.py develop 113 | 114 | 2. Run the unit tests:: 115 | 116 | nosetests 117 | 118 | On Linux and MacOS X, the following should also work:: 119 | 120 | python setup.py nosetests 121 | 122 | You must build the extensions in-place on Windows, then run nosetests 123 | if you use setup to run the tests:: 124 | 125 | python setup.py build_ext -i 126 | python setup.py nosetests 127 | 128 | See the section :ref:`unit-testing` for how to run unit tests for your 129 | own projects that use Javabridge. 130 | 131 | 132 | -------------------------------------------------------------------------------- /docs/java2python.rst: -------------------------------------------------------------------------------- 1 | Calling Python from Java 2 | ======================== 3 | 4 | The Javabridge loads a Java class, org.cellprofiler.javabridge.CPython, that 5 | can be used to execute Python code. The class can be used within Java code 6 | called from the Python interpreter or it can be used within Java to run 7 | Python embedded in Java. 8 | 9 | .. js:class:: org.cellprofiler.javascript.CPython 10 | 11 | The CPython class binds the Python interpreter to the JVM and provides 12 | the ability to execute Python scripts. 13 | 14 | .. js:function:: exec 15 | 16 | :param script: The Python script to execute. 17 | :param locals: A map of the name of a Java object in the Python 18 | execution context to the Java object itself. The objects 19 | in the map have local scope. A null value can be used 20 | if no locals need to be defined. 21 | :param globals: A map of the name of a Java object to the Java 22 | object itself. The objects in the map have global scope. 23 | If a null value is used, ``globals`` defaults to the 24 | builtin globals. 25 | 26 | ``exec()`` executes the script passed within the Python interpreter. 27 | The interpreter adds the builtin globals to the globals passed in, 28 | then executes the script. The same map may be used for both the 29 | locals and the globals - this mode may seem more familiar to those 30 | who regularly script in Python and expect the ``import`` statement 31 | to have a global effect. 32 | 33 | There is no ``eval`` method. You can retrieve values by passing 34 | a container object such as an array or map as one of the locals and you 35 | can set elements in the object with values to be returned. 36 | 37 | Example:: 38 | 39 | class MyClass { 40 | static final CPython cpython = CPython(); 41 | 42 | public List whereIsWaldo(String root) { 43 | ArrayList result = new ArrayList(); 44 | Hashtable locals = new Hashtable(); 45 | locals.put("result", result); 46 | locals.put("root", root); 47 | StringBuilder script = new StringBuilder(); 48 | script.append("import os\n"); 49 | script.append("import javabridge\n"); 50 | script.append("root = javabridge.to_string(root)"); 51 | script.append("result = javabridge.JWrapper(result)"); 52 | script.append("for path, dirnames, filenames in os.walk(root):\n"); 53 | script.append(" if 'waldo' in filenames:"); 54 | script.append(" result.add(path)"); 55 | cpython.exec(script.toString(), locals, null); 56 | return result; 57 | } 58 | 59 | } 60 | 61 | .. js:function:: execute 62 | 63 | ``execute`` is a synonym for ``exec`` which is a Python keyword. 64 | Use ``execute`` in place of ``exec`` to call Python from a javabridge 65 | CWrapper for CPython. 66 | 67 | Maintaing references to Python values 68 | ------------------------------------- 69 | 70 | You may want to maintain references to Python objects across script executions. 71 | The following functions let a Java caller refer to a Python value (which can 72 | be a base type or an object) via a token which may be exchanged for the value 73 | at any time. The Java code is responsible for managing the reference's lifetime. 74 | Example:: 75 | 76 | import javabridge 77 | 78 | cpython = javabridge.JClassWrapper('org.cellprofiler.javabridge.CPython')() 79 | d = javabridge.JClassWrapper('java.util.Hashtable')() 80 | result = javabridge.JClassWrapper('java.util.ArrayList')() 81 | d.put("result", result) 82 | cpython.execute( 83 | 'import javabridge\n' 84 | 'x = { "foo":"bar"}\n' 85 | 'ref_id = javabridge.create_and_lock_jref(x)\n' 86 | 'javabridge.JWrapper(result).add(ref_id)', d, d) 87 | cpython.execute( 88 | 'import javabridge\n' 89 | 'ref_id = javabridge.to_string(javabridge.JWrapper(result).get(0))\n' 90 | 'assert javabridge.redeem_jref(ref_id)["foo"] == "bar"\n' 91 | 'javabridge.unlock_jref(ref_id)', d, d) 92 | 93 | .. autofunction:: javabridge.create_jref 94 | .. autofunction:: javabridge.create_and_lock_jref 95 | .. autofunction:: javabridge.redeem_jref 96 | .. autofunction:: javabridge.lock_jref 97 | .. autofunction:: javabridge.unlock_jref 98 | 99 | -------------------------------------------------------------------------------- /docs/javascript.rst: -------------------------------------------------------------------------------- 1 | Executing JavaScript on the JVM 2 | =============================== 3 | 4 | As you will see in subsequent sections, navigating and manipulating 5 | the JVM's class and object structure can result in verbose and 6 | cumbersome Python code. Therefore, Javabridge ships with the 7 | JavaScript interpreter Rhino, which runs on the JVM. In many cases, 8 | the most convienient way to interact with the JVM is to execute a 9 | piece of JavaScript. 10 | 11 | .. autofunction:: javabridge.run_script 12 | 13 | For more information on using Rhino with the JVM see 14 | https://developer.mozilla.org/en-US/docs/Rhino/Scripting_Java 15 | 16 | Examples: 17 | 18 | >>> javabridge.run_script("2 + 2") 19 | 4 20 | 21 | >>> javabridge.run_script("a + b", bindings_in={"a": 2, "b": 3}) 22 | 5 23 | 24 | >>> outputs = {"result": None} 25 | >>> javabridge.run_script("var result = 2 + 2;", bindings_out=outputs) 26 | >>> outputs["result"] 27 | 4 28 | 29 | >>> javabridge.run_script("java.lang.Math.abs(v)", bindings_in=dict(v=-1.5)) 30 | 1.5 31 | 32 | A conversion is necessary when converting from Python primitives and objects 33 | to Java and JavaScript primitives and objects. Python primitives are boxed into 34 | Java objects - Javascript will automatically unbox them when calling a 35 | method that takes primitive arguments (e.g. the call to Math.abs(double) as 36 | in the above example. The following is a table 37 | of bidirectional translations from Python to Java / Javascript and vice-versa: 38 | 39 | +-------------------------+------------------------+----------------------+ 40 | | Python | Java - boxed | Java-primitive | 41 | +=========================+========================+======================+ 42 | | bool | java.lang.Boolean | boolean | 43 | +-------------------------+------------------------+----------------------+ 44 | | int | java.lang.Integer | int | 45 | +-------------------------+------------------------+----------------------+ 46 | | long | java.lang.Long | long | 47 | +-------------------------+------------------------+----------------------+ 48 | | float | java.lang.Double | double | 49 | +-------------------------+------------------------+----------------------+ 50 | | unicode | java.lang.String | N/A | 51 | +-------------------------+------------------------+----------------------+ 52 | | str (Python->java only) | java.lang.String | N/A | 53 | +-------------------------+------------------------+----------------------+ 54 | | None | null | N/A | 55 | +-------------------------+------------------------+----------------------+ 56 | -------------------------------------------------------------------------------- /docs/lowlevel.rst: -------------------------------------------------------------------------------- 1 | The low-level API 2 | ================= 3 | 4 | This API wraps the Java Native Interface (JNI) at the lowest level. It 5 | provides primitives for creating an environment and making calls on 6 | it. 7 | 8 | Java array objects are handled as numpy arrays. 9 | 10 | Each thread has its own environment. When you start a thread, you must attach 11 | to the VM to get that thread's environment and access Java from that thread. 12 | You must detach from the VM before the thread exits. 13 | 14 | .. autofunction:noindex: javabridge.attach 15 | .. autofunction:noindex: javabridge.detach 16 | 17 | In order to get the environment: 18 | 19 | .. autofunction:: javabridge.get_env 20 | 21 | Examples:: 22 | >>> env = get_env() 23 | >>> s = env.new_string(u"Hello, world.") 24 | >>> c = env.get_object_class(s) 25 | >>> method_id = env.get_method_id(c, "length", "()I") 26 | >>> method_id 27 | 28 | >>> result = env.call_method(s, method_id) 29 | >>> result 30 | 13 31 | 32 | .. autoclass:: javabridge.JB_Env 33 | 34 | .. automethod:: javabridge.JB_Env.get_version() 35 | 36 | .. line-block:: **Class discovery** 37 | 38 | .. automethod:: javabridge.JB_Env.find_class(name) 39 | .. automethod:: javabridge.JB_Env.get_object_class(o) 40 | .. automethod:: javabridge.JB_Env.is_instance_of(o, c) 41 | 42 | .. line-block:: **Calling Java object and class (static) methods:** 43 | 44 | .. automethod:: javabridge.JB_Env.get_method_id(c, name, sig) 45 | .. automethod:: javabridge.JB_Env.get_static_method_id(c, name, sig) 46 | .. automethod:: javabridge.JB_Env.from_reflected_method(method, sig, is_static) 47 | .. automethod:: javabridge.JB_Env.new_object(c, m, \*args) 48 | .. automethod:: javabridge.JB_Env.call_method(o, m, \*args) 49 | .. automethod:: javabridge.JB_Env.call_static_method(c, m, \*args) 50 | 51 | .. line-block:: **Accessing Java object and class (static) fields:** 52 | 53 | .. automethod:: javabridge.JB_Env.get_field_id(c, name, sig) 54 | .. automethod:: javabridge.JB_Env.get_static_field_id(c, name, sig) 55 | .. automethod:: javabridge.JB_Env.get_static_object_field 56 | .. automethod:: javabridge.JB_Env.get_static_boolean_field 57 | .. automethod:: javabridge.JB_Env.get_static_byte_field 58 | .. automethod:: javabridge.JB_Env.get_static_short_field 59 | .. automethod:: javabridge.JB_Env.get_static_int_field 60 | .. automethod:: javabridge.JB_Env.get_static_long_field 61 | .. automethod:: javabridge.JB_Env.get_static_float_field 62 | .. automethod:: javabridge.JB_Env.get_static_double_field 63 | .. automethod:: javabridge.JB_Env.set_static_object_field 64 | .. automethod:: javabridge.JB_Env.set_static_boolean_field 65 | .. automethod:: javabridge.JB_Env.set_static_byte_field 66 | .. automethod:: javabridge.JB_Env.set_static_short_field 67 | .. automethod:: javabridge.JB_Env.set_static_int_field 68 | .. automethod:: javabridge.JB_Env.set_static_long_field 69 | .. automethod:: javabridge.JB_Env.set_static_float_field 70 | .. automethod:: javabridge.JB_Env.set_static_double_field 71 | .. automethod:: javabridge.JB_Env.get_object_field 72 | .. automethod:: javabridge.JB_Env.get_boolean_field 73 | .. automethod:: javabridge.JB_Env.get_byte_field 74 | .. automethod:: javabridge.JB_Env.get_short_field 75 | .. automethod:: javabridge.JB_Env.get_int_field 76 | .. automethod:: javabridge.JB_Env.get_long_field 77 | .. automethod:: javabridge.JB_Env.get_float_field 78 | .. automethod:: javabridge.JB_Env.get_double_field 79 | .. automethod:: javabridge.JB_Env.set_object_field 80 | .. automethod:: javabridge.JB_Env.set_boolean_field 81 | .. automethod:: javabridge.JB_Env.set_byte_field 82 | .. automethod:: javabridge.JB_Env.set_char_field 83 | .. automethod:: javabridge.JB_Env.set_short_field 84 | .. automethod:: javabridge.JB_Env.set_long_field 85 | .. automethod:: javabridge.JB_Env.set_float_field 86 | .. automethod:: javabridge.JB_Env.set_double_field 87 | 88 | .. line-block:: **String functions** 89 | 90 | .. automethod:: javabridge.JB_Env.new_string(u) 91 | .. automethod:: javabridge.JB_Env.new_string_utf(s) 92 | .. automethod:: javabridge.JB_Env.get_string(s) 93 | .. automethod:: javabridge.JB_Env.get_string_utf(s) 94 | 95 | .. line-block:: **Array functions** 96 | 97 | .. automethod:: javabridge.JB_Env.get_array_length(array) 98 | .. automethod:: javabridge.JB_Env.get_boolean_array_elements(array) 99 | .. automethod:: javabridge.JB_Env.get_byte_array_elements(array) 100 | .. automethod:: javabridge.JB_Env.get_short_array_elements(array) 101 | .. automethod:: javabridge.JB_Env.get_int_array_elements(array) 102 | .. automethod:: javabridge.JB_Env.get_long_array_elements(array) 103 | .. automethod:: javabridge.JB_Env.get_float_array_elements(array) 104 | .. automethod:: javabridge.JB_Env.get_double_array_elements(array) 105 | .. automethod:: javabridge.JB_Env.get_object_array_elements(array) 106 | .. automethod:: javabridge.JB_Env.make_boolean_array(array) 107 | .. automethod:: javabridge.JB_Env.make_byte_array(array) 108 | .. automethod:: javabridge.JB_Env.make_short_array(array) 109 | .. automethod:: javabridge.JB_Env.make_int_array(array) 110 | .. automethod:: javabridge.JB_Env.make_long_array(array) 111 | .. automethod:: javabridge.JB_Env.make_float_array(array) 112 | .. automethod:: javabridge.JB_Env.make_double_array(array) 113 | .. automethod:: javabridge.JB_Env.make_object_array(len, klass) 114 | .. automethod:: javabridge.JB_Env.set_object_array_element(jbo, index, v) 115 | 116 | .. line-block:: **Exception handling** 117 | 118 | .. automethod:: javabridge.JB_Env.exception_occurred() 119 | .. automethod:: javabridge.JB_Env.exception_describe() 120 | .. automethod:: javabridge.JB_Env.exception_clear() 121 | 122 | .. autoclass:: javabridge.JB_Object 123 | :members: 124 | 125 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | goto end 41 | ) 42 | 43 | if "%1" == "clean" ( 44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 45 | del /q /s %BUILDDIR%\* 46 | goto end 47 | ) 48 | 49 | 50 | %SPHINXBUILD% 2> nul 51 | if errorlevel 9009 ( 52 | echo. 53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 54 | echo.installed, then set the SPHINXBUILD environment variable to point 55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 56 | echo.may add the Sphinx directory to PATH. 57 | echo. 58 | echo.If you don't have Sphinx installed, grab it from 59 | echo.http://sphinx-doc.org/ 60 | exit /b 1 61 | ) 62 | 63 | if "%1" == "html" ( 64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 68 | goto end 69 | ) 70 | 71 | if "%1" == "dirhtml" ( 72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 76 | goto end 77 | ) 78 | 79 | if "%1" == "singlehtml" ( 80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 84 | goto end 85 | ) 86 | 87 | if "%1" == "pickle" ( 88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can process the pickle files. 92 | goto end 93 | ) 94 | 95 | if "%1" == "json" ( 96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished; now you can process the JSON files. 100 | goto end 101 | ) 102 | 103 | if "%1" == "htmlhelp" ( 104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can run HTML Help Workshop with the ^ 108 | .hhp project file in %BUILDDIR%/htmlhelp. 109 | goto end 110 | ) 111 | 112 | if "%1" == "qthelp" ( 113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 117 | .qhcp project file in %BUILDDIR%/qthelp, like this: 118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\python-javabridge.qhcp 119 | echo.To view the help file: 120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\python-javabridge.ghc 121 | goto end 122 | ) 123 | 124 | if "%1" == "devhelp" ( 125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished. 129 | goto end 130 | ) 131 | 132 | if "%1" == "epub" ( 133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 137 | goto end 138 | ) 139 | 140 | if "%1" == "latex" ( 141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 145 | goto end 146 | ) 147 | 148 | if "%1" == "latexpdf" ( 149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 150 | cd %BUILDDIR%/latex 151 | make all-pdf 152 | cd %BUILDDIR%/.. 153 | echo. 154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 155 | goto end 156 | ) 157 | 158 | if "%1" == "latexpdfja" ( 159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 160 | cd %BUILDDIR%/latex 161 | make all-pdf-ja 162 | cd %BUILDDIR%/.. 163 | echo. 164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 165 | goto end 166 | ) 167 | 168 | if "%1" == "text" ( 169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.Build finished. The text files are in %BUILDDIR%/text. 173 | goto end 174 | ) 175 | 176 | if "%1" == "man" ( 177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 181 | goto end 182 | ) 183 | 184 | if "%1" == "texinfo" ( 185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 186 | if errorlevel 1 exit /b 1 187 | echo. 188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 189 | goto end 190 | ) 191 | 192 | if "%1" == "gettext" ( 193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 197 | goto end 198 | ) 199 | 200 | if "%1" == "changes" ( 201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.The overview file is in %BUILDDIR%/changes. 205 | goto end 206 | ) 207 | 208 | if "%1" == "linkcheck" ( 209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Link check complete; look for any errors in the above output ^ 213 | or in %BUILDDIR%/linkcheck/output.txt. 214 | goto end 215 | ) 216 | 217 | if "%1" == "doctest" ( 218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 219 | if errorlevel 1 exit /b 1 220 | echo. 221 | echo.Testing of doctests in the sources finished, look at the ^ 222 | results in %BUILDDIR%/doctest/output.txt. 223 | goto end 224 | ) 225 | 226 | if "%1" == "xml" ( 227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 228 | if errorlevel 1 exit /b 1 229 | echo. 230 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 231 | goto end 232 | ) 233 | 234 | if "%1" == "pseudoxml" ( 235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 236 | if errorlevel 1 exit /b 1 237 | echo. 238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 239 | goto end 240 | ) 241 | 242 | :end 243 | -------------------------------------------------------------------------------- /docs/start_kill.rst: -------------------------------------------------------------------------------- 1 | .. -*- visual-line-mode -*- 2 | 3 | Starting and killing the JVM 4 | ============================ 5 | 6 | API 7 | --- 8 | 9 | .. autofunction:: javabridge.start_vm 10 | .. autofunction:: javabridge.kill_vm 11 | 12 | .. py:data:: javabridge.JARS 13 | 14 | a list of strings; gives the full path to some JAR files that should be added to the class path in order for all the feature sof the Javabridge to work properly. 15 | 16 | .. autofunction:: javabridge.activate_awt 17 | .. autofunction:: javabridge.deactivate_awt 18 | 19 | 20 | Environment 21 | +++++++++++ 22 | 23 | In order to use the Javabridge in a thread, you need to attach to the JVM's environment in that thread. In order for the garbage collector to be able to collect thread-local variables, it is also necessary to detach from the environment before the thread ends. 24 | 25 | .. autofunction:: javabridge.attach 26 | .. autofunction:: javabridge.detach 27 | 28 | 29 | 30 | Without GUI (headless mode) 31 | --------------------------- 32 | 33 | Using the JVM in headless mode is straighforward:: 34 | 35 | import os 36 | import javabridge 37 | 38 | javabridge.start_vm(run_headless=True) 39 | try: 40 | print javabridge.run_script('java.lang.String.format("Hello, %s!", greetee);', 41 | dict(greetee='world')) 42 | finally: 43 | javabridge.kill_vm() 44 | 45 | With GUI on the Java side 46 | ------------------------- 47 | 48 | Using the JVM with a graphical user interface is much more involved 49 | because you have to run an event loop on the Python side. You also 50 | have to make sure that everything executes in the proper thread; in 51 | particular, all GUI operations have to run in the main thread on Mac 52 | OS X. Here is an example, using a wxPython app to provide the event loop:: 53 | 54 | import os 55 | import wx 56 | import javabridge 57 | 58 | javabridge.start_vm() 59 | 60 | class EmptyApp(wx.App): 61 | def OnInit(self): 62 | javabridge.activate_awt() 63 | return True 64 | 65 | try: 66 | 67 | app = EmptyApp(False) 68 | 69 | # Must exist (perhaps the app needs to have a top-level window?), but 70 | # does not have to be shown. 71 | frame = wx.Frame(None) 72 | 73 | javabridge.execute_runnable_in_main_thread(javabridge.run_script(""" 74 | new java.lang.Runnable() { 75 | run: function() { 76 | with(JavaImporter(java.awt.Frame)) Frame().setVisible(true); 77 | } 78 | };""")) 79 | 80 | app.MainLoop() 81 | 82 | finally: 83 | 84 | javabridge.kill_vm() 85 | 86 | With GUI on both the Java side and the Python side 87 | -------------------------------------------------- 88 | 89 | Finally, an example combining AWT for GUI on the Java side with 90 | wxPython for GUI on the Python side:: 91 | 92 | import os 93 | import wx 94 | import javabridge 95 | 96 | class EmptyApp(wx.PySimpleApp): 97 | def OnInit(self): 98 | javabridge.activate_awt() 99 | 100 | return True 101 | 102 | javabridge.start_vm() 103 | 104 | try: 105 | app = EmptyApp(False) 106 | 107 | frame = wx.Frame(None) 108 | frame.Sizer = wx.BoxSizer(wx.HORIZONTAL) 109 | launch_button = wx.Button(frame, label="Launch AWT frame") 110 | frame.Sizer.Add(launch_button, 1, wx.ALIGN_CENTER_HORIZONTAL) 111 | 112 | def fn_launch_frame(event): 113 | javabridge.execute_runnable_in_main_thread(javabridge.run_script(""" 114 | new java.lang.Runnable() { 115 | run: function() { 116 | with(JavaImporter(java.awt.Frame)) Frame().setVisible(true); 117 | } 118 | };""")) 119 | launch_button.Bind(wx.EVT_BUTTON, fn_launch_frame) 120 | 121 | frame.Layout() 122 | frame.Show() 123 | app.MainLoop() 124 | 125 | finally: 126 | 127 | javabridge.kill_vm() 128 | 129 | -------------------------------------------------------------------------------- /docs/unittesting.rst: -------------------------------------------------------------------------------- 1 | .. _unit-testing: 2 | 3 | Unit testing 4 | ============ 5 | 6 | Unit testing of code that uses the Javabridge requires special care because the JVM can only be run once: after you kill it, it cannot be restarted. Therefore, the JVM cannot be started and stopped in the regular ``setUp()`` and ``tearDown()`` methods. 7 | 8 | We provide a plugin to `Nose `_ that 9 | takes care of starting and stopping the JVM. The plugin's name is 10 | ``javabridge.noseplugin``. Installing the Javabridge adds the plugin 11 | to Nose. 12 | 13 | To use the plugin for your own project, in the ``[nosetests]`` section 14 | to your ``setup.cfg``, add ``with-javabridge = True``. You can also 15 | specify a classpath; the jar files required for javabridge to function 16 | (:py:data:`javabridge.JARS`) will be added to this path:: 17 | 18 | [nosetests] 19 | with-javabridge = True 20 | classpath = my-project/jars/foo.jar 21 | 22 | You should then be able to run the ``nosetests`` command:: 23 | 24 | nosetests 25 | 26 | On some installations, setuptools's nosetests command will also work:: 27 | 28 | python setup.py nosetests 29 | 30 | If you prefer, these options can also be given on the command line:: 31 | 32 | nosetests --with-javabridge=True --classpath=my-project/jars/foo.jar 33 | 34 | or:: 35 | 36 | python setup.py nosetests --with-javabridge=True --classpath=my-project/jars/foo.jar 37 | -------------------------------------------------------------------------------- /java/org/cellprofiler/findlibjvm.java: -------------------------------------------------------------------------------- 1 | // Code adapted from http://markmail.org/message/4kh7yqwbipdgjwxa 2 | 3 | import java.io.File; 4 | 5 | class findlibjvm 6 | { 7 | public static void main(String args[]) 8 | { 9 | String java_library_path = System.getProperty("java.library.path"); 10 | String [] paths = java_library_path.split(":"); 11 | for (String path:paths) { 12 | File f = new File(path, "libjvm.so"); 13 | if (f.exists()) { 14 | System.out.println(path); 15 | break; 16 | } 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /java/org/cellprofiler/javabridge/CPython.java: -------------------------------------------------------------------------------- 1 | /* python-javabridge is licensed under the BSD license. See the 2 | * accompanying file LICENSE for details. 3 | 4 | * Copyright (c) 2003-2009 Massachusetts Institute of Technology 5 | * Copyright (c) 2009-2015 Broad Institute 6 | * All rights reserved. 7 | */ 8 | 9 | package org.cellprofiler.javabridge; 10 | 11 | import java.io.File; 12 | import java.util.Arrays; 13 | import java.util.Collections; 14 | import java.util.List; 15 | import java.util.Map; 16 | import java.util.logging.Logger; 17 | import java.lang.reflect.Field; 18 | 19 | /** 20 | * @author Lee Kamentsky 21 | * 22 | * The CPython class manages an in-process 23 | * C Python instance, allowing Java code to execute 24 | * and evaluate scripts. 25 | */ 26 | public class CPython { 27 | private static final Logger log = Logger.getLogger(CPython.class.getName()); 28 | /** 29 | * A StackFrame records a frame of a Python stack, 30 | * for instance as reported by a WrappedException 31 | */ 32 | public static class StackFrame { 33 | /** 34 | * The path to the Python file holding the code being 35 | * executed by the frame 36 | */ 37 | public final String fileName; 38 | /** 39 | * The line number being executed 40 | */ 41 | public final int lineNumber; 42 | /** 43 | * The name of the function being executed 44 | */ 45 | public final String functionName; 46 | /** 47 | * The text of the line of code at the line being executed. 48 | */ 49 | public final String codeContext; 50 | public StackFrame(String fileName, int lineNumber, String functionName, String codeContext) { 51 | this.fileName = fileName; 52 | this.lineNumber = lineNumber; 53 | this.functionName = functionName; 54 | this.codeContext = codeContext; 55 | } 56 | }; 57 | /** 58 | * A wrapping of a Python exception, thrown during 59 | * evaluation or execution of a Python script. 60 | */ 61 | public static class WrappedException extends Exception { 62 | /** 63 | * The CPython type of the exception, for instance as 64 | * reported by "type(exception)". 65 | */ 66 | public final String type; 67 | /** 68 | * The stack traceback from the point where the exception was raised. 69 | * The frames are arranged with the immediate location of the exception 70 | * as index zero and calling frames at successively higher indices. 71 | */ 72 | public final List traceback; 73 | WrappedException(String message, String type, List traceback) { 74 | super(message); 75 | this.type = type; 76 | this.traceback = Collections.unmodifiableList(traceback); 77 | } 78 | } 79 | static { 80 | final String pathSeparator = System.getProperty("path.separator"); 81 | final String classPaths = System.getProperty("java.class.path"); 82 | String oldLibraryPath = null; 83 | 84 | for (String classPath:classPaths.split(pathSeparator)) { 85 | if (classPath.toLowerCase().endsWith("cpython.jar")) { 86 | File file = new File(classPath); 87 | final String libraryPath = file.getParent(); 88 | /* 89 | * The following is based on: 90 | * 91 | * http://stackoverflow.com/questions/15409223/adding-new-paths-for-native-libraries-at-runtime-in-java 92 | */ 93 | try { 94 | final Field usrPathsField = ClassLoader.class.getDeclaredField("usr_paths"); 95 | usrPathsField.setAccessible(true); 96 | final String [] paths = (String[])usrPathsField.get(null); 97 | boolean hasPath = false; 98 | for (String path:paths) { 99 | if (path.equalsIgnoreCase(libraryPath)) { 100 | hasPath = true; 101 | break; 102 | } 103 | } 104 | if (! hasPath) { 105 | final String[] newPaths = Arrays.copyOf(paths, paths.length + 1); 106 | newPaths[newPaths.length-1] = libraryPath; 107 | usrPathsField.set(null, newPaths); 108 | } 109 | } catch (Exception e) { 110 | log.warning(e.getMessage()); 111 | } 112 | System.setProperty("java.library.path", libraryPath); 113 | break; 114 | } 115 | } 116 | 117 | System.loadLibrary("java2cpython"); 118 | if (oldLibraryPath != null) { 119 | System.setProperty("java.library.path", oldLibraryPath); 120 | } 121 | } 122 | /** 123 | * Execute a Python script (synonym for CPython.exec needed because 124 | * "exec" is a Python keyword. 125 | */ 126 | public void execute(String script) throws WrappedException { 127 | exec(script, null, null); 128 | } 129 | /** 130 | * Execute a Python script (synonym for CPython.exec needed because 131 | * "exec" is a Python keyword. 132 | */ 133 | public void execute(String script, Map locals, Map globals) 134 | throws WrappedException { 135 | exec(script, locals, globals); 136 | } 137 | /** 138 | * Execute a Python script 139 | * 140 | * @param script - the Python to be executed 141 | */ 142 | public void exec(String script) throws WrappedException { 143 | exec(script, null, null); 144 | } 145 | /** 146 | * Execute a Python script, passing a local and global execution context 147 | * 148 | * @param script - the Python script to be executed 149 | * @param locals - the execution context local to the execution frame of the script 150 | * @param globals - the execution context accessible by all frames of the script 151 | * 152 | * You can retrieve values by passing a container as one of the locals, for instance 153 | * 154 | * locals = new HashMap(); 155 | * locals.put("answer", new ArrayList()); 156 | * new CPython().exec("import javabridge; janswer=javabridge.JWrapper(answer);janswer.add(1+1)"); 157 | * assert(locals.get("answer").equals(2)); 158 | */ 159 | public native void exec(String script, Map locals, Map globals) 160 | throws WrappedException; 161 | } -------------------------------------------------------------------------------- /java/org/cellprofiler/javabridge/CPythonInvocationHandler.java: -------------------------------------------------------------------------------- 1 | /* python-javabridge is licensed under the BSD license. See the 2 | * accompanying file LICENSE for details. 3 | 4 | * Copyright (c) 2003-2009 Massachusetts Institute of Technology 5 | * Copyright (c) 2009-2015 Broad Institute 6 | * All rights reserved. 7 | */ 8 | 9 | package org.cellprofiler.javabridge; 10 | 11 | import java.lang.reflect.InvocationHandler; 12 | import java.lang.reflect.Method; 13 | import java.util.Hashtable; 14 | import java.util.ArrayList; 15 | import org.cellprofiler.javabridge.CPython; 16 | 17 | /** 18 | * @author Lee Kamentsky 19 | * 20 | * The CPythonInvocationHandler reflects an invocation 21 | * to a Python object that implements the call interface 22 | */ 23 | public class CPythonInvocationHandler implements InvocationHandler { 24 | private final String ref_id; 25 | private final CPython cpython = new CPython(); 26 | /** 27 | * Constructor 28 | * 29 | * @param ref_id the reference to the Python callable, for instance as 30 | * returned by javabridge.create_jref 31 | */ 32 | public CPythonInvocationHandler(String ref_id) { 33 | this.ref_id = ref_id; 34 | } 35 | @Override 36 | public Object invoke(Object proxy, Method method, Object [] args) throws Throwable { 37 | final String script = 38 | "import javabridge\n" + 39 | String.format("result = javabridge.redeem_jref('%s')(proxy, method, args);\n", ref_id) + 40 | "javabridge.call(jresult, 'add', '(Ljava/lang/Object;)Z', result)"; 41 | final Hashtable locals = new Hashtable(); 42 | locals.put("proxy", proxy); 43 | locals.put("method", method); 44 | if (args == null) { 45 | args = new Object [0]; 46 | } 47 | locals.put("args", args); 48 | ArrayList result = new ArrayList(); 49 | locals.put("jresult", result); 50 | cpython.exec(script, locals, locals); 51 | return result.get(0); 52 | } 53 | } -------------------------------------------------------------------------------- /java/org/cellprofiler/javabridge/test/RealRect.java: -------------------------------------------------------------------------------- 1 | // A class with public fields. This exists only in order to test 2 | // the get_field() and set_field() function in the Javabridge. 3 | 4 | package org.cellprofiler.javabridge.test; 5 | 6 | public class RealRect { 7 | 8 | // -- Fields -- 9 | 10 | public double x; 11 | public double y; 12 | public double width; 13 | public double height; 14 | public char f_char; 15 | public byte f_byte; 16 | public short f_short; 17 | public int f_int; 18 | public long f_long; 19 | public float f_float; 20 | public double f_double; 21 | public Object f_object; 22 | static public char fs_char; 23 | static public byte fs_byte; 24 | static public short fs_short; 25 | static public int fs_int; 26 | static public long fs_long; 27 | static public float fs_float; 28 | static public double fs_double; 29 | static public Object fs_object; 30 | 31 | // -- Constructor -- 32 | 33 | public RealRect() { 34 | // default constructor - allow all instance vars to be initialized to 0 35 | } 36 | 37 | public RealRect(final double x, final double y, final double width, 38 | final double height) 39 | { 40 | this.x = x; 41 | this.y = y; 42 | this.width = width; 43 | this.height = height; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /java/org/cellprofiler/javabridge/test/TestCPython.java: -------------------------------------------------------------------------------- 1 | /** 2 | * python-javabridge is licensed under the BSD license. See the 3 | * accompanying file LICENSE for details. 4 | * 5 | * Copyright (c) 2003-2009 Massachusetts Institute of Technology 6 | * Copyright (c) 2009-2015 Broad Institute 7 | * All rights reserved. 8 | * 9 | */ 10 | 11 | package org.cellprofiler.javabridge.test; 12 | 13 | import org.junit.Test; 14 | import static org.junit.Assert.*; 15 | import org.cellprofiler.javabridge.CPython; 16 | 17 | public class TestCPython { 18 | @Test 19 | public void test_01_01_exec() { 20 | try { 21 | new CPython().exec("print('Hello, world.')\n"); 22 | } catch (CPython.WrappedException e) { 23 | fail(); 24 | } 25 | } 26 | @Test 27 | public void test_02_01_threading() { 28 | /* 29 | * Regression test for issue #104 - call into Python 30 | * from Java, start a Python thread, attach to the Java VM. 31 | * VM pointer wasn't being initialized, so it dies. 32 | */ 33 | String code = 34 | "import javabridge\n" + 35 | "import threading\n" + 36 | "print('yes I did run')\n" + 37 | "def do_something()\n" + 38 | " print('from inside thread')\n" + 39 | " system = javabridge.JClassWrapper('java.lang.System')\n" + 40 | " system.setProperty('foo', 'bar')\n" + 41 | "thread=threading.Thread(target=do_something)\n" + 42 | "thread.start()\n" + 43 | "thread.join()\n" + 44 | "print('yes I did finish')\n"; 45 | try { 46 | System.out.print(code); 47 | new CPython().exec(code); 48 | } catch (CPython.WrappedException e) { 49 | fail(); 50 | } 51 | System.out.println("Yes I did return"); 52 | assertEquals(System.getProperty("foo"), "bar"); 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /java/org/cellprofiler/runnablequeue/RunnableQueue.java: -------------------------------------------------------------------------------- 1 | /** 2 | * python-javabridge is licensed under the BSD license. See the 3 | * accompanying file LICENSE for details. 4 | * 5 | * Copyright (c) 2003-2009 Massachusetts Institute of Technology 6 | * Copyright (c) 2009-2013 Broad Institute 7 | * All rights reserved. 8 | * 9 | */ 10 | 11 | package org.cellprofiler.runnablequeue; 12 | 13 | import java.util.concurrent.Callable; 14 | import java.util.concurrent.ExecutionException; 15 | import java.util.concurrent.Executor; 16 | import java.util.concurrent.FutureTask; 17 | import java.util.concurrent.Semaphore; 18 | import java.util.concurrent.SynchronousQueue; 19 | 20 | /** 21 | * @author Leek 22 | * 23 | * This class is solely designed to operate a single instance 24 | * on the main thread to allow other threads to run runnables 25 | * on that thread. 26 | * 27 | * Use something like FutureTask if you need to return a 28 | * result or synchronize to the completion of the submitted 29 | * runnable. 30 | * 31 | */ 32 | public class RunnableQueue implements Runnable { 33 | private static SynchronousQueue queue = new SynchronousQueue(); 34 | 35 | /* (non-Javadoc) 36 | * @see java.lang.Runnable#run() 37 | */ 38 | public void run() { 39 | try { 40 | while (true) { 41 | Runnable task = queue.take(); 42 | task.run(); 43 | } 44 | } catch (InterruptedException e) { 45 | // System.out.println("Exiting RunnableQueue."); 46 | } 47 | } 48 | 49 | /** 50 | * Enqueue a runnable to be executed on the thread. 51 | * 52 | * Put the runnable on the main thread's queue and return 53 | * asynchronous to the runnable's execution. 54 | * 55 | * @param runnable - run this runnable. 56 | * @throws InterruptedException on thread interruption 57 | */ 58 | static public void enqueue(Runnable runnable) throws InterruptedException { 59 | queue.put(new FutureTask(runnable, null)); 60 | } 61 | 62 | /** 63 | * Execute a runnable synchronously. 64 | * 65 | * @param runnable - runnable to be executed 66 | * @throws InterruptedException if thread was interrupted while enqueueing runnable 67 | * @throws ExecutionException if there was an exception while running the runnable 68 | */ 69 | static public void execute(Runnable runnable) throws InterruptedException, ExecutionException { 70 | FutureTask future = new FutureTask(runnable, null); 71 | enqueue(future); 72 | future.get(); 73 | } 74 | 75 | /** 76 | * Execute a callable synchronously returning the callable's result. 77 | * 78 | * @param the type of result to be returned 79 | * @param callable the callable to be executed on the main thread 80 | * @return the result of the callable's execution 81 | * 82 | * @throws InterruptedException 83 | * @throws ExecutionException 84 | */ 85 | static public V execute(Callable callable) throws InterruptedException, ExecutionException { 86 | FutureTask future = new FutureTask(callable); 87 | enqueue(future); 88 | return future.get(); 89 | } 90 | 91 | /** 92 | * Stop the main thread. 93 | * 94 | * @throws InterruptedException if this thread was waiting for initialization and was interrupted. 95 | * @throws ExecutionException 96 | */ 97 | static public void stop() throws InterruptedException, ExecutionException { 98 | Runnable r = new Runnable() { 99 | 100 | public void run() { 101 | Thread.currentThread().interrupt(); 102 | } 103 | 104 | }; 105 | execute(r); 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /java/org/cellprofiler/runnablequeue/TestRunnableQueue.java: -------------------------------------------------------------------------------- 1 | /** 2 | * python-javabridge is licensed under the BSD license. See the 3 | * accompanying file LICENSE for details. 4 | * 5 | * Copyright (c) 2003-2009 Massachusetts Institute of Technology 6 | * Copyright (c) 2009-2013 Broad Institute 7 | * All rights reserved. 8 | * 9 | */ 10 | 11 | package org.cellprofiler.runnablequeue; 12 | 13 | import java.util.concurrent.Callable; 14 | import java.util.concurrent.ExecutionException; 15 | import java.util.concurrent.Semaphore; 16 | 17 | import junit.framework.AssertionFailedError; 18 | 19 | import org.junit.After; 20 | import org.junit.Before; 21 | import org.junit.Test; 22 | import static org.junit.Assert.*; 23 | 24 | public class TestRunnableQueue { 25 | Thread t; 26 | @Before 27 | public void setUp() { 28 | RunnableQueue rq = new RunnableQueue(); 29 | t = new Thread(rq); 30 | t.start(); 31 | } 32 | 33 | @After 34 | public void tearDown() { 35 | try { 36 | RunnableQueue.stop(); 37 | t.join(); 38 | } catch (InterruptedException e) { 39 | throw new AssertionError("Thread unexpectedly interrupted during join"); 40 | } catch (ExecutionException e) { 41 | throw new AssertionError("Stop's runnable unexpectedly threw an exception."); 42 | } 43 | } 44 | 45 | @Test 46 | public void testStartStop() { 47 | } 48 | 49 | @Test 50 | public void testEnqueue() { 51 | final String [] putSomethingHere = new String [] { null }; 52 | final String something = "Something"; 53 | 54 | Runnable myRunnable = new Runnable() { 55 | public void run() { 56 | synchronized(this) { 57 | putSomethingHere[0] = something; 58 | this.notify(); 59 | } 60 | } 61 | }; 62 | try { 63 | RunnableQueue.enqueue(myRunnable); 64 | synchronized(myRunnable) { 65 | while (putSomethingHere[0] == null) { 66 | myRunnable.wait(); 67 | } 68 | } 69 | } catch (InterruptedException e) { 70 | throw new AssertionError("Thread unexpectedly interrupted during enqueue"); 71 | } 72 | assertEquals(putSomethingHere[0], something); 73 | } 74 | @Test 75 | public void testExecute() { 76 | final String [] putSomethingHere = new String [] { null }; 77 | final String something = "Something"; 78 | 79 | Runnable myRunnable = new Runnable() { 80 | public void run() { 81 | putSomethingHere[0] = something; 82 | } 83 | }; 84 | try { 85 | RunnableQueue.execute(myRunnable); 86 | } catch (InterruptedException e) { 87 | throw new AssertionError("Thread unexpectedly interrupted during enqueue"); 88 | } catch (ExecutionException e) { 89 | throw new AssertionError("Runnable unexpectedly threw an exception"); 90 | } 91 | assertEquals(putSomethingHere[0], something); 92 | } 93 | @Test 94 | public void testExecuteV() { 95 | final String something = "Something"; 96 | Callable myCallable = new Callable() { 97 | 98 | public String call() throws Exception { 99 | return something; 100 | } 101 | }; 102 | try { 103 | assertEquals(RunnableQueue.execute(myCallable), something); 104 | } catch (InterruptedException e) { 105 | throw new AssertionError("Thread unexpectedly interrupted during enqueue"); 106 | } catch (ExecutionException e) { 107 | throw new AssertionError("Runnable unexpectedly threw an exception"); 108 | } 109 | } 110 | @Test 111 | public void testExceptionProof(){ 112 | Runnable myRunnable = new Runnable() { 113 | public void run() { 114 | int [] a = new int [] { 1, 2, 3 }; 115 | @SuppressWarnings("unused") 116 | int b = a[a.length]; 117 | } 118 | }; 119 | try { 120 | RunnableQueue.enqueue(myRunnable); 121 | } catch (InterruptedException e) { 122 | throw new AssertionError("Thread unexpectedly interrupted during enqueue"); 123 | } 124 | testEnqueue(); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /java/org_cellprofiler_javabridge_CPython.c: -------------------------------------------------------------------------------- 1 | /* 2 | python-javabridge is licensed under the BSD license. See the 3 | accompanying file LICENSE for details. 4 | 5 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 6 | Copyright (c) 2009-2013 Broad Institute 7 | All rights reserved. 8 | */ 9 | 10 | #include 11 | #include 12 | #include 13 | #ifdef __linux__ 14 | #include 15 | #include 16 | #endif 17 | #include "org_cellprofiler_javabridge_CPython.h" 18 | 19 | int initialized = 0; 20 | static void check_init(void); 21 | 22 | #ifdef __linux__ 23 | /* 24 | * On Linux, it appears that Python's symbols cannot be found by other 25 | * native libraries if we let the JVM load libpython... so we have to load it 26 | * explicitly, with the correct flag (RTLD_GLOBAL). 27 | */ 28 | 29 | static char *get_property(JavaVM *vm, const char *key) 30 | { 31 | JNIEnv *pEnv; 32 | jclass system; 33 | jmethodID get; 34 | jstring string; 35 | const char *characters; 36 | char *result; 37 | 38 | if ((*vm)->GetEnv(vm, (void **)&pEnv, JNI_VERSION_1_2) != JNI_OK) { 39 | fprintf(stderr, "Could not obtain JNI environment\n"); 40 | return NULL; 41 | } 42 | 43 | if (!(system = (*pEnv)->FindClass(pEnv, "java/lang/System"))) { 44 | fprintf(stderr, "Could not access System class\n"); 45 | return NULL; 46 | } 47 | 48 | if (!(get = (*pEnv)->GetStaticMethodID(pEnv, system, "getProperty", 49 | "(Ljava/lang/String;)Ljava/lang/String;"))) { 50 | fprintf(stderr, "Could not find getProperty method\n"); 51 | return NULL; 52 | } 53 | 54 | if (!(string = (jstring)(*pEnv)->CallStaticObjectMethod(pEnv, system, 55 | get, (*pEnv)->NewStringUTF(pEnv, key)))) 56 | return NULL; 57 | 58 | characters = (*pEnv)->GetStringUTFChars(pEnv, string, NULL); 59 | result = strdup(characters); 60 | (*pEnv)->ReleaseStringUTFChars(pEnv, string, characters); 61 | 62 | (*vm)->DetachCurrentThread(vm); 63 | 64 | return result; 65 | } 66 | #endif 67 | JavaVM *pVM; 68 | 69 | JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) 70 | { 71 | #ifdef __linux__ 72 | char buf[1024]; 73 | char *python_location = get_property(vm, "python.location"); 74 | const char *command = "python -c \"import sysconfig; from os.path import join; print(join(sysconfig.get_config_var('LIBDIR'), sysconfig.get_config_var('multiarchsubdir')[1:], sysconfig.get_config_var('LDLIBRARY')))\""; 75 | 76 | if (!python_location) { 77 | size_t len=1024; 78 | FILE *stream = popen(command, "r"); 79 | python_location = buf; 80 | getline(&python_location, &len, stream); 81 | python_location[strlen(python_location)-1] = 0; 82 | pclose(stream); 83 | } 84 | if (!dlopen(python_location, RTLD_LAZY | RTLD_GLOBAL)) 85 | fprintf(stderr, "Warning: Error loading %s\n", python_location); 86 | #endif 87 | pVM = vm; 88 | return JNI_VERSION_1_2; 89 | } 90 | /* 91 | * Run some code here to encapsulate a pointer to the VM and call 92 | * import javabridge 93 | * javabridge.jvm_enter(capsule) 94 | * 95 | */ 96 | static int set_vm(void) 97 | { 98 | PyObject *pPyVM; 99 | PyObject *pJavabridge; 100 | PyObject *pJVMEnter; 101 | PyObject *pArgs; 102 | PyObject *pResult; 103 | 104 | pPyVM = PyCapsule_New((void *)pVM, NULL, NULL); 105 | if (PyErr_Occurred()) { 106 | fprintf(stderr, "Unable to encapsulate VM for Python.\n"); 107 | return -1; 108 | } 109 | pJavabridge = PyImport_ImportModule("javabridge"); 110 | if (PyErr_Occurred()) { 111 | fprintf(stderr, "Failed to import javabridge.\n"); 112 | Py_DECREF(pPyVM); 113 | return -1; 114 | } 115 | pJVMEnter = PyObject_GetAttrString(pJavabridge, "jvm_enter"); 116 | if (PyErr_Occurred()) { 117 | fprintf(stderr, "Failed to find function, javabridge.jvm_enter\n"); 118 | Py_DECREF(pJavabridge); 119 | Py_DECREF(pPyVM); 120 | return -1; 121 | } 122 | pArgs = PyTuple_Pack(1, pPyVM); 123 | if (! pArgs) { 124 | fprintf(stderr, "Failed to create the arguments for jvm_enter\n"); 125 | Py_DECREF(pJVMEnter); 126 | Py_DECREF(pJavabridge); 127 | Py_DECREF(pPyVM); 128 | return -1; 129 | } 130 | pResult = PyObject_CallObject(pJVMEnter, pArgs); 131 | if (! pResult) { 132 | fprintf(stderr, "Caught exception in jvm_enter.\n"); 133 | Py_DECREF(pArgs); 134 | Py_DECREF(pJVMEnter); 135 | Py_DECREF(pJavabridge); 136 | Py_DECREF(pPyVM); 137 | return -1; 138 | } 139 | Py_DECREF(pResult); 140 | Py_DECREF(pArgs); 141 | Py_DECREF(pJVMEnter); 142 | Py_DECREF(pJavabridge); 143 | Py_DECREF(pPyVM); 144 | return 0; 145 | } 146 | 147 | #ifdef _WIN32 148 | /* 149 | * If MSVC90.dll is on the path, we will perish horribly in Windows 150 | * with an R6034 exception on loading it from some of the numerous 151 | * pyd files that include it. 152 | */ 153 | const char *pCleanPath = "import os;os.environ['path']=';'.join([path for path in os.environ['path'].split(';') if 'msvcr90.dll' not in map((lambda x:x.lower()), os.listdir(path))])"; 154 | #endif 155 | static void check_init(void) { 156 | if ((initialized == 0) && ! Py_IsInitialized()) { 157 | Py_Initialize(); 158 | #ifdef _WIN32 159 | PyRun_SimpleString(pCleanPath); 160 | #endif 161 | set_vm(); 162 | initialized = 1; 163 | } 164 | } 165 | 166 | /* 167 | throwError 168 | 169 | Throw an error that indicates a problem beyond what would be caused 170 | by the evaluation or execution of Python code 171 | 172 | pEnv - JNI environment 173 | message - message to report 174 | */ 175 | static void throwError(JNIEnv *pEnv, char *message) { 176 | jclass exClass; 177 | char *className = "java/lang/Error"; 178 | 179 | exClass = (*pEnv)->FindClass(pEnv, className); 180 | if (exClass == NULL) { 181 | return; 182 | } 183 | (*pEnv)->ThrowNew(pEnv, exClass, message); 184 | PyErr_Clear(); 185 | } 186 | 187 | /* 188 | throwWrappedError 189 | 190 | Throw an exception that reflects the current Python exception into 191 | Java. 192 | */ 193 | static void throwWrappedError(JNIEnv *pEnv, int linenumber) 194 | { 195 | char buffer[1000]; 196 | /* TODO: implement*/ 197 | PyErr_Print(); 198 | snprintf(buffer, sizeof(buffer), 199 | "Python exception at %s:%d", __FILE__, linenumber); 200 | throwError(pEnv, buffer); 201 | } 202 | /* 203 | attach_env 204 | 205 | Attach the supplied environment to the javabridge thread-local context. 206 | 207 | pEnv - the environment passed via the JNI call 208 | 209 | Prerequisites: The GIL must be taken. 210 | 211 | Returns: 0 if successful, negative value on failure indicating that a 212 | Java exception has been thrown. 213 | */ 214 | static int attach_env(JNIEnv *pEnv){ 215 | PyObject *pPyEnv; 216 | PyObject *pJavabridge; 217 | PyObject *pJNIEnter; 218 | PyObject *pArgs; 219 | PyObject *pResult; 220 | /* 221 | Equivalent to: 222 | import javabridge 223 | javabridge.jni_enter(env) 224 | */ 225 | 226 | pPyEnv = PyCapsule_New((void *)pEnv, NULL, NULL); 227 | if (PyErr_Occurred()) { 228 | throwWrappedError(pEnv, __LINE__); 229 | return -1; 230 | } 231 | pJavabridge = PyImport_ImportModule("javabridge"); 232 | if (PyErr_Occurred()) { 233 | throwWrappedError(pEnv, __LINE__); 234 | Py_DECREF(pPyEnv); 235 | return -1; 236 | } 237 | pJNIEnter = PyObject_GetAttrString(pJavabridge, "jni_enter"); 238 | if (PyErr_Occurred()) { 239 | throwWrappedError(pEnv, __LINE__); 240 | Py_DECREF(pJavabridge); 241 | Py_DECREF(pPyEnv); 242 | return -1; 243 | } 244 | pArgs = PyTuple_Pack(1, pPyEnv); 245 | if (! pArgs) { 246 | throwWrappedError(pEnv, __LINE__); 247 | Py_DECREF(pJNIEnter); 248 | Py_DECREF(pJavabridge); 249 | Py_DECREF(pPyEnv); 250 | return -1; 251 | } 252 | pResult = PyObject_CallObject(pJNIEnter, pArgs); 253 | if (! pResult) { 254 | throwWrappedError(pEnv, __LINE__); 255 | Py_DECREF(pArgs); 256 | Py_DECREF(pJNIEnter); 257 | Py_DECREF(pJavabridge); 258 | Py_DECREF(pPyEnv); 259 | return -1; 260 | } 261 | Py_DECREF(pResult); 262 | Py_DECREF(pArgs); 263 | Py_DECREF(pJNIEnter); 264 | Py_DECREF(pJavabridge); 265 | Py_DECREF(pPyEnv); 266 | return 0; 267 | } 268 | 269 | /* 270 | detach_env 271 | 272 | Detach an environment previously attached using attach_env 273 | */ 274 | static int detach_env(JNIEnv *pEnv) { 275 | PyObject *pJavabridge; 276 | PyObject *pJNIExit; 277 | PyObject *pArgs; 278 | PyObject *pResult; 279 | 280 | pJavabridge = PyImport_ImportModule("javabridge"); 281 | if (! pJavabridge) { 282 | throwWrappedError(pEnv, __LINE__); 283 | return -1; 284 | } 285 | pJNIExit = PyObject_GetAttrString(pJavabridge, "jni_exit"); 286 | if (! pJNIExit) { 287 | throwWrappedError(pEnv, __LINE__); 288 | Py_DECREF(pJavabridge); 289 | return -1; 290 | } 291 | pArgs = PyTuple_New(0); 292 | if (! pArgs) { 293 | throwWrappedError(pEnv, __LINE__); 294 | Py_DECREF(pJNIExit); 295 | Py_DECREF(pJavabridge); 296 | } 297 | pResult = PyObject_CallObject(pJNIExit, pArgs); 298 | if (! pResult) { 299 | throwWrappedError(pEnv, __LINE__); 300 | Py_DECREF(pArgs); 301 | Py_DECREF(pJNIExit); 302 | Py_DECREF(pJavabridge); 303 | return -1; 304 | } 305 | Py_DECREF(pResult); 306 | Py_DECREF(pArgs); 307 | Py_DECREF(pJNIExit); 308 | Py_DECREF(pJavabridge); 309 | return 0; 310 | } 311 | 312 | static PyObject *wrapJObject(JNIEnv *pEnv, jobject j) { 313 | PyObject *pJavabridge; 314 | PyObject *pGetEnv; 315 | PyObject *pTheEnv; 316 | PyObject *pCapsule; 317 | PyObject *pResult; 318 | 319 | if (! j) { 320 | Py_RETURN_NONE; 321 | } 322 | pJavabridge = PyImport_ImportModule("javabridge"); 323 | if (! pJavabridge) { 324 | throwWrappedError(pEnv, __LINE__); 325 | return NULL; 326 | } 327 | pGetEnv = PyObject_GetAttrString(pJavabridge, "get_env"); 328 | if (! pGetEnv) { 329 | throwWrappedError(pEnv, __LINE__); 330 | Py_DECREF(pJavabridge); 331 | return NULL; 332 | } 333 | pTheEnv = PyObject_CallObject(pGetEnv, NULL); 334 | if (! pTheEnv) { 335 | throwWrappedError(pEnv, __LINE__); 336 | Py_DECREF(pGetEnv); 337 | Py_DECREF(pJavabridge); 338 | return NULL; 339 | } 340 | pCapsule = PyCapsule_New((void *)j, NULL, NULL); 341 | if (! pCapsule) { 342 | throwWrappedError(pEnv, __LINE__); 343 | Py_DECREF(pTheEnv); 344 | Py_DECREF(pGetEnv); 345 | Py_DECREF(pJavabridge); 346 | return NULL; 347 | } 348 | pResult = PyObject_CallMethod(pTheEnv, "make_jb_object", "O", pCapsule); 349 | if (! pResult) { 350 | throwWrappedError(pEnv, __LINE__); 351 | } 352 | Py_DECREF(pCapsule); 353 | Py_DECREF(pTheEnv); 354 | Py_DECREF(pGetEnv); 355 | Py_DECREF(pJavabridge); 356 | return pResult; 357 | } 358 | 359 | static PyObject *mapToDictionary(JNIEnv *pEnv, jobject map) { 360 | PyObject *pMap; 361 | PyObject *pJavabridge; 362 | PyObject *pFn; 363 | PyObject *pArgs; 364 | PyObject *pResult; 365 | 366 | if (! map) { 367 | pResult = PyDict_New(); 368 | if (! pResult) { 369 | throwWrappedError(pEnv, __LINE__); 370 | } 371 | return pResult; 372 | } 373 | pMap = wrapJObject(pEnv, map); 374 | if (! pMap) { 375 | return NULL; 376 | } 377 | pJavabridge = PyImport_ImportModule("javabridge.jutil"); 378 | if (! pJavabridge) { 379 | throwWrappedError(pEnv, __LINE__); 380 | Py_DECREF(pMap); 381 | return NULL; 382 | } 383 | pFn = PyObject_GetAttrString(pJavabridge, "make_run_dictionary"); 384 | Py_DECREF(pJavabridge); 385 | if (! pFn) { 386 | throwWrappedError(pEnv, __LINE__); 387 | Py_DECREF(pMap); 388 | return NULL; 389 | } 390 | pArgs = PyTuple_Pack(1, pMap); 391 | Py_DECREF(pMap); 392 | if (! pArgs) { 393 | throwWrappedError(pEnv, __LINE__); 394 | Py_DECREF(pFn); 395 | return NULL; 396 | } 397 | pResult = PyObject_CallObject(pFn, pArgs); 398 | Py_DECREF(pFn); 399 | Py_DECREF(pArgs); 400 | if (! pResult){ 401 | throwWrappedError(pEnv, __LINE__); 402 | return NULL; 403 | } 404 | return pResult; 405 | } 406 | 407 | /* 408 | * Add globals from __main__ to a dictionary of them. 409 | */ 410 | static int add_globals(JNIEnv *pEnv, PyObject *pGlobals) { 411 | PyObject *pMain; 412 | PyObject *pMainDict; 413 | int result; 414 | pMain = PyImport_AddModule("__main__"); 415 | if (! pMain) { 416 | throwWrappedError(pEnv, __LINE__); 417 | return -1; 418 | } 419 | pMainDict = PyModule_GetDict(pMain); 420 | result = PyDict_Merge(pGlobals, pMainDict, 0); 421 | if (result) { 422 | throwWrappedError(pEnv, __LINE__); 423 | } 424 | return result; 425 | } 426 | 427 | JNIEXPORT void JNICALL Java_org_cellprofiler_javabridge_CPython_exec 428 | (JNIEnv *pEnv, jobject thiss, jstring script, jobject locals, jobject globals) { 429 | PyGILState_STATE state; 430 | PyObject *pLocals; 431 | PyObject *pGlobals; 432 | const char *pScript; 433 | PyObject *pResult; 434 | 435 | if (! pEnv) { 436 | throwError(pEnv, "JNIEnv was null."); 437 | return; 438 | } 439 | if (! script) { 440 | throwError(pEnv, "Script was null."); 441 | return; 442 | } 443 | check_init(); 444 | state = PyGILState_Ensure(); 445 | if (attach_env(pEnv) == 0) { 446 | pLocals = mapToDictionary(pEnv, locals); 447 | if (pLocals) { 448 | if ((locals != NULL) && 449 | ((*pEnv)->IsSameObject(pEnv, locals, globals))) { 450 | pGlobals = pLocals; 451 | Py_INCREF(pGlobals); 452 | } else { 453 | pGlobals = mapToDictionary(pEnv, globals); 454 | } 455 | if (pGlobals) { 456 | if (! add_globals(pEnv, pGlobals)) { 457 | pScript = (*pEnv)->GetStringUTFChars(pEnv, script, NULL); 458 | pResult = PyRun_String( 459 | pScript, Py_file_input, pGlobals, pLocals); 460 | (*pEnv)->ReleaseStringUTFChars(pEnv, script, NULL); 461 | if (pResult) { 462 | Py_DECREF(pResult); 463 | } else { 464 | throwWrappedError(pEnv, __LINE__); 465 | } 466 | } 467 | Py_DECREF(pGlobals); 468 | } 469 | Py_DECREF(pLocals); 470 | } 471 | } 472 | detach_env(pEnv); 473 | PyGILState_Release(state); 474 | } 475 | -------------------------------------------------------------------------------- /java/org_cellprofiler_javabridge_CPython.h: -------------------------------------------------------------------------------- 1 | /* DO NOT EDIT THIS FILE - it is machine generated */ 2 | #include 3 | /* Header for class org_cellprofiler_javabridge_CPython */ 4 | 5 | #ifndef _Included_org_cellprofiler_javabridge_CPython 6 | #define _Included_org_cellprofiler_javabridge_CPython 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | /* 11 | * Class: org_cellprofiler_javabridge_CPython 12 | * Method: exec 13 | * Signature: (Ljava/lang/String;Ljava/util/Map;Ljava/util/Map;)V 14 | */ 15 | JNIEXPORT void JNICALL Java_org_cellprofiler_javabridge_CPython_exec 16 | (JNIEnv *, jobject, jstring, jobject, jobject); 17 | 18 | #ifdef __cplusplus 19 | } 20 | #endif 21 | #endif 22 | -------------------------------------------------------------------------------- /javabridge/__init__.py: -------------------------------------------------------------------------------- 1 | """__init__.py - the javabridge package 2 | 3 | python-javabridge is licensed under the BSD license. See the 4 | accompanying file LICENSE for details. 5 | 6 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 7 | Copyright (c) 2009-2013 Broad Institute 8 | All rights reserved. 9 | 10 | """ 11 | 12 | import os.path 13 | 14 | try: 15 | from _version import __version__ 16 | except ImportError: 17 | # We're running in a tree that doesn't have a _version.py, so we don't know what our version is. 18 | __version__ = "0.0.0" 19 | 20 | # We must dynamically find libjvm.so since its unlikely to be in the same place 21 | # as it was on the distribution on which javabridge was built. 22 | import sys 23 | if sys.platform.startswith('linux'): 24 | from .locate import find_jre_bin_jdk_so 25 | _, jdk_so = find_jre_bin_jdk_so() 26 | if jdk_so: 27 | import ctypes 28 | ctypes.cdll.LoadLibrary(jdk_so) 29 | 30 | _jars_dir = os.path.join(os.path.dirname(__file__), 'jars') 31 | 32 | #: List of absolute paths to JAR files that are required for the 33 | #: Javabridge to work. 34 | JARS = [os.path.realpath(os.path.join(_jars_dir, name + '.jar')) 35 | for name in ['rhino-1.7R4', 'runnablequeue', 'cpython']] 36 | 37 | 38 | from .jutil import start_vm, kill_vm, vm, activate_awt, deactivate_awt 39 | 40 | from .jutil import attach, detach, get_env 41 | 42 | 43 | # JavaScript 44 | from .jutil import run_script, unwrap_javascript 45 | 46 | 47 | # Operations on Java objects 48 | from .jutil import call, get_static_field, static_call, \ 49 | is_instance_of, make_instance, set_static_field, to_string, \ 50 | get_field, set_field, make_static_call 51 | 52 | # Make Python object that wraps a Java object 53 | from .jutil import make_method, make_new, make_call, box 54 | from .wrappers import JWrapper, JClassWrapper, JProxy 55 | 56 | from .jutil import get_nice_arg 57 | 58 | # Useful collection wrappers 59 | from .jutil import get_dictionary_wrapper, jdictionary_to_string_dictionary, \ 60 | jenumeration_to_string_list, get_enumeration_wrapper, iterate_collection, \ 61 | iterate_java, make_list, get_collection_wrapper, make_future_task, \ 62 | make_map, get_map_wrapper 63 | 64 | # Reflection. (These use make_method or make_new internally.) 65 | from .jutil import get_class_wrapper, get_field_wrapper, class_for_name, \ 66 | get_constructor_wrapper, get_method_wrapper 67 | 68 | # Ensure that callables, runnables and futures that use AWT run in the 69 | # AWT main thread, which is not accessible from Python. 70 | from .jutil import execute_callable_in_main_thread, \ 71 | execute_runnable_in_main_thread, execute_future_in_main_thread, \ 72 | get_future_wrapper 73 | 74 | # Exceptions 75 | from .jutil import JavaError, JavaException, JVMNotFoundError 76 | 77 | from ._javabridge import mac_enter_run_loop, mac_stop_run_loop, mac_run_loop_init 78 | 79 | # References 80 | from .jutil import create_jref, redeem_jref, create_and_lock_jref,\ 81 | lock_jref, unlock_jref 82 | 83 | # Don't expose: AtExit, get_nice_args, 84 | # make_run_dictionary, run_in_main_thread, split_sig, unwrap_javascript, 85 | # print_all_stack_traces 86 | 87 | 88 | # Low-level API 89 | from ._javabridge import JB_Env, JB_Object, JB_Class 90 | # JNI helpers. 91 | from ._javabridge import jni_enter, jni_exit, jvm_enter 92 | -------------------------------------------------------------------------------- /javabridge/jars/rhino-1.7R4.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeeKamentsky/python-javabridge/8fd52f1966ccabe04e51e00393846fd3b25aa8ce/javabridge/jars/rhino-1.7R4.jar -------------------------------------------------------------------------------- /javabridge/locate.py: -------------------------------------------------------------------------------- 1 | """locate.py - determine architecture and find Java 2 | 3 | python-javabridge is licensed under the BSD license. See the 4 | accompanying file LICENSE for details. 5 | 6 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 7 | Copyright (c) 2009-2013 Broad Institute 8 | All rights reserved.lo 9 | 10 | """ 11 | 12 | import ctypes 13 | import os 14 | import sys 15 | import logging 16 | import subprocess 17 | import re 18 | 19 | # Note: if a matching gcc is available from the shell on Windows, its 20 | # probably safe to assume the user is in an MINGW or MSYS or Cygwin 21 | # environment, in which case he/she wants to compile with gcc for 22 | # Windows, in which case the correct compiler flags will be triggered 23 | # by is_mingw. This method is not great, improve it if you know a 24 | # better way to discriminate between compilers on Windows. 25 | def is_mingw(): 26 | # currently this check detects mingw only on Windows. Extend for other 27 | # platforms if required: 28 | if (os.name != "nt"): 29 | return False 30 | 31 | # if the user defines DISTUTILS_USE_SDK or MSSdk, we expect they want 32 | # to use Microsoft's compiler (as described here: 33 | # https://github.com/cython/cython/wiki/CythonExtensionsOnWindows): 34 | if (os.getenv("DISTUTILS_USE_SDK") != None or os.getenv("MSSdk") != None): 35 | return False 36 | 37 | mingw32 = "" 38 | mingw64 = "" 39 | if (os.getenv("MINGW32_PREFIX")): 40 | mingw32 = os.getenv("MINGW32_PREFIX") 41 | if (os.getenv("MINGW64_PREFIX")): 42 | mingw64 = os.getenv("MINGW64_PREFIX") 43 | 44 | # if any invocation of gcc works, then we assume the user wants mingw: 45 | test = "gcc --version > NUL 2>&1" 46 | if (os.system(test) == 0 or os.system(mingw32+test) == 0 or os.system(mingw64+test) == 0): 47 | return True 48 | 49 | return False 50 | 51 | 52 | 53 | is_linux = sys.platform.startswith('linux') 54 | is_mac = sys.platform == 'darwin' 55 | is_win = sys.platform.startswith("win") 56 | is_win64 = (is_win and (os.environ["PROCESSOR_ARCHITECTURE"] == "AMD64")) 57 | is_msvc = (is_win and 58 | ((sys.version_info.major == 2 and sys.version_info.minor >= 6) or 59 | (sys.version_info.major == 3))) 60 | is_mingw = is_mingw() 61 | 62 | if is_win: 63 | if sys.version_info.major == 2: 64 | import _winreg as winreg 65 | from exceptions import WindowsError 66 | else: 67 | import winreg 68 | 69 | logger = logging.getLogger(__name__) 70 | 71 | def find_javahome(): 72 | """Find JAVA_HOME if it doesn't exist""" 73 | if 'JAVA_HOME' in os.environ: 74 | return os.environ['JAVA_HOME'] 75 | elif is_mac: 76 | # Use the "java_home" executable to find the location 77 | # see "man java_home" 78 | libc = ctypes.CDLL("/usr/lib/libc.dylib") 79 | if sys.maxsize <= 2**32: 80 | arch = "i386" 81 | else: 82 | arch = "x86_64" 83 | try: 84 | result = subprocess.check_output(["/usr/libexec/java_home", "--arch", arch]) 85 | path = result.strip().decode("utf-8") 86 | for place_to_look in ( 87 | os.path.join(os.path.dirname(path), "Libraries"), 88 | os.path.join(path, "jre", "lib", "server")): 89 | # In "Java for OS X 2015-001" libjvm.dylib is a symlink to libclient.dylib 90 | # which is i686 only, whereas libserver.dylib contains both architectures. 91 | for file_to_look in ('libjvm.dylib', 92 | 'libclient.dylib', 93 | 'libserver.dylib'): 94 | lib = os.path.join(place_to_look, file_to_look) 95 | # 96 | # dlopen_preflight checks to make sure the dylib 97 | # can be loaded in the current architecture 98 | # 99 | if os.path.exists(lib) and \ 100 | libc.dlopen_preflight(lib.encode('utf-8')) != 0: 101 | return path 102 | else: 103 | logger.error("Could not find Java JRE compatible with %s architecture" % arch) 104 | if arch == "i386": 105 | logger.error( 106 | "Please visit https://support.apple.com/kb/DL1572 for help\n" 107 | "installing Apple legacy Java 1.6 for 32 bit support.") 108 | return None 109 | except: 110 | logger.error("Failed to run /usr/libexec/java_home, defaulting to best guess for Java", exc_info=1) 111 | return "/System/Library/Frameworks/JavaVM.framework/Home" 112 | elif is_linux: 113 | def get_out(cmd): 114 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 115 | o, ignore = p.communicate() 116 | if p.poll() != 0: 117 | raise Exception("Error finding javahome on linux: %s" % cmd) 118 | o = o.strip().decode('utf-8') 119 | return o 120 | java_bin = get_out(["bash", "-c", "type -p java"]) 121 | java_dir = get_out(["readlink", "-f", java_bin]) 122 | java_version_string = get_out(["bash", "-c", "java -version"]) 123 | if re.search('^openjdk', java_version_string, re.MULTILINE) is not None: 124 | pattern = 'openjdk version "([^"]+)"' 125 | match = re.search(pattern, java_version_string, re.MULTILINE) 126 | if match: 127 | version = match.groups()[0] 128 | if version < "1.8": 129 | jdk_dir = os.path.join(java_dir, "..", "..", "..") 130 | else: 131 | jdk_dir = os.path.join(java_dir, "..", "..") 132 | else: 133 | raise RuntimeError("Failed to parse version from %s" % 134 | java_version_string) 135 | elif re.search('^java', java_version_string, re.MULTILINE) is not None: 136 | jdk_dir = os.path.join(java_dir, "..", "..") 137 | else: 138 | raise RuntimeError( 139 | "Failed to determine JDK vendor. " 140 | "OpenJDK and Oracle JDK are supported." 141 | ) 142 | jdk_dir = os.path.abspath(jdk_dir) 143 | return jdk_dir 144 | elif is_win: 145 | # Registry keys changed in 1.9 146 | # https://docs.oracle.com/javase/9/migrate/toc.htm#GUID-EEED398E-AE37-4D12-AB10-49F82F720027 147 | java_key_paths = ( 148 | 'SOFTWARE\\JavaSoft\\JRE', 149 | 'SOFTWARE\\JavaSoft\\Java Runtime Environment', 150 | 'SOFTWARE\\JavaSoft\\JDK' 151 | ) 152 | for java_key_path in java_key_paths: 153 | looking_for = java_key_path 154 | try: 155 | kjava = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, java_key_path) 156 | looking_for = java_key_path + "\\CurrentVersion" 157 | kjava_values = dict([winreg.EnumValue(kjava, i)[:2] 158 | for i in range(winreg.QueryInfoKey(kjava)[1])]) 159 | current_version = kjava_values['CurrentVersion'] 160 | looking_for = java_key_path + '\\' + current_version 161 | kjava_current = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 162 | looking_for) 163 | kjava_current_values = dict([winreg.EnumValue(kjava_current, i)[:2] 164 | for i in range(winreg.QueryInfoKey(kjava_current)[1])]) 165 | return kjava_current_values['JavaHome'] 166 | except WindowsError as e: 167 | if e.errno == 2: 168 | continue 169 | else: 170 | raise 171 | 172 | raise RuntimeError( 173 | "Failed to find the Java Runtime Environment. " 174 | "Please download and install the Oracle JRE 1.6 or later" 175 | ) 176 | 177 | 178 | def find_jdk(): 179 | """Find the JDK under Windows""" 180 | if 'JDK_HOME' in os.environ: 181 | return os.environ['JDK_HOME'] 182 | if is_linux: 183 | jdk_home = find_javahome() 184 | if jdk_home.endswith("jre") or jdk_home.endswith("jre/"): 185 | jdk_home = jdk_home[:jdk_home.rfind("jre")] 186 | return jdk_home 187 | if is_mac: 188 | return find_javahome() 189 | if is_win: 190 | # Registry keys changed in 1.9 191 | # https://docs.oracle.com/javase/9/migrate/toc.htm#GUID-EEED398E-AE37-4D12-AB10-49F82F720027 192 | jdk_key_paths = ( 193 | 'SOFTWARE\\JavaSoft\\JDK', 194 | 'SOFTWARE\\JavaSoft\\Java Development Kit', 195 | ) 196 | for jdk_key_path in jdk_key_paths: 197 | try: 198 | kjdk = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, jdk_key_path) 199 | kjdk_values = dict([winreg.EnumValue(kjdk, i)[:2] 200 | for i in range(winreg.QueryInfoKey(kjdk)[1])]) 201 | current_version = kjdk_values['CurrentVersion'] 202 | kjdk_current = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, 203 | jdk_key_path + '\\' + current_version) 204 | kjdk_current_values = dict([winreg.EnumValue(kjdk_current, i)[:2] 205 | for i in range(winreg.QueryInfoKey(kjdk_current)[1])]) 206 | return kjdk_current_values['JavaHome'] 207 | except WindowsError as e: 208 | if e.errno == 2: 209 | continue 210 | else: 211 | raise 212 | 213 | raise RuntimeError( 214 | "Failed to find the Java Development Kit. " 215 | "Please download and install the Oracle JDK 1.6 or later" 216 | ) 217 | 218 | def find_javac_cmd(): 219 | """Find the javac executable""" 220 | if is_win: 221 | jdk_base = find_jdk() 222 | javac = os.path.join(jdk_base, "bin", "javac.exe") 223 | if os.path.isfile(javac): 224 | return javac 225 | raise RuntimeError("Failed to find javac.exe in its usual location under the JDK (%s)" % javac) 226 | else: 227 | # will be along path for other platforms 228 | return "javac" 229 | 230 | def find_jar_cmd(): 231 | """Find the javac executable""" 232 | if is_win: 233 | jdk_base = find_jdk() 234 | javac = os.path.join(jdk_base, "bin", "jar.exe") 235 | if os.path.isfile(javac): 236 | return javac 237 | raise RuntimeError("Failed to find jar.exe in its usual location under the JDK (%s)" % javac) 238 | else: 239 | # will be along path for other platforms 240 | return "jar" 241 | 242 | 243 | def find_jre_bin_jdk_so(): 244 | """Finds the jre bin dir and the jdk shared library file""" 245 | jvm_dir = None 246 | java_home = find_javahome() 247 | if java_home is not None: 248 | found_jvm = False 249 | for jre_home in (java_home, os.path.join(java_home, "jre"), os.path.join(java_home, 'default-java'), os.path.join(java_home, 'default-runtime')): 250 | jre_bin = os.path.join(jre_home, 'bin') 251 | jre_libexec = os.path.join(jre_home, 'bin' if is_win else 'lib') 252 | arches = ('amd64', 'i386', '') if is_linux else ('',) 253 | lib_prefix = '' if is_win else 'lib' 254 | lib_suffix = '.dll' if is_win else ('.dylib' if is_mac else '.so') 255 | for arch in arches: 256 | for place_to_look in ('client','server'): 257 | jvm_dir = os.path.join(jre_libexec, arch, place_to_look) 258 | jvm_so = os.path.join(jvm_dir, lib_prefix + "jvm" + lib_suffix) 259 | if os.path.isfile(jvm_so): 260 | return (jre_bin, jvm_so) 261 | return (jre_bin, None) 262 | -------------------------------------------------------------------------------- /javabridge/noseplugin.py: -------------------------------------------------------------------------------- 1 | """noseplugin.py - start and stop JVM when running unit tests 2 | 3 | python-javabridge is licensed under the BSD license. See the 4 | accompanying file LICENSE for details. 5 | 6 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 7 | Copyright (c) 2009-2013 Broad Institute 8 | All rights reserved. 9 | 10 | """ 11 | 12 | import logging 13 | from nose.plugins import Plugin 14 | import os 15 | import numpy as np 16 | np.seterr(all='ignore') 17 | import sys 18 | 19 | 20 | log = logging.getLogger(__name__) 21 | 22 | 23 | class JavabridgePlugin(Plugin): 24 | '''Javabridge nose test plugin 25 | 26 | This plugin starts the JVM before running tests and kills it when 27 | the tests are done. The plugin is necessary because the JVM cannot 28 | be restarted once it is killed, so unittest's setUp() and 29 | tearDown() methods cannot be used to start and stop the JVM. 30 | ''' 31 | enabled = False 32 | name = "javabridge" 33 | score = 100 34 | extra_jvm_args = [] 35 | 36 | def begin(self): 37 | import javabridge 38 | 39 | javabridge.start_vm(self.extra_jvm_args, 40 | class_path=self.class_path.split(os.pathsep), 41 | run_headless=self.headless, 42 | max_heap_size=self.max_heap_size) 43 | if not self.headless: 44 | javabridge.activate_awt() 45 | 46 | def options(self, parser, env=os.environ): 47 | super(JavabridgePlugin, self).options(parser, env=env) 48 | parser.add_option("--classpath", action="store", 49 | default=env.get('NOSE_CLASSPATH'), 50 | metavar="PATH", 51 | dest="classpath", 52 | help="Additional class path for JVM [NOSE_CLASSPATH]") 53 | parser.add_option("--no-headless", action="store_true", 54 | default=bool(env.get('NOSE_NO_HEADLESS')), 55 | dest="no_headless", 56 | help="Set Java environment variable, java.awt.headless to false to allow AWT calls [NOSE_NO_HEADLESS]") 57 | parser.add_option("--max-heap-size", action="store", 58 | default=env.get('NOSE_MAX_HEAP_SIZE'), 59 | dest="max_heap_size", 60 | help="Set the maximum heap size argument to the JVM as in the -Xmx command-line argument [NOSE_MAX_HEAP_SIZE]") 61 | 62 | def configure(self, options, conf): 63 | import javabridge 64 | super(JavabridgePlugin, self).configure(options, conf) 65 | self.class_path = os.pathsep.join(javabridge.JARS) 66 | if options.classpath: 67 | self.class_path = os.pathsep.join([options.classpath, self.class_path]) 68 | self.headless = not options.no_headless 69 | self.max_heap_size = options.max_heap_size 70 | 71 | def prepareTestRunner(self, testRunner): 72 | '''Need to make the test runner call finalize if in Wing 73 | 74 | Wing IDE's XML test runner fails to call finalize, so we 75 | wrap it and add that function here 76 | ''' 77 | if (getattr(testRunner, "__module__","unknown") == 78 | "wingtest_common"): 79 | outer_self = self 80 | class TestRunnerProxy(object): 81 | def run(self, test): 82 | result = testRunner.run(test) 83 | outer_self.finalize(testRunner.result) 84 | return result 85 | 86 | @property 87 | def result(self): 88 | return testRunner.result 89 | return TestRunnerProxy() 90 | 91 | def finalize(self, result): 92 | import javabridge 93 | javabridge.kill_vm() 94 | -------------------------------------------------------------------------------- /javabridge/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LeeKamentsky/python-javabridge/8fd52f1966ccabe04e51e00393846fd3b25aa8ce/javabridge/tests/__init__.py -------------------------------------------------------------------------------- /javabridge/tests/test_cpython.py: -------------------------------------------------------------------------------- 1 | '''test_cpython.py - test the JNI CPython class 2 | 3 | python-javabridge is licensed under the BSD license. See the 4 | accompanying file LICENSE for details. 5 | 6 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 7 | Copyright (c) 2009-2013 Broad Institute 8 | All rights reserved. 9 | 10 | ''' 11 | import unittest 12 | import javabridge 13 | 14 | class TestCPython(unittest.TestCase): 15 | def setUp(self): 16 | self.cpython = javabridge.JClassWrapper( 17 | "org.cellprofiler.javabridge.CPython")() 18 | 19 | def test_01_01_exec(self): 20 | self.cpython.execute("pass") 21 | 22 | def test_01_02_locals(self): 23 | jlocals = javabridge.JClassWrapper('java.util.HashMap')() 24 | jref = javabridge.JClassWrapper('java.util.ArrayList')() 25 | jlocals.put("numerator", "6") 26 | jlocals.put("denominator", "2") 27 | code = """ 28 | global javabridge 29 | import javabridge 30 | def fn(numerator, denominator, answer): 31 | result = int(numerator) / int(denominator) 32 | javabridge.call(answer, "add", "(Ljava/lang/Object;)Z", str(result)) 33 | fn(numerator, denominator, answer) 34 | """ 35 | jlocals.put("code", code) 36 | jlocals.put("answer", jref.o) 37 | self.cpython.execute(code, jlocals.o, None) 38 | self.assertEqual(float(javabridge.to_string(jref.get(0))), 3) 39 | 40 | def test_01_03_globals(self): 41 | jglobals = javabridge.JClassWrapper('java.util.HashMap')() 42 | jref = javabridge.JClassWrapper('java.util.ArrayList')() 43 | jglobals.put("numerator", "6") 44 | jglobals.put("denominator", "2") 45 | jglobals.put("answer", jref.o) 46 | self.cpython.execute(""" 47 | global javabridge 48 | import javabridge 49 | def fn(): 50 | result = int(numerator) / int(denominator) 51 | javabridge.call(answer, "add", "(Ljava/lang/Object;)Z", str(result)) 52 | fn() 53 | """, None, jglobals.o) 54 | self.assertEqual(float(javabridge.to_string(jref.get(0))), 3) 55 | 56 | def test_01_04_globals_equals_locals(self): 57 | jglobals = javabridge.JClassWrapper('java.util.HashMap')() 58 | jref = javabridge.JClassWrapper('java.util.ArrayList')() 59 | jglobals.put("numerator", "6") 60 | jglobals.put("denominator", "2") 61 | jglobals.put("answer", jref.o) 62 | # 63 | # The import will be added to "locals", but that will be the globals. 64 | # 65 | self.cpython.execute(""" 66 | import javabridge 67 | def fn(): 68 | result = int(numerator) / int(denominator) 69 | javabridge.call(answer, "add", "(Ljava/lang/Object;)Z", str(result)) 70 | fn() 71 | """, jglobals.o, jglobals.o) 72 | self.assertEqual(float(javabridge.to_string(jref.get(0))), 3) -------------------------------------------------------------------------------- /javabridge/tests/test_wrappers.py: -------------------------------------------------------------------------------- 1 | '''test_wrappers.py test JWrapper and JClassWrapper 2 | 3 | python-javabridge is licensed under the BSD license. See the 4 | accompanying file LICENSE for details. 5 | 6 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 7 | Copyright (c) 2009-2013 Broad Institute 8 | All rights reserved. 9 | 10 | ''' 11 | import unittest 12 | import javabridge as J 13 | 14 | class TestJWrapper(unittest.TestCase): 15 | def test_01_01_init(self): 16 | jobj = J.get_env().new_string(u"Hello, world.") 17 | obj = J.JWrapper(jobj) 18 | self.assertEqual(jobj, obj.o) 19 | 20 | def test_01_02_call_noargs(self): 21 | jobj = J.get_env().new_string(u"Hello, world.") 22 | obj = J.JWrapper(jobj) 23 | self.assertEqual(obj.toLowerCase(), "hello, world.") 24 | 25 | def test_01_03_call_args(self): 26 | jobj = J.get_env().new_string(u"Hello, world.") 27 | obj = J.JWrapper(jobj) 28 | result = obj.replace("Hello,", "Goodbye cruel") 29 | self.assertEqual(result, "Goodbye cruel world.") 30 | 31 | def test_01_04_call_varargs(self): 32 | sclass = J.JWrapper(J.class_for_name("java.lang.String")); 33 | for constructor in J.get_env().get_object_array_elements( 34 | sclass.getConstructors().o): 35 | wconstructor = J.JWrapper(constructor) 36 | parameter_types = J.get_env().get_object_array_elements( 37 | wconstructor.getParameterTypes().o) 38 | c1 = sclass.getConstructor(*parameter_types) 39 | self.assertTrue(c1.equals(constructor)) 40 | 41 | def test_02_01_get_field(self): 42 | obj = J.JClassWrapper("org.cellprofiler.javabridge.test.RealRect")( 43 | 1.5, 2.5, 3.5, 4.5) 44 | self.assertEqual(obj.x, 1.5) 45 | 46 | def test_02_02_set_field(self): 47 | obj = J.JClassWrapper("org.cellprofiler.javabridge.test.RealRect")( 48 | 1.5, 2.5, 3.5, 4.5) 49 | obj.x = 2.5 50 | self.assertEqual(obj.x, 2.5) 51 | 52 | class TestJClassWrapper_Unboxing(unittest.TestCase): 53 | def setUp(self): 54 | self.i = J.JClassWrapper('java.lang.Integer')(3) 55 | 56 | def test_01_01_int(self): 57 | self.assertEqual(int(self.i), 3) 58 | 59 | def test_01_02_float(self): 60 | self.assertEqual(float(self.i),3.0) 61 | 62 | def test_01_03_str(self): 63 | self.assertEqual(str(self.i), '3') 64 | 65 | class TestJClassWrapper_Collection(unittest.TestCase): 66 | def setUp(self): 67 | self.a = J.JClassWrapper('java.util.ArrayList')() 68 | self.assertEqual(len(self.a), 0) 69 | self.ints = [0,1,2,4,8,16] 70 | self.assertEqual(len(self.ints), 6) 71 | for i in self.ints: 72 | self.a.add(i) 73 | 74 | def test_01_01_get_len(self): 75 | self.assertEqual(len(self.a), len(self.ints)) 76 | 77 | def test_01_02_iterate(self): 78 | for x,y in zip(self.a, self.ints): 79 | self.assertEqual(x.intValue(), y) 80 | 81 | def test_01_03_get_index(self): 82 | for i in range(len(self.a)): 83 | self.assertEqual(self.a[i].intValue(), self.ints[i]) 84 | 85 | def test_01_04_set_index(self): 86 | for i in range(len(self.a)): 87 | self.a[i] = 10 88 | for i in range(len(self.a)): 89 | self.assertEqual(self.a[i].intValue(), 10) 90 | 91 | class TestJClassWrapper(unittest.TestCase): 92 | def test_01_01_init(self): 93 | c = J.JClassWrapper("java.lang.Integer") 94 | 95 | def test_01_02_field(self): 96 | c = J.JClassWrapper("java.lang.Short") 97 | field = c.MAX_VALUE 98 | self.assertEqual(field, (1 << 15)-1) 99 | 100 | def test_02_03_static_call(self): 101 | c = J.JClassWrapper("java.lang.Integer") 102 | self.assertEqual(c.toString(123), "123") 103 | 104 | def test_02_04_static_call_varargs(self): 105 | # 106 | # Test calling a static function with a variable number of 107 | # arguments. 108 | # 109 | c = J.JClassWrapper("java.lang.String") 110 | self.assertEqual(c.format("Hello, %s.", "world"), 111 | "Hello, world.") 112 | self.assertEqual(c.format("Goodbye %s %s.", "cruel", "world"), 113 | "Goodbye cruel world.") 114 | 115 | def test_02_05_constructor_varargs(self): 116 | # Regression test of issue #41 117 | # 118 | args = ("foo", "bar") 119 | f = J.JClassWrapper( 120 | "javax.swing.filechooser.FileNameExtensionFilter")("baz", *args) 121 | exts = J.get_env().get_object_array_elements(f.getExtensions().o) 122 | self.assertEqual(args[0], J.to_string(exts[0])) 123 | self.assertEqual(args[1], J.to_string(exts[1])) 124 | 125 | class TestJProxy(unittest.TestCase): 126 | def test_01_01_init(self): 127 | def whatever(): 128 | pass 129 | J.JProxy('java.lang.Runnable', dict(run=whatever)) 130 | 131 | def test_01_02_runnable(self): 132 | magic = [] 133 | def whatever(magic=magic): 134 | magic.append("bus") 135 | runnable = J.JProxy('java.lang.Runnable', 136 | dict(run=whatever)) 137 | J.JWrapper(runnable.o).run() 138 | self.assertEqual(magic[0], "bus") 139 | 140 | def test_01_03_runnable_class(self): 141 | class MyProxy(J.JProxy): 142 | def __init__(self): 143 | J.JProxy.__init__(self, 'java.lang.Runnable') 144 | self.esteem = 0 145 | 146 | def run(self): 147 | self.esteem = "through the roof" 148 | 149 | proxy = MyProxy() 150 | J.JWrapper(proxy.o).run() 151 | self.assertEqual(proxy.esteem, "through the roof") 152 | 153 | def test_01_04_args(self): 154 | my_observable = J.make_instance("java/util/Observable", "()V") 155 | def update(observable, obj): 156 | self.assertTrue(J.JWrapper(observable).equals(my_observable)) 157 | self.assertTrue(J.JWrapper(obj).equals("bar")) 158 | proxy = J.JProxy('java.util.Observer', dict(update=update)) 159 | J.JWrapper(proxy.o).update(my_observable, "bar") 160 | 161 | def test_01_05_return_value(self): 162 | def call(): 163 | return "foo" 164 | proxy = J.JProxy('java.util.concurrent.Callable', 165 | dict(call = call)) 166 | self.assertEqual(J.JWrapper(proxy.o).call(), "foo") 167 | 168 | if __name__=="__main__": 169 | import javabridge 170 | javabridge.start_vm() 171 | try: 172 | unittest.main() 173 | finally: 174 | javabridge.kill_vm() 175 | -------------------------------------------------------------------------------- /javabridge/wrappers.py: -------------------------------------------------------------------------------- 1 | # -*- Encoding: utf-8 -*- 2 | '''wrappers.py - Wrappers for Java classes and instances 3 | 4 | python-javabridge is licensed under the BSD license. See the 5 | accompanying file LICENSE for details. 6 | 7 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 8 | Copyright (c) 2009-2014 Broad Institute 9 | All rights reserved. 10 | 11 | ''' 12 | 13 | import inspect 14 | import sys 15 | import numpy as np 16 | import javabridge as J 17 | 18 | try: 19 | basestring # Python 2 20 | except NameError: 21 | basestring = (str, ) # Python 3 22 | 23 | 24 | class JWrapper(object): 25 | '''A class that wraps a Java object 26 | 27 | JWrapper uses Java reflection to find a Java object's methods and fields. 28 | You can then use dot notation to call the methods and get references 29 | to the fields. If methods return Java objects, these will also be 30 | wrapped, so you can use the wrapper to do almost anything. 31 | 32 | When a class has overloaded methods with the same name, JWrapper will 33 | try to pick the one that matches the types of the arguments. 34 | 35 | To access static methods and fields, use JClassWrapper. 36 | 37 | `self.o` is the JB_Object wrapped by the wrapper. You 38 | can use `self.o` as an argument for the collection wrappers or anywhere 39 | else you might use a JB_Object. 40 | 41 | Usage: 42 | 43 | >>> a = JWrapper(javabridge.make_instance("java/util/ArrayList", "()V")) 44 | >>> a.add("Hello") 45 | >>> a.add("World") 46 | >>> a.size() 47 | 2 48 | >>> a.get(0).toLowerCase() 49 | hello 50 | ''' 51 | def __init__(self, o): 52 | '''Initialize the JWrapper with a Java object 53 | 54 | :param o: a Java object (class = JB_Object) 55 | ''' 56 | STATIC = J.get_static_field("java/lang/reflect/Modifier", "STATIC", "I") 57 | self.o = o 58 | self.class_wrapper = J.get_class_wrapper(o) 59 | env = J.get_env() 60 | jmethods = env.get_object_array_elements(self.class_wrapper.getMethods()) 61 | methods = {} 62 | for jmethod in jmethods: 63 | if (J.call(jmethod, "getModifiers", "()I") & STATIC) == STATIC: 64 | continue 65 | method = J.get_method_wrapper(jmethod) 66 | name = method.getName() 67 | if name not in methods: 68 | methods[name] = [] 69 | fn = lambda naame=name: lambda *args: self.__call(naame, *args) 70 | fn = fn() 71 | fn.__doc__ = J.to_string(jmethod) 72 | setattr(self, name, fn) 73 | else: 74 | fn = getattr(self, name) 75 | fn.__doc__ = fn.__doc__ +"\n"+J.to_string(jmethod) 76 | methods[name].append(method) 77 | jfields = env.get_object_array_elements( 78 | self.class_wrapper.getFields(self)) 79 | field_class = env.find_class("java/lang/reflect/Field") 80 | method_id = env.get_method_id( 81 | field_class, "getName", "()Ljava/lang/String;") 82 | self.field_names = [ 83 | env.get_string_utf(env.call_method(o, method_id)) for o in jfields] 84 | self.methods = methods 85 | 86 | def __getattr__(self, name): 87 | if name in ("o", "class_wrapper", "methods", "field_names"): 88 | raise AttributeError() 89 | if not hasattr(self, "methods") or not hasattr(self, "field_names"): 90 | # not initialized 91 | raise AttributeError() 92 | if name not in self.field_names: 93 | raise AttributeError() 94 | try: 95 | jfield = self.class_wrapper.getField(name) 96 | except: 97 | raise AttributeError() 98 | 99 | STATIC = J.get_static_field("java/lang/reflect/Modifier", "STATIC", "I") 100 | if (J.call(jfield, "getModifiers", "()I") & STATIC) == STATIC: 101 | raise AttributeError() 102 | klass = J.call(jfield, "getType", "()Ljava/lang/Class;") 103 | result = J.get_field(self.o, name, sig(klass)) 104 | if isinstance(result, J.JB_Object): 105 | result = JWrapper(result) 106 | return result 107 | 108 | def __setattr__(self, name, value): 109 | if name in ("o", "class_wrapper", "methods", "field_names") or \ 110 | not hasattr(self, "methods"): 111 | object.__setattr__(self, name, value) 112 | return 113 | try: 114 | jfield = self.class_wrapper.getField(name) 115 | except: 116 | object.__setattr__(self, name, value) 117 | return 118 | 119 | STATIC = J.get_static_field("java/lang/reflect/Modifier", "STATIC", "I") 120 | if (J.call(jfield, "getModifiers", "()I") & STATIC) == STATIC: 121 | raise AttributeError() 122 | klass = J.call(jfield, "getType", "()Ljava/lang/Class;") 123 | result = J.set_field(self.o, name, sig(klass), value) 124 | 125 | def __call(self, method_name, *args): 126 | '''Call the appropriate overloaded method with the given name 127 | 128 | :param method_name: the name of the method to call 129 | :param *args: the arguments to the method, which are used to 130 | disambiguate between similarly named methods 131 | ''' 132 | env = J.get_env() 133 | last_e = None 134 | for method in self.methods[method_name]: 135 | params = env.get_object_array_elements(method.getParameterTypes()) 136 | is_var_args = J.call(method.o, "isVarArgs", "()Z") 137 | if len(args) < len(params) - (1 if is_var_args else 0): 138 | continue 139 | if len(args) > len(params) and not is_var_args: 140 | continue 141 | if is_var_args: 142 | pm1 = len(params)-1 143 | args1 = list(args[:pm1]) + [args[pm1:]] 144 | else: 145 | args1 = args 146 | try: 147 | cargs = [cast(o, klass) for o, klass in zip(args1, params)] 148 | except: 149 | last_e = sys.exc_info()[1] 150 | continue 151 | rtype = J.call(method.o, "getReturnType", "()Ljava/lang/Class;") 152 | args_sig = "".join(map(sig, params)) 153 | rsig = sig(rtype) 154 | msig = "(%s)%s" % (args_sig, rsig) 155 | result = J.call(self.o, method_name, msig, *cargs) 156 | if isinstance(result, J.JB_Object): 157 | result = JWrapper(result) 158 | return result 159 | raise TypeError("No matching method found for %s" % method_name) 160 | 161 | def __repr__(self): 162 | classname = J.call(J.call(self.o, "getClass", "()Ljava/lang/Class;"), 163 | "getName", "()Ljava/lang/String;") 164 | return "Instance of %s: %s" % (classname, J.to_string(self.o)) 165 | 166 | def __str__(self): 167 | return J.to_string(self.o) 168 | 169 | def __int__(self): 170 | return self.intValue() 171 | 172 | def __float__(self): 173 | return self.floatValue() 174 | 175 | def __len__(self): 176 | if not J.is_instance_of(self.o,'java/util/Collection'): 177 | raise TypeError("%s is not a Collection and does not support __len__" % self) 178 | return self.size() 179 | 180 | def __getitem__(self, i): 181 | if not J.is_instance_of(self.o,'java/util/Collection'): 182 | raise TypeError("%s is not a Collection and does not support __getitem__" % self) 183 | return self.get(i) 184 | 185 | def __setitem__(self, i, v): 186 | if not J.is_instance_of(self.o,'java/util/Collection'): 187 | raise TypeError("%s is not a Collection and does not support __setitem__" % self) 188 | return self.set(i, v) 189 | 190 | class Iterator: 191 | def __init__(self, o): 192 | self.o = o 193 | self.i = 0 194 | 195 | def next(self): 196 | return self.__next__() 197 | 198 | def __next__(self): 199 | if self.i == len(self.o): 200 | raise StopIteration 201 | self.i = self.i +1 202 | return self.o[self.i-1] 203 | 204 | def __iter__(self): 205 | if not J.is_instance_of(self.o,'java/util/Collection'): 206 | raise TypeError("%s is not a Collection and does not support __iter__" % self) 207 | return self.Iterator(self) 208 | 209 | class JClassWrapper(object): 210 | '''Wrapper for a class 211 | 212 | JWrapper uses Java reflection to find a Java object's methods and fields. 213 | You can then use dot notation to call the static methods and get references 214 | to the static fields. If methods return Java objects, these will also be 215 | wrapped, so you can use the wrapper to do almost anything. 216 | 217 | When a class has overloaded methods with the same name, JWrapper will 218 | try to pick the one that matches the types of the arguments. 219 | 220 | >>> Integer = JClassWrapper("java.lang.Integer") 221 | >>> Integer.MAX_VALUE 222 | 2147483647 223 | ''' 224 | def __init__(self, class_name): 225 | '''Initialize to wrap a class name 226 | 227 | :param class_name: name of class in dotted form, e.g. java.lang.Integer 228 | ''' 229 | STATIC = J.get_static_field("java/lang/reflect/Modifier", "STATIC", "I") 230 | self.cname = class_name.replace(".", "/") 231 | self.klass = J.get_class_wrapper(J.class_for_name(class_name), True) 232 | self.static_methods = {} 233 | env = J.get_env() 234 | jmethods = env.get_object_array_elements(self.klass.getMethods()) 235 | methods = {} 236 | for jmethod in jmethods: 237 | if (J.call(jmethod, "getModifiers", "()I") & STATIC) != STATIC: 238 | continue 239 | method = J.get_method_wrapper(jmethod) 240 | name = method.getName() 241 | if name not in methods: 242 | methods[name] = [] 243 | fn = lambda naame=name: lambda *args: self.__call_static(naame, *args) 244 | fn = fn() 245 | fn.__doc__ = J.to_string(jmethod) 246 | setattr(self, name, fn) 247 | else: 248 | fn = getattr(self, name) 249 | fn.__doc__ = fn.__doc__ +"\n"+J.to_string(jmethod) 250 | methods[name].append(method) 251 | jfields = env.get_object_array_elements(self.klass.getFields(self)) 252 | field_class = env.find_class("java/lang/reflect/Field") 253 | method_id = env.get_method_id( 254 | field_class, "getName", "()Ljava/lang/String;") 255 | self.field_names = [ 256 | env.get_string_utf(env.call_method(o, method_id)) for o in jfields] 257 | self.methods = methods 258 | 259 | def __getattr__(self, name): 260 | if name in ("klass", "static_methods", "methods", "cname", 261 | "field_names"): 262 | raise AttributeError() 263 | if not hasattr(self, "methods") or not hasattr(self, "field_names"): 264 | raise AttributeError() 265 | if name not in self.field_names: 266 | raise AttributeError("Cound not find field %s" % name) 267 | try: 268 | jfield = self.klass.getField(name) 269 | except: 270 | raise AttributeError("Could not find field %s" % name) 271 | 272 | STATIC = J.get_static_field("java/lang/reflect/Modifier", "STATIC", "I") 273 | if (J.call(jfield, "getModifiers", "()I") & STATIC) != STATIC: 274 | raise AttributeError("Field %s is not static" % name) 275 | klass = J.call(jfield, "getType", "()Ljava/lang/Class;") 276 | result = J.get_static_field(self.cname, name, sig(klass)) 277 | if isinstance(result, J.JB_Object): 278 | result = JWrapper(result) 279 | return result 280 | 281 | def __setattr__(self, name, value): 282 | if name in ("klass", "static_methods", "methods", "cname", 283 | "field_names") or not hasattr(self, "methods"): 284 | object.__setattr__(self, name, value) 285 | return 286 | try: 287 | jfield = self.klass.getField(name) 288 | except: 289 | return object.__setattr__(self, name, value) 290 | 291 | STATIC = J.get_static_field("java/lang/reflect/Modifier", "STATIC", "I") 292 | if (J.call(jfield, "getModifiers", "()I") & STATIC) != STATIC: 293 | raise AttributeError() 294 | klass = J.call(jfield, "getType", "()Ljava/lang/Class;") 295 | result = J.set_static_field(self.cname, name, sig(klass), value) 296 | 297 | def __call_static(self, method_name, *args): 298 | '''Call the appropriate overloaded method with the given name 299 | 300 | :param method_name: the name of the method to call 301 | :param *args: the arguments to the method, which are used to 302 | disambiguate between similarly named methods 303 | ''' 304 | env = J.get_env() 305 | last_e = None 306 | for method in self.methods[method_name]: 307 | params = env.get_object_array_elements(method.getParameterTypes()) 308 | is_var_args = J.call(method.o, "isVarArgs", "()Z") 309 | if len(args) < len(params) - (1 if is_var_args else 0): 310 | continue 311 | if len(args) > len(params) and not is_var_args: 312 | continue 313 | if is_var_args: 314 | pm1 = len(params)-1 315 | args1 = list(args[:pm1]) + [args[pm1:]] 316 | else: 317 | args1 = args 318 | try: 319 | cargs = [cast(o, klass) for o, klass in zip(args1, params)] 320 | except: 321 | last_e = sys.exc_info()[1] 322 | continue 323 | rtype = J.call(method.o, "getReturnType", "()Ljava/lang/Class;") 324 | args_sig = "".join(map(sig, params)) 325 | rsig = sig(rtype) 326 | msig = "(%s)%s" % (args_sig, rsig) 327 | result = J.static_call(self.cname, method_name, msig, *cargs) 328 | if isinstance(result, J.JB_Object): 329 | result = JWrapper(result) 330 | return result 331 | raise TypeError("No matching method found for %s" % method_name) 332 | 333 | def __call__(self, *args): 334 | '''Constructors''' 335 | env = J.get_env() 336 | jconstructors = self.klass.getConstructors() 337 | for jconstructor in env.get_object_array_elements(jconstructors): 338 | constructor = J.get_constructor_wrapper(jconstructor) 339 | params = env.get_object_array_elements( 340 | constructor.getParameterTypes()) 341 | is_var_args = J.call(constructor.o, "isVarArgs", "()Z") 342 | if len(args) < len(params) - (1 if is_var_args else 0): 343 | continue 344 | if len(args) > len(params) and not is_var_args: 345 | continue 346 | if is_var_args: 347 | pm1 = len(params)-1 348 | args1 = list(args[:pm1]) + [args[pm1:]] 349 | else: 350 | args1 = args 351 | try: 352 | cargs = [cast(o, klass) for o, klass in zip(args1, params)] 353 | except: 354 | last_e = sys.exc_info()[1] 355 | continue 356 | args_sig = "".join(map(sig, params)) 357 | msig = "(%s)V" % (args_sig) 358 | result = J.make_instance(self.cname, msig, *cargs) 359 | result = JWrapper(result) 360 | return result 361 | raise TypeError("No matching constructor found") 362 | 363 | class JProxy(object): 364 | '''A wrapper around java.lang.reflect.Proxy 365 | 366 | The wrapper takes a dictionary of either method name or a 367 | `java.lang.reflect.Method` instance to a callable that handles 368 | the method. You can also subclass JProxy and define methods 369 | with the same names as the Java methods and they will be called. 370 | 371 | An example: 372 | 373 | >>> import javabridge 374 | >>> import sys 375 | >>> runnable = javabridge.JProxy( 376 | 'java.lang.Runnable', 377 | dict(run=lambda:sys.stderr.write("Hello, world.\\n")))) 378 | >>> javabridge.JWrapper(runnable.o).run() 379 | 380 | Another example: 381 | 382 | >>> import javabridge 383 | >>> import sys 384 | >>> class MyRunnable(javabridge.JProxy): 385 | def __init__(self): 386 | javabridge.JProxy.__init__(self, 'java.lang.Runnable') 387 | def run(self): 388 | sys.stderr.write("Hello, world.\\n") 389 | >>> proxy = MyRunnable() 390 | >>> javabridge.JWrapper(runnable.o).run() 391 | ''' 392 | def __init__(self, base_class_name, d=None): 393 | '''Initialize the proxy with the interface name and methods 394 | 395 | :param base_class_name: the class name of the interface to implement 396 | in dotted form (e.g. java.lang.Runnable) 397 | :param d: an optional dictionary of method name to implementation 398 | ''' 399 | self.ref_id, self.ref = J.create_jref(self) 400 | self.__d = d or {} 401 | jclass = J.class_for_name(base_class_name) 402 | loader = J.call(jclass, "getClassLoader", 403 | "()Ljava/lang/ClassLoader;") 404 | env = J.get_env() 405 | classes = env.make_object_array(1, env.find_class("java/lang/Class")) 406 | env.set_object_array_element(classes, 0, jclass) 407 | handler = J.make_instance( 408 | "org/cellprofiler/javabridge/CPythonInvocationHandler", 409 | "(Ljava/lang/String;)V", self.ref_id) 410 | self.o = J.static_call( 411 | "java/lang/reflect/Proxy", 412 | "newProxyInstance", 413 | "(Ljava/lang/ClassLoader;" 414 | "[Ljava/lang/Class;" 415 | "Ljava/lang/reflect/InvocationHandler;)" 416 | "Ljava/lang/Object;", 417 | loader, classes, handler) 418 | 419 | def __call__(self, proxy, method, jargs): 420 | name = J.call(method, "getName", "()Ljava/lang/String;") 421 | env = J.get_env() 422 | args = tuple(env.get_object_array_elements(jargs)) 423 | if name in self.__d: 424 | result = self.__d[name](*args) 425 | else: 426 | result = getattr(self, name)(*args) 427 | retclass = J.call(method, "getReturnType", "()Ljava/lang/Class;") 428 | return cast(result, retclass) 429 | 430 | def importClass(class_name, import_name = None): 431 | '''Import a wrapped class into the global context 432 | 433 | :param class_name: a dotted class name such as java.lang.String 434 | :param import_name: if defined, use this name instead of the class's name 435 | ''' 436 | if import_name is None: 437 | if "." in class_name: 438 | import_name = class_name.rsplit(".", 1)[1] 439 | else: 440 | import_name = class_name 441 | frame = inspect.currentframe(1) 442 | frame.f_locals[import_name] = JClassWrapper(class_name) 443 | 444 | def sig(klass): 445 | '''Return the JNI signature for a class''' 446 | name = J.call(klass, "getName", "()Ljava/lang/String;") 447 | if not (J.call(klass, "isPrimitive", "()Z") or 448 | J.call(klass, "isArray", "()Z")): 449 | name = "L%s;" % name 450 | if name == 'void': 451 | return "V" 452 | if name == 'int': 453 | return "I" 454 | if name == 'byte': 455 | return "B" 456 | if name == 'boolean': 457 | return "Z" 458 | if name == 'long': 459 | return "J" 460 | if name == 'float': 461 | return "F" 462 | if name == 'double': 463 | return "D" 464 | if name == 'char': 465 | return "C" 466 | if name == 'short': 467 | return "S" 468 | return name.replace(".", "/") 469 | 470 | def cast(o, klass): 471 | '''Cast the given object to the given class 472 | 473 | :param o: either a Python object or Java object to be cast 474 | :param klass: a java.lang.Class indicating the target class 475 | 476 | raises a TypeError if the object can't be cast. 477 | ''' 478 | if J.call(klass, "getName", "()Ljava/lang/String;") == 'void': 479 | return None 480 | is_primitive = J.call(klass, "isPrimitive", "()Z") 481 | csig = sig(klass) 482 | if o is None: 483 | if not is_primitive: 484 | return None 485 | else: 486 | raise TypeError("Can't cast None to a primitive type") 487 | 488 | if isinstance(o, J.JB_Object): 489 | if J.call(klass, "isInstance", "(Ljava/lang/Object;)Z", o): 490 | return o 491 | classname = J.run_script("o.getClass().getCanonicalName()", dict(o=o)) 492 | klassname = J.run_script("klass.getCanonicalName()", dict(klass=klass)) 493 | raise TypeError("Object of class %s cannot be cast to %s", 494 | classname, klassname) 495 | elif hasattr(o, "o"): 496 | return cast(o.o, klass) 497 | elif not np.isscalar(o): 498 | component_type = J.call(klass, "getComponentType", "()Ljava/lang/Class;") 499 | if component_type is None: 500 | raise TypeError("Argument must not be a sequence") 501 | if len(o) > 0: 502 | # Test if an element can be cast to the array type 503 | cast(o[0], component_type) 504 | return J.get_nice_arg(o, csig) 505 | elif is_primitive or csig in \ 506 | ('Ljava/lang/String;', 'Ljava/lang/CharSequence;', 507 | 'Ljava/lang/Object;'): 508 | if csig == 'Ljava/lang/CharSequence;': 509 | csig = 'Ljava/lang/String;' 510 | elif csig == 'C' and isinstance(o, basestring) and len(o) != 1: 511 | raise TypeError("Failed to convert string of length %d to char" % 512 | len(o)) 513 | return J.get_nice_arg(o, csig) 514 | raise TypeError("Failed to convert argument to %s" % csig) 515 | 516 | all = [JWrapper, JClassWrapper] 517 | -------------------------------------------------------------------------------- /jenkins/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Build python-javabridge on the centos_javabridge Docker image. 4 | # 5 | # Jenkins will run docker to spin up a container based on the 6 | # centos_javabridge image, mount the Jenkins workspace as a volume, 7 | # then run this script inside the container. 8 | 9 | set -e 10 | set -x 11 | 12 | here=$(dirname "$0") 13 | cd "$here"/.. 14 | python setup.py develop 15 | python setup.py sdist 16 | -------------------------------------------------------------------------------- /jenkins/docker/centos_javabridge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Defines a docker image based on CentOS that includes everything that 2 | # is required to either build the Javabridge or to install the source 3 | # distribution and run the unit tests. 4 | 5 | FROM centos 6 | MAINTAINER Lee Kamentsky, leek@broadinstitute.org 7 | RUN yum install -y python-setuptools numpy gcc python-devel java-1.6.0-openjdk-devel 8 | 9 | 10 | -------------------------------------------------------------------------------- /jenkins/docker/centos_javabridge_build/Dockerfile: -------------------------------------------------------------------------------- 1 | # Build on centos_javabridge by installing software that is required 2 | # for building the javabridge but not for testing it. 3 | 4 | FROM centos_javabridge 5 | MAINTAINER Lee Kamentsky,leek@broadinstitute.org 6 | 7 | RUN yum install -y git 8 | # Copied from https://raw.github.com/pypa/pip/master/contrib/get-pip.py 9 | ADD get-pip.py /tmp/get-pip.py 10 | RUN python /tmp/get-pip.py 11 | RUN pip install cython -------------------------------------------------------------------------------- /jenkins/docker/ensure_image.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Ensure that the specified Docker image exists, building it if 4 | # necessary. 5 | 6 | set -ex 7 | 8 | here=$(dirname "$0") 9 | name="$1" 10 | if [ -z "$name" ]; then 11 | echo >&2 Usage: $(basename "$0") IMAGE-NAME 12 | exit 64 13 | fi 14 | id=$(docker images -q ${name}) 15 | if [ -z "$id" ]; then 16 | docker build -t "$name" "$here"/"$name" 17 | fi 18 | 19 | -------------------------------------------------------------------------------- /jenkins/docker/ubuntu_javabridge/Dockerfile: -------------------------------------------------------------------------------- 1 | # Start with Ubuntu and install software that is required for 2 | # installing, testing, and running the javabridge. 3 | 4 | FROM ubuntu 5 | MAINTAINER Lee Kamentsky,leek@broadinstitute.org 6 | 7 | RUN apt-get update 8 | RUN apt-get install -y openjdk-6-jdk python-numpy python-dev python-setuptools python-nose 9 | -------------------------------------------------------------------------------- /jenkins/docker/ubuntu_javabridge_build/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu_javabridge 2 | MAINTAINER Lee Kamentsky,leek@broadinstitute.org 3 | 4 | RUN apt-get install -y cython git 5 | 6 | -------------------------------------------------------------------------------- /jenkins/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Test the python-javabridge source distribution on the 4 | # centos_javabridge Docker image. 5 | # 6 | # Jenkins will run docker to spn up a container based on the 7 | # centos_javabridge image, mount the "dist" subdirectory of the 8 | # Jenkins workspace as a volume, then run this script inside the 9 | # container. 10 | # 11 | # This script installs the source distribution and runs the unit 12 | # tests. 13 | 14 | set -e 15 | set -x 16 | 17 | mkdir /javabridge 18 | cd /javabridge 19 | tar xvzf /dist/*.tar.gz 20 | cd * 21 | python setup.py develop 22 | python setup.py build_clib 23 | python setup.py nosetests 24 | -------------------------------------------------------------------------------- /jvm.def: -------------------------------------------------------------------------------- 1 | LIBRARY jvm.dll 2 | EXPORTS 3 | JNI_CreateJavaVM@12 4 | JNI_GetDefaultJavaVMInitArgs@4 5 | JNI_GetCreatedJavaVMs@12 6 | -------------------------------------------------------------------------------- /mac_javabridge_utils.c: -------------------------------------------------------------------------------- 1 | /* mac_javabridge_utils.c - Utilities for managing the Java Bridge on OS/X 2 | * 3 | * CellProfiler is distributed under the GNU General Public License, 4 | * but this file is licensed under the more permissive BSD license. 5 | * See the accompanying file LICENSE for details. 6 | * 7 | * Copyright (c) 2003-2009 Massachusetts Institute of Technology 8 | * Copyright (c) 2009-2014 Broad Institute 9 | * All rights reserved. 10 | * 11 | * Please see the AUTHORS file for credits. 12 | * 13 | * Website: http://www.cellprofiler.org 14 | * 15 | * The launching strategy and some of the code are liberally borrowed from 16 | * the Fiji launcher (ij-launcher/ImageJ.c) (Thanks to Dscho) 17 | * 18 | * Copyright 2007-2011 Johannes Schindelin, Mark Longair, Albert Cardona 19 | * Benjamin Schmid, Erwin Frise and Gregory Jefferis 20 | * 21 | * The source is distributed under the BSD license. 22 | */ 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include "jni.h" 29 | #include 30 | #include 31 | 32 | JNIEnv *pEnv; 33 | 34 | static void *thread_function(void *); 35 | 36 | typedef struct { 37 | JavaVM **pvm; 38 | const char *path_to_libjvm; 39 | const char *path_to_libjli; 40 | const char *class_name; 41 | JavaVMInitArgs *pVMArgs; 42 | int result; 43 | char message[256]; 44 | } ThreadFunctionArgs; 45 | 46 | /********************************************************** 47 | * 48 | * The JVM thread 49 | * 50 | **********************************************************/ 51 | static pthread_t thread; 52 | 53 | /********************************************************** 54 | * 55 | * JVM start communication 56 | * 57 | ***********************************************************/ 58 | static pthread_mutex_t start_mutex; 59 | static pthread_cond_t start_cv; 60 | static int started = 0; 61 | 62 | /********************************************************** 63 | * 64 | * JVM stop communication 65 | * 66 | **********************************************************/ 67 | static pthread_mutex_t stop_mutex; 68 | static pthread_cond_t stop_cv; 69 | static int stopped = 0; 70 | 71 | /********************************************************** 72 | * 73 | * Run loop synchronization 74 | * 75 | **********************************************************/ 76 | 77 | #define RLS_BEFORE_START 1 78 | #define RLS_STARTED 2 79 | #define RLS_TERMINATING 3 80 | #define RLS_TERMINATED 4 81 | 82 | static pthread_mutex_t run_loop_mutex; 83 | static pthread_cond_t run_loop_cv; 84 | static int run_loop_state = RLS_BEFORE_START; 85 | 86 | /********************************************************** 87 | * 88 | * MacStartVM 89 | * 90 | * Start the VM on its own thread, instantiate the thread's runnable 91 | * and run it until exit. 92 | * 93 | * vm_args - a pointer to a JavaVMInitArgs structure 94 | * as documented for JNI_CreateJavaVM 95 | * 96 | * class_name - instantiate this class in the startup thread 97 | * 98 | * path_to_libjvm - path to libjvm.dylib to be dlopened. 99 | * 100 | * path_to_libjli - path to libjli to be opened. 101 | * 102 | * Returns only after the thread terminates. Exit code other 103 | * than zero indicates failure. 104 | **********************************************************/ 105 | 106 | int MacStartVM(JavaVM **pVM, JavaVMInitArgs *pVMArgs, 107 | const char *class_name, const char *path_to_libjvm, 108 | const char *path_to_libjli) 109 | { 110 | ThreadFunctionArgs threadArgs; 111 | pthread_attr_t attr; 112 | void *retval; 113 | int result; 114 | 115 | threadArgs.pvm = pVM; 116 | 117 | pthread_mutex_init(&start_mutex, NULL); 118 | pthread_cond_init(&start_cv, NULL); 119 | 120 | pthread_mutex_init(&stop_mutex, NULL); 121 | pthread_cond_init(&stop_cv, NULL); 122 | 123 | pthread_attr_init(&attr); 124 | pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM); 125 | pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 126 | threadArgs.pVMArgs = pVMArgs; 127 | threadArgs.class_name = class_name; 128 | threadArgs.path_to_libjvm = path_to_libjvm; 129 | threadArgs.path_to_libjli = path_to_libjli; 130 | threadArgs.result = -1; 131 | 132 | /* Start the thread that we will start the JVM on. */ 133 | result = pthread_create(&thread, &attr, thread_function, &threadArgs); 134 | if (result) 135 | return result; 136 | pthread_attr_destroy(&attr); 137 | pthread_mutex_lock(&start_mutex); 138 | while (started == 0) { 139 | pthread_cond_wait(&start_cv, &start_mutex); 140 | } 141 | pthread_mutex_unlock(&start_mutex); 142 | if (threadArgs.result) { 143 | printf("%s\n", threadArgs.message); 144 | } 145 | return threadArgs.result; 146 | } 147 | 148 | /************************************************************ 149 | * 150 | * Stop the JVM 151 | * 152 | ************************************************************/ 153 | void MacStopVM() 154 | { 155 | pthread_mutex_lock(&stop_mutex); 156 | stopped = 1; 157 | pthread_cond_signal(&stop_cv); 158 | pthread_mutex_unlock(&stop_mutex); 159 | pthread_join(thread, NULL); 160 | } 161 | 162 | static void signal_start() 163 | { 164 | pthread_mutex_lock(&start_mutex); 165 | started = 1; 166 | pthread_cond_signal(&start_cv); 167 | pthread_mutex_unlock(&start_mutex); 168 | } 169 | 170 | static void *thread_function(void *arg) 171 | { 172 | JNIEnv *env; 173 | jclass klass; 174 | jmethodID method; 175 | jobject instance; 176 | jthrowable exception; 177 | JavaVM *vm; 178 | void *handleToJVM; 179 | void *handleToJLI; 180 | static jint (* JNI_CreateJavaVM)(JavaVM **pvm, void **penv, void *args); 181 | ThreadFunctionArgs *pThreadArgs = (ThreadFunctionArgs *)arg; 182 | /* 183 | * dlopen libjli.dylib 184 | */ 185 | handleToJLI = dlopen(pThreadArgs->path_to_libjli, RTLD_LAZY); 186 | if (dlerror()) { 187 | strcpy(pThreadArgs->message, "Failed to open libjli.dylib.\n"); 188 | signal_start(); 189 | return NULL; 190 | } 191 | /* 192 | * Get the pointer to JNI_CreateJavaVM via dlopen and dlsym 193 | */ 194 | handleToJVM = dlopen(pThreadArgs->path_to_libjvm, RTLD_LAZY); 195 | if (dlerror()) { 196 | strcpy(pThreadArgs->message, "Failed to open libjvm.dylib.\n"); 197 | signal_start(); 198 | dlclose(handleToJLI); 199 | return NULL; 200 | } 201 | JNI_CreateJavaVM = dlsym(handleToJVM, "JNI_CreateJavaVM"); 202 | if (dlerror()) { 203 | JNI_CreateJavaVM = dlsym(handleToJVM, "JNI_CreateJavaVM_Impl"); 204 | if (dlerror()) { 205 | strcpy(pThreadArgs->message, "Could not find JNI_CreateJavaVM in libjvm.dylib\n"); 206 | signal_start(); 207 | return NULL; 208 | } 209 | } 210 | pThreadArgs->result = JNI_CreateJavaVM(&vm, (void **)&env, 211 | pThreadArgs->pVMArgs); 212 | *pThreadArgs->pvm = vm; 213 | if (pThreadArgs->result) { 214 | strcpy(pThreadArgs->message, "Failed to create Java virtual machine.\n"); 215 | signal_start(); 216 | return NULL; 217 | } 218 | 219 | klass = (*env)->FindClass(env, pThreadArgs->class_name); 220 | if ((*env)->ExceptionOccurred(env)) { 221 | snprintf(pThreadArgs->message, 256, "Failed to find class %s\n", 222 | pThreadArgs->class_name); 223 | pThreadArgs->result = -1; 224 | signal_start(); 225 | goto STOP_VM; 226 | } 227 | 228 | method = (*env)->GetMethodID(env, klass, "", "()V"); 229 | if ((*env)->ExceptionOccurred(env)) { 230 | (*env)->ExceptionDescribe(env); 231 | snprintf(pThreadArgs->message, 256, "%s has no default constructor\n", 232 | pThreadArgs->class_name); 233 | pThreadArgs->result = -2; 234 | signal_start(); 235 | goto STOP_VM; 236 | } 237 | instance = (*env)->NewObjectA(env, klass, method, NULL); 238 | if ((*env)->ExceptionOccurred(env)) { 239 | (*env)->ExceptionDescribe(env); 240 | snprintf(pThreadArgs->message, 256, "Failed to construct %s\n", 241 | pThreadArgs->class_name); 242 | pThreadArgs->result = -3; 243 | signal_start(); 244 | goto STOP_VM; 245 | } 246 | signal_start(); 247 | 248 | method = (*env)->GetMethodID(env, klass, "run", "()V"); 249 | if ((*env)->ExceptionOccurred(env)) { 250 | (*env)->ExceptionDescribe(env); 251 | snprintf(pThreadArgs->message, 256, "%s has no run method\n", 252 | pThreadArgs->class_name); 253 | pThreadArgs->result = -4; 254 | goto STOP_VM; 255 | } 256 | (*env)->CallVoidMethodA(env, instance, method, NULL); 257 | if ((*env)->ExceptionOccurred(env)) { 258 | (*env)->ExceptionDescribe(env); 259 | snprintf(pThreadArgs->message, 256, "Failed to execute run method for %s\n", 260 | pThreadArgs->class_name); 261 | pThreadArgs->result = -5; 262 | goto STOP_VM; 263 | } 264 | 265 | STOP_VM: 266 | pthread_mutex_lock(&stop_mutex); 267 | while (stopped == 0) { 268 | pthread_cond_wait(&stop_cv, &stop_mutex); 269 | } 270 | started = 0; 271 | pthread_mutex_unlock(&stop_mutex); 272 | (*vm)->DestroyJavaVM(vm); 273 | dlclose(handleToJVM); 274 | dlclose(handleToJLI); 275 | return NULL; 276 | } 277 | 278 | /************************************************************************** 279 | * 280 | * CBPerform - a dummy run loop source context perform callback 281 | * 282 | **************************************************************************/ 283 | 284 | static void CBPerform(void *info) 285 | { 286 | } 287 | 288 | /************************************************************************* 289 | * 290 | * CBObserve - a CFRunLoopObserver callback which is called when the 291 | * run loop's state changes 292 | * 293 | *************************************************************************/ 294 | static void CBObserve(CFRunLoopObserverRef observer, 295 | CFRunLoopActivity activity, 296 | void *info) 297 | { 298 | if (activity == kCFRunLoopEntry) { 299 | pthread_mutex_lock(&run_loop_mutex); 300 | if (run_loop_state == RLS_BEFORE_START) { 301 | run_loop_state = RLS_STARTED; 302 | pthread_cond_signal(&run_loop_cv); 303 | } 304 | pthread_mutex_unlock(&run_loop_mutex); 305 | } 306 | if (run_loop_state == RLS_TERMINATING) { 307 | /* Kill, Kill, Kill */ 308 | CFRunLoopStop(CFRunLoopGetCurrent()); 309 | } 310 | } 311 | 312 | /************************************************************************* 313 | * 314 | * MacRunLoopInit - Configure the main event loop with an observer and source 315 | * 316 | *************************************************************************/ 317 | 318 | void MacRunLoopInit() 319 | { 320 | CFRunLoopObserverContext observerContext; 321 | CFRunLoopObserverRef observerRef; 322 | CFRunLoopSourceContext sourceContext; 323 | CFRunLoopSourceRef sourceRef; 324 | 325 | pthread_mutex_init(&run_loop_mutex, NULL); 326 | pthread_cond_init(&run_loop_cv, NULL); 327 | 328 | memset(&sourceContext, 0, sizeof(sourceContext)); 329 | sourceContext.perform = CBPerform; 330 | sourceRef = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &sourceContext); 331 | CFRunLoopAddSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes); 332 | } 333 | 334 | /************************************************************************* 335 | * 336 | * MacRunLoopReset - reset the run loop state to before start 337 | * 338 | *************************************************************************/ 339 | void MacRunLoopReset() 340 | { 341 | run_loop_state = RLS_BEFORE_START; 342 | } 343 | 344 | /************************************************************************* 345 | * 346 | * MacRunLoopRun - run the event loop until stopped 347 | * 348 | *************************************************************************/ 349 | void MacRunLoopRun() 350 | { 351 | CFRunLoopRun(); 352 | pthread_mutex_lock(&run_loop_mutex); 353 | run_loop_state = RLS_TERMINATED; 354 | pthread_cond_signal(&run_loop_cv); 355 | pthread_mutex_unlock(&run_loop_mutex); 356 | } 357 | 358 | /************************************************************************* 359 | * 360 | * MacRunLoopRunInMode - run the event loop until timeout or stopped 361 | * 362 | *************************************************************************/ 363 | void MacRunLoopRunInMode(double timeInterval) 364 | { 365 | CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeInterval, 1); 366 | } 367 | 368 | /**************************************************************************** 369 | * 370 | * MacRunLoopStop - stop the Mac run loop 371 | * 372 | ****************************************************************************/ 373 | 374 | void MacRunLoopStop() 375 | { 376 | pthread_mutex_lock(&run_loop_mutex); 377 | while(1) { 378 | if (run_loop_state == RLS_BEFORE_START) { 379 | pthread_cond_wait(&run_loop_cv, &run_loop_mutex); 380 | } else if (run_loop_state == RLS_STARTED) { 381 | run_loop_state = RLS_TERMINATING; 382 | CFRunLoopStop(CFRunLoopGetMain()); 383 | pthread_cond_signal(&run_loop_cv); 384 | while (run_loop_state == RLS_TERMINATING) { 385 | pthread_cond_wait(&run_loop_cv, &run_loop_mutex); 386 | } 387 | break; 388 | } else { 389 | /* 390 | * Assume either RLS_TERMINATING (called twice) or RLS_TERMINATED 391 | */ 392 | break; 393 | } 394 | } 395 | pthread_mutex_unlock(&run_loop_mutex); 396 | } 397 | 398 | /*************************************************************** 399 | * 400 | * MacIsMainThread - return true if the run loop of this thread 401 | * is the main run loop 402 | * 403 | ***************************************************************/ 404 | int MacIsMainThread() 405 | { 406 | return CFRunLoopGetCurrent() == CFRunLoopGetMain(); 407 | } 408 | 409 | -------------------------------------------------------------------------------- /mac_javabridge_utils.h: -------------------------------------------------------------------------------- 1 | /* mac_javabridge_utils.c - Utilities for managing the Java Bridge on OS/X 2 | 3 | CellProfiler is distributed under the GNU General Public License, 4 | but this file is licensed under the more permissive BSD license. 5 | See the accompanying file LICENSE for details. 6 | 7 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 8 | Copyright (c) 2009-2012 Broad Institute 9 | All rights reserved. 10 | 11 | Please see the AUTHORS file for credits. 12 | 13 | Website: http://www.cellprofiler.org 14 | 15 | 16 | See http://docs.oracle.com/javase/6/docs/technotes/guides/jni/spec/jniTOC.html 17 | for JNI documentation. 18 | */ 19 | 20 | #include "jni.h" 21 | 22 | /********************************************************** 23 | * 24 | * MacStartVM 25 | * 26 | * Start the VM on its own thread, instantiate the thread's runnable 27 | * and run it until exit. 28 | * 29 | * pVMArgs - a pointer to a JavaVMInitArgs structure 30 | * as documented for JNI_CreateJavaVM 31 | * 32 | * Returns only after the thread terminates. Exit code other 33 | * than zero indicates failure. 34 | **********************************************************/ 35 | 36 | JNIEXPORT int MacStartVM(JavaVM **pVM, JavaVMInitArgs *pVMArgs, 37 | const char *class_name, const char *path_to_libjvm, 38 | const char *path_to_libjli); 39 | 40 | /********************************************************** 41 | * 42 | * Stop the JVM 43 | * 44 | * 45 | **********************************************************/ 46 | 47 | JNIEXPORT void MacStopVM(); 48 | 49 | /********************************************************** 50 | * 51 | * Initialize the run loop and synchronization variables 52 | * 53 | **********************************************************/ 54 | 55 | JNIEXPORT void MacRunLoopInit(); 56 | 57 | /********************************************************** 58 | * 59 | * Enter the Mac's run loop 60 | * 61 | **********************************************************/ 62 | 63 | JNIEXPORT void MacRunLoopRun(); 64 | 65 | /************************************************************************* 66 | * 67 | * MacRunLoopReset - reset the run loop state to before start 68 | * 69 | *************************************************************************/ 70 | 71 | JNIEXPORT void MacRunLoopReset(); 72 | 73 | /********************************************************** 74 | * 75 | * Signal the run loop to stop from some thread 76 | * 77 | **********************************************************/ 78 | 79 | JNIEXPORT void MacStopRunLoop(); 80 | 81 | /*************************************************************** 82 | * 83 | * MacIsMainThread - return true if the run loop of this thread 84 | * is the main run loop 85 | * 86 | ***************************************************************/ 87 | 88 | JNIEXPORT int MacIsMainThread(); 89 | 90 | /************************************************************************* 91 | * 92 | * MacRunLoopRunInMode - run the event loop until timeout or stopped 93 | * 94 | *************************************************************************/ 95 | void MacRunLoopRunInMode(double timeInterval); 96 | 97 | /**************************************************************************** 98 | * 99 | * MacRunLoopStop - stop the Mac run loop 100 | * 101 | ****************************************************************************/ 102 | 103 | void MacRunLoopStop(); 104 | 105 | void StopVM(JavaVM *vm); 106 | 107 | int CreateJavaVM(JavaVM **pvm, void **pEnv, void *args); 108 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy 2 | Cython>=0.18.0 3 | 4 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [nosetests] 2 | with-javabridge = True 3 | classpath = javabridge/jars/test.jar 4 | with-coverage=1 5 | cover-erase=1 6 | cover-package=javabridge 7 | 8 | [build_sphinx] 9 | source-dir = docs/ 10 | build-dir = docs/_build 11 | all_files = 1 12 | 13 | [upload_sphinx] 14 | upload-dir = docs/_build/html 15 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """setup.py - build python-javabridge 2 | 3 | python-javabridge is licensed under the BSD license. See the 4 | accompanying file LICENSE for details. 5 | 6 | Copyright (c) 2003-2009 Massachusetts Institute of Technology 7 | Copyright (c) 2009-2013 Broad Institute 8 | All rights reserved. 9 | 10 | """ 11 | from __future__ import print_function 12 | 13 | import errno 14 | import glob 15 | import os 16 | import re 17 | import sys 18 | try: 19 | import sysconfig 20 | except: 21 | import distutils.sysconfig as sysconfig 22 | import subprocess 23 | import traceback 24 | import distutils.log 25 | from distutils.errors import DistutilsSetupError, DistutilsExecError, LinkError 26 | from setuptools import setup, Extension 27 | from setuptools.command.build_ext import build_ext as _build_ext 28 | from distutils.command.build_clib import build_clib 29 | from distutils.ccompiler import CCompiler 30 | 31 | 32 | # Hack to avoid importing the javabridge package 33 | sys.path.append(os.path.join(os.path.dirname(__file__), 'javabridge')) 34 | from locate import * 35 | 36 | def in_cwd(basename): 37 | return os.path.join(os.path.dirname(__file__), basename) 38 | 39 | def build_cython(): 40 | """Compile the pyx files if we have them. 41 | 42 | The git repository has the .pyx files but not the .c files, and 43 | the source distributions that are uploaded to PyPI have the .c 44 | files and not the .pyx files. (The reason for the latter is that 45 | some versions of pip discovers the .pyx files and implicitly adds 46 | a dependency on Cython.) Therefore, if we have the .pyx files, 47 | compile them. 48 | 49 | """ 50 | stems = ['_javabridge', '_javabridge_mac', '_javabridge_nomac'] 51 | pyx_filenames = [in_cwd(s + '.pyx') for s in stems] 52 | c_filenames = [in_cwd(s + '.c') for s in stems] 53 | nc_pyx_filenames = [ 54 | pyx for pyx, c in zip(pyx_filenames, c_filenames) 55 | if os.path.exists(pyx) and needs_compilation(c, pyx)] 56 | if len(nc_pyx_filenames) > 0: 57 | cython_cmd = [sys.executable, '-m', 'cython', "-3"] 58 | cmd = cython_cmd + nc_pyx_filenames 59 | env = dict(os.environ) 60 | env['PYTHONPATH'] = os.pathsep.join(sys.path) 61 | try: 62 | subprocess.check_call(cmd, env=env) 63 | except FileNotFoundError: 64 | raise RuntimeError("Failed to find Cython: {}".format(cython_cmd)) 65 | 66 | def get_jvm_include_dirs(): 67 | '''Return a sequence of paths to include directories for JVM defs''' 68 | jdk_home = find_jdk() 69 | java_home = find_javahome() 70 | include_dirs = [] 71 | if is_win: 72 | if jdk_home is not None: 73 | jdk_include = os.path.join(jdk_home, "include") 74 | jdk_include_plat = os.path.join(jdk_include, sys.platform) 75 | include_dirs += [jdk_include, jdk_include_plat] 76 | elif is_mac: 77 | where_jni_h_is_post_6 = os.path.join(java_home, 'include') 78 | if os.path.isfile(os.path.join(where_jni_h_is_post_6, "jni.h")): 79 | 80 | include_dirs += [where_jni_h_is_post_6, 81 | os.path.join(java_home, 'include', 'darwin')] 82 | else: 83 | include_dirs += ["/System/Library/Frameworks/JavaVM.Framework/Headers"] 84 | elif is_linux: 85 | include_dirs += [os.path.join(jdk_home,'include'), 86 | os.path.join(jdk_home,'include','linux'), 87 | os.path.join(jdk_home,'default-java','include'), 88 | os.path.join(jdk_home,'default-java','include','linux') 89 | ] 90 | 91 | return include_dirs 92 | 93 | def ext_modules(): 94 | extensions = [] 95 | extra_link_args = None 96 | java_home = find_javahome() 97 | if java_home is None: 98 | raise Exception("JVM not found") 99 | jdk_home = find_jdk() 100 | include_dirs = get_jvm_include_dirs() 101 | libraries = None 102 | library_dirs = None 103 | javabridge_sources = ['_javabridge.c'] 104 | _, jvm_so = find_jre_bin_jdk_so() 105 | if is_mac: 106 | javabridge_sources += ['_javabridge_mac.c'] 107 | extra_link_args = ['-framework', 'CoreFoundation'] 108 | else: 109 | javabridge_sources += ['_javabridge_nomac.c'] 110 | if is_win: 111 | jdk_lib = os.path.join(jdk_home, "lib") 112 | if is_mingw: 113 | # 114 | # Build libjvm from jvm.dll on Windows. 115 | # This assumes that we're using mingw32 for build 116 | # 117 | # generate the jvm.def file matching to the jvm.dll 118 | cmd = ["gendef", os.path.join(jdk_home,"jre\\bin\\server\\jvm.dll")] 119 | p = subprocess.Popen(cmd) 120 | p.communicate() 121 | cmd = ["dlltool", "--dllname", 122 | jvm_so, 123 | "--output-lib","libjvm.a", 124 | "--input-def","jvm.def", 125 | "--kill-at"] 126 | p = subprocess.Popen(cmd) 127 | p.communicate() 128 | library_dirs = [os.path.abspath("."), jdk_lib] 129 | else: 130 | # 131 | # Use the MSVC lib in the JDK 132 | # 133 | extra_link_args = ['/MANIFEST'] 134 | library_dirs = [jdk_lib] 135 | javabridge_sources.append("strtoull.c") 136 | 137 | libraries = ["jvm"] 138 | elif is_mac: 139 | javabridge_sources += [ "mac_javabridge_utils.c" ] 140 | elif is_linux: 141 | library_dirs = [os.path.dirname(jvm_so)] 142 | libraries = ["jvm"] 143 | extension_kwargs = dict( 144 | name="javabridge._javabridge", 145 | sources=javabridge_sources, 146 | libraries=libraries, 147 | library_dirs=library_dirs, 148 | include_dirs=include_dirs, 149 | extra_link_args=extra_link_args) 150 | if not is_win: 151 | extension_kwargs["runtime_library_dirs"] =library_dirs 152 | 153 | extensions += [Extension(**extension_kwargs)] 154 | return extensions 155 | 156 | SO = ".dll" if sys.platform == 'win32' \ 157 | else ".jnilib" if sys.platform == 'darwin'\ 158 | else ".so" 159 | 160 | def needs_compilation(target, *sources): 161 | try: 162 | target_date = os.path.getmtime(target) 163 | except OSError as e: 164 | if e.errno != errno.ENOENT: 165 | raise 166 | return True 167 | for source in sources: 168 | source_date = os.path.getmtime(source) 169 | if source_date > target_date: 170 | return True 171 | return False 172 | 173 | def package_path(relpath): 174 | return os.path.normpath(os.path.join(os.path.dirname(__file__), relpath)) 175 | 176 | class build_ext(_build_ext): 177 | java2cpython_sources = ["java/org_cellprofiler_javabridge_CPython.c"] 178 | 179 | def initialize_options(self): 180 | from numpy import get_include 181 | _build_ext.initialize_options(self) 182 | if self.include_dirs is None: 183 | self.include_dirs = get_include() 184 | else: 185 | self.include_dirs += get_include() 186 | 187 | def run(self, *args, **kwargs): 188 | self.build_java() 189 | result = build_cython() 190 | if self.inplace: 191 | dirty = False 192 | for source in self.get_source_files(): 193 | source_mtime = os.stat(source).st_mtime 194 | for output in self.get_outputs(): 195 | if not os.path.isfile(output) or \ 196 | os.stat(output).st_mtime < source_mtime: 197 | dirty = True 198 | break 199 | output_dir = os.path.splitext( 200 | self.get_ext_fullpath("javabridge.jars"))[0] 201 | java2cpython_lib = os.path.join( 202 | output_dir, self.get_java2cpython_libdest()[1]) 203 | if (not os.path.exists(java2cpython_lib)) or \ 204 | any([os.stat(src).st_mtime > os.stat(java2cpython_lib).st_mtime 205 | for src in self.java2cpython_sources]): 206 | dirty = True 207 | else: 208 | dirty = True 209 | if dirty: 210 | result = _build_ext.run(self, *args, **kwargs) 211 | self.build_java2cpython() 212 | return result 213 | 214 | def build_jar_from_sources(self, jar, sources): 215 | if sys.platform == 'win32': 216 | sources = [source.replace("/", os.path.sep) for source in sources] 217 | jar_filename = jar.rsplit(".", 1)[1] + ".jar" 218 | jar_dir = os.path.dirname(self.get_ext_fullpath(jar)) 219 | jar = os.path.join(jar_dir, jar_filename) 220 | jar_command = [find_jar_cmd(), 'cf', package_path(jar)] 221 | 222 | javac_loc = find_javac_cmd() 223 | dirty_jar = False 224 | javac_command = [javac_loc] 225 | for source in sources: 226 | javac_command.append(package_path(source)) 227 | if needs_compilation(jar, source): 228 | dirty_jar = True 229 | 230 | self.spawn(javac_command) 231 | if dirty_jar: 232 | if not os.path.exists(os.path.dirname(jar)): 233 | os.mkdir(os.path.dirname(jar)) 234 | for source in sources: 235 | for klass in glob.glob(source[:source.rindex('.')] + '*.class'): 236 | java_klass_path = klass[klass.index(os.path.sep) + 1:].replace(os.path.sep, "/") 237 | jar_command.extend(['-C', package_path('java'), java_klass_path]) 238 | self.spawn(jar_command) 239 | 240 | def build_java2cpython(self): 241 | sources = self.java2cpython_sources 242 | distutils.log.info("building java2cpython library") 243 | 244 | 245 | # First, compile the source code to object files in the library 246 | # directory. (This should probably change to putting object 247 | # files in a temporary build directory.) 248 | include_dirs = \ 249 | [sysconfig.get_config_var("INCLUDEPY"), "java"] +\ 250 | get_jvm_include_dirs() 251 | python_lib_dir, lib_name = self.get_java2cpython_libdest() 252 | library_dirs = [python_lib_dir] 253 | output_dir = os.path.join(os.path.dirname( 254 | self.get_ext_fullpath("javabridge.jars")), "jars") 255 | export_symbols = ['Java_org_cellprofiler_javabridge_CPython_exec'] 256 | objects = self.compiler.compile(sources, 257 | output_dir=self.build_temp, 258 | include_dirs=include_dirs, 259 | debug=self.debug) 260 | ver = sys.version_info 261 | needs_manifest = sys.platform == 'win32' and ver.major == 2 and not is_mingw 262 | extra_postargs = ["/MANIFEST"] if needs_manifest else None 263 | libraries = ["python{}{}".format(ver.major, ver.minor)] if is_mingw else None 264 | self.compiler.link( 265 | CCompiler.SHARED_OBJECT, 266 | objects, lib_name, 267 | output_dir=output_dir, 268 | debug=self.debug, 269 | library_dirs=library_dirs, 270 | libraries=libraries, 271 | export_symbols=export_symbols, 272 | extra_postargs=extra_postargs) 273 | if needs_manifest: 274 | temp_dir = os.path.dirname(objects[0]) 275 | manifest_name = lib_name +".manifest" 276 | lib_path = os.path.join(output_dir, lib_name) 277 | manifest_file = os.path.join(temp_dir, manifest_name) 278 | lib_path = os.path.abspath(lib_path) 279 | manifest_file = os.path.abspath(manifest_file) 280 | out_arg = '-outputresource:%s;2' % lib_path 281 | try: 282 | self.compiler.spawn([ 283 | 'mt.exe', '-nologo', '-manifest', manifest_file, 284 | out_arg]) 285 | except DistutilsExecError as msg: 286 | raise LinkError(msg) 287 | 288 | def get_java2cpython_libdest(self): 289 | if is_win: 290 | python_lib_dir = os.path.join( 291 | sysconfig.get_config_var('platbase'), 292 | 'LIBS') 293 | lib_name = "java2cpython" + SO 294 | else: 295 | python_lib_dir = sysconfig.get_config_var('LIBDIR') 296 | lib_name = "libjava2cpython" + SO 297 | return python_lib_dir, lib_name 298 | 299 | 300 | def build_jar_from_single_source(self, jar, source): 301 | self.build_jar_from_sources(jar, [source]) 302 | 303 | def build_runnablequeue(self): 304 | jar = 'javabridge.jars.runnablequeue' 305 | source = 'java/org/cellprofiler/runnablequeue/RunnableQueue.java' 306 | self.build_jar_from_single_source(jar, source) 307 | 308 | def build_cpython(self): 309 | jar = 'javabridge.jars.cpython' 310 | sources = [ 311 | 'java/org/cellprofiler/javabridge/CPython.java', 312 | 'java/org/cellprofiler/javabridge/CPythonInvocationHandler.java'] 313 | self.build_jar_from_sources(jar, sources) 314 | 315 | def build_test(self): 316 | jar = 'javabridge.jars.test' 317 | source = 'java/org/cellprofiler/javabridge/test/RealRect.java' 318 | self.build_jar_from_single_source(jar, source) 319 | 320 | def build_java(self): 321 | self.build_runnablequeue() 322 | self.build_test() 323 | self.build_cpython() 324 | 325 | 326 | def pep440_compliant(ver): 327 | if ver is None: 328 | return ver 329 | m = re.match(r"^(?P(\d[\d\.]*))$", ver) 330 | if m: 331 | return ver 332 | m = re.match(r"^(?P(\d[\d\.]*))-(?P\d+)-(?P.*)$", ver) 333 | if m: 334 | res = m.group('version') + '.post' + m.group('count') + '+' + m.group('sha') 335 | return res 336 | return ver 337 | 338 | 339 | def get_version(): 340 | """Get version from git or file system. 341 | 342 | If this is a git repository, try to get the version number by 343 | running ``git describe``, then store it in 344 | javabridge/_version.py. Otherwise, try to load the version number 345 | from that file. If both methods fail, quietly return None. 346 | 347 | """ 348 | git_version = None 349 | if os.path.exists(os.path.join(os.path.dirname(__file__), '.git')): 350 | import subprocess 351 | try: 352 | git_version = subprocess.Popen(['git', 'describe'], 353 | stdout=subprocess.PIPE).communicate()[0].strip().decode('utf-8') 354 | except: 355 | pass 356 | 357 | version_file = os.path.join(os.path.dirname(__file__), 'javabridge', 358 | '_version.py') 359 | if os.path.exists(version_file): 360 | with open(version_file) as f: 361 | cached_version_line = f.read().strip() 362 | try: 363 | # From http://stackoverflow.com/a/3619714/17498 364 | cached_version = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]", 365 | cached_version_line, re.M).group(1) 366 | except: 367 | raise RuntimeError("Unable to find version in %s" % version_file) 368 | else: 369 | cached_version = None 370 | 371 | if git_version and git_version != cached_version: 372 | with open(version_file, 'w') as f: 373 | print('__version__ = "%s"' % git_version, file=f) 374 | 375 | return pep440_compliant(git_version or cached_version) 376 | 377 | 378 | if __name__ == '__main__': 379 | if '/' in __file__: 380 | os.chdir(os.path.dirname(__file__)) 381 | 382 | setup(name="javabridge", 383 | version=get_version(), 384 | description="Python wrapper for the Java Native Interface", 385 | long_description='''The python-javabridge package makes it easy to start a Java virtual 386 | machine (JVM) from Python and interact with it. Python code can 387 | interact with the JVM using a low-level API or a more convenient 388 | high-level API. Python-javabridge was developed for and is used by the 389 | cell image analysis software CellProfiler (cellprofiler.org).''', 390 | url="http://github.com/CellProfiler/python-javabridge/", 391 | packages=['javabridge', 'javabridge.tests'], 392 | classifiers=['Development Status :: 5 - Production/Stable', 393 | 'License :: OSI Approved :: BSD License', 394 | 'Programming Language :: Java', 395 | 'Programming Language :: Python :: 2', 396 | 'Programming Language :: Python :: 3' 397 | ], 398 | license='BSD License', 399 | setup_requires=['cython', 'numpy'], 400 | install_requires=['numpy'], 401 | tests_require="nose", 402 | entry_points={'nose.plugins.0.10': [ 403 | 'javabridge = javabridge.noseplugin:JavabridgePlugin' 404 | ]}, 405 | test_suite="nose.collector", 406 | ext_modules=ext_modules(), 407 | package_data={"javabridge": [ 408 | 'jars/*.jar', 'jars/*%s' % SO, 'VERSION']}, 409 | cmdclass={'build_ext': build_ext}) 410 | -------------------------------------------------------------------------------- /strtoull.c: -------------------------------------------------------------------------------- 1 | /* strtoull.c - replacement for strtoull.c function missing from msvcrt */ 2 | #include 3 | 4 | extern unsigned long long int strtoull(const char *s, char **endptr, int base) 5 | { 6 | unsigned long long int value = 0; 7 | 8 | while (isspace(*s)){ 9 | s++; 10 | } 11 | 12 | if (((base == 0) || (base == 16)) && (s[0] == '0') && 13 | (s[1] == 'x' || s[1] == 'X')) { 14 | s += 2; 15 | base = 16; 16 | } else if (((base == 0) || (base == 8)) && (s[0] == '0')) { 17 | base = 8; 18 | } 19 | while (1) { 20 | unsigned long long int digit = 0; 21 | if (isdigit(*s)) { 22 | digit = *s - '0'; 23 | } else if ((base > 10) && isxdigit(*s)) { 24 | digit = *s + 10 - 'A'; 25 | } else { 26 | break; 27 | } 28 | if (digit >= base) break; 29 | value += digit; 30 | s++; 31 | } 32 | 33 | if (endptr) { 34 | *endptr = (char *)s; 35 | } 36 | return value; 37 | } 38 | --------------------------------------------------------------------------------