程式扎記: [ Java 文章收集 ] Accessing Jython from Java Without Using jythonc

標籤

2014年9月17日 星期三

[ Java 文章收集 ] Accessing Jython from Java Without Using jythonc

Source From Here 
Preface 
You may or may not know that it is possible to access Jython code from Java without compiling it using the jythonc utility. This technique is possible using a mixture of Java interfaces and usage of the PythonInterpreter. As a matter of fact, I believe that using this technique correctly is more effective than using jythonc. 

To put it simply, to use this technique you must create a "factory" method which uses the PythonInterpreter class to interpret a .py module for use within Java code. Any Java code that uses the Jython code should be coded against an interface which is implemented by the Jython code. 

In order to provide a fully functional example, I've created a simple application with hard-coded data. This application shows the potential for using this technique within your Java applications to have the ability for use of dynamic Jython objects. 

The application is simply called "jyinterface" and it contains four pieces of code: 
* Main.java
* JythonFactory.java - Uses the PythonInterpreter to return a Java object
* EmployeeType.java - An interface which will be implemented by a Jython bean -Employee.py - Jython bean representing an employee

Step By Step 
We'll start by coding the "EmployeeType.java" interface which is what our Java code will use in order to interact with the Jython object: 
  1. package test.jython;  
  2.   
  3. public interface EmployeeType {  
  4.     public String getEmployeeFirst();  
  5.     public String getEmployeeLast();  
  6.     public String getEmployeeId();  
  7.     public String getPID();  
  8. }  
The Jython bean "Employee.py" is just a simple Jython object which implements the Java interface "EmployeeType.java": 
  1. # Jython source file  
  2. from test.jython import EmployeeType  
  3. import os  
  4.   
  5. class Employee(EmployeeType):  
  6.     def __init__(self):  
  7.         self.first = "Josh"  
  8.         self.last  = "Juneau"  
  9.         self.id = "myempid"  
  10.           
  11.       
  12.     def getEmployeeFirst(self):  
  13.         return self.first  
  14.   
  15.     def getEmployeeLast(self):  
  16.        return self.last  
  17.   
  18.     def getEmployeeId(self):  
  19.        return self.id  
  20.   
  21.     def getPID(self):  
  22.        return str(os.getpid())  
Next, the most powerful code for this technique is the "JythonFactory.java" class. This code defines a method which interprets a Jython module into Java and returns for use within Java code. The best part about creating a factory class such as this one is reuse! The factory can be coded in many different ways, but this way allows for reuse because you can essentially pass any Java interface/Jython module to it. 
  1. package test.jython;  
  2.   
  3. import org.python.util.PythonInterpreter;  
  4.   
  5. public class JythonFactory {  
  6.     private static JythonFactory instance = null;  
  7.   
  8.     public synchronized static JythonFactory getInstance() {  
  9.         if (instance == null) {  
  10.             instance = new JythonFactory();  
  11.         }  
  12.   
  13.         return instance;  
  14.   
  15.     }  
  16.   
  17.     public static Object getJythonObject(String interfaceName, String pathToJythonModule) {  
  18.         Object javaInt = null;  
  19.         PythonInterpreter interpreter = new PythonInterpreter();  
  20.         interpreter.execfile(pathToJythonModule);  
  21.         String tempName = pathToJythonModule.substring(pathToJythonModule  
  22.                 .lastIndexOf("/") + 1);  
  23.         tempName = tempName.substring(0, tempName.indexOf("."));  
  24.         System.out.println(tempName);  
  25.         String instanceName = tempName.toLowerCase();  
  26.         String javaClassName = tempName.substring(01).toUpperCase()  
  27.                 + tempName.substring(1);  
  28.         String objectDef = "=" + javaClassName + "()";  
  29.         interpreter.exec(instanceName + objectDef);  
  30.         try {  
  31.             Class JavaInterface = Class.forName(interfaceName);  
  32.             javaInt = interpreter.get(instanceName).__tojava__(JavaInterface);  
  33.         } catch (ClassNotFoundException ex) {  
  34.             ex.printStackTrace(); // Add logging here  
  35.         }  
  36.   
  37.         return javaInt;  
  38.     }  
  39. }  
As we stated previously, a Java interface/Jython module combo needs to be passed to the getJythonObject method in order to return the resulting code. In the following piece of code, you can see how this is done. Simply pass in two strings: 
* Fully qualified name of the Java Interface
* Full path to the Jython code module

Here is the "Main.java" code: 
  1. package test.jython;  
  2.   
  3. public class Main {  
  4.   
  5.     public static void main(String[] args) {  
  6.         JythonFactory jf = JythonFactory.getInstance();  
  7.         EmployeeType eType = (EmployeeType) jf.getJythonObject(  
  8.                                "test.jython.EmployeeType""src/test/jython/Employee.py");  
  9.         System.out.println("Employee Name: " + eType.getEmployeeFirst() + " " +   
  10.                     eType.getEmployeeLast());  
  11.         System.out.println("Employee ID: " + eType.getEmployeeId());  
  12.         System.out.printf("Test output: %s\n", eType.getPID());  
  13.     }  
  14. }  
This technique is powerful because it allows an application to use code which can be interchanged or dynamically updated without re-deployment or re-compile. It also follows a great Java practice which is code against Java interfaces!! One downfall to this approach is that the code is interpreted every time it is invoked, so the performance may not be as good as using a jythonc compiled piece of code. It obviously depends upon the requirements of the application, but the usefulness of this technique may outweigh the performance factor in many cases. 

Next time you plan to create a Java application that contains some Jython code, give this technique a try... 

沒有留言:

張貼留言

網誌存檔

關於我自己

我的相片
Where there is a will, there is a way!