標籤:地址 sig test 整合 內部類 notify -- led this
1.緣由
有一龐大Python django webproject,要引入工作流程引擎,像OA一樣。方便的流程式控制制與管理。Python或django關於工作流程的開源外掛程式,稀少,並且弱爆了,終於選用java的開源架構JBPM。為了使Pythonproject整合Java架構,嘗試過jbpm-console提供的 REST, 以失敗告終,終於選用Python 直接調用Java代碼。操作JBPM.
1.1pythonprojectREST與JBPM Workbench互動 失敗
REST URL格式
http://host:8080/jbpm-console/rest/runtime/{deploymentId}/process/{processDefId}/start
比如
http://localhost:8080/jbpm-console/rest/runtime/com.fun:test:1.0.0/process/test.TaskData/start
並不是如文檔所言以
/runtime 打頭。REST介面是jbpm-console.war子項目提供的,必須部署此項目。
失敗原因:流程複雜而且須要處理複雜資料,JBPM內部能夠建立資料模型,使用POJO傳遞或儲存複雜資料,可是REST介面無法POST某種格式的資料。使jbpm-console自己主動映射成POJO,假設自己寫java代碼實現REST 資料轉POJO,可行度再說,既然都自己寫Java代碼了。就不是必需走REST,網路慢。不如直接Java代碼完畢JBPM邏輯。
比如:JBPM建立了一個資料模型Person,形如
public class Person{ String name = null; int age = 0; boolean isMan= false;}REST介面沒法POST資料,使JBPM能映射成一個Person類的執行個體,預設jbpm-console會當作三個零散變數(參數)處理,不會當一個對象的三個屬性。所以預設會在資料庫裡variableinstancelog表存入三行記錄,每行代表一個變數。達不到期望結果。僅僅有一條記錄,僅僅存一個對象的序列化資訊。
假設某大神知道怎樣POST資料(或Python簡單處理POST資料後再發請求),jbpm-console能自己主動映射成POJO。請留言。銘謝!
2.Python 直接調用 Java
2.1 jPype 不採用
- 坑(能夠人為避免)
- 當Java方法或屬性是Pythonkeyword時,無法訪問
- 無法訪問不在包以下(default包)的Java代碼
缺點
適合Python26。實測27版本號碼啟動jvm失敗
Java特殊方法不支援,如java.lang.Class.forName(String classname),硬傷(由於此方法在架構/容器代碼中十分頻繁)
無法執行個體化匿名內部類。僅能執行個體化靜態內部類
線程同步:明白支援synchronized類同步,notify, notifyAll, wait等未提及怎樣處理
明白表示有較大效能影響:can impose rather large performance bottlenecks
2.2 pyjnius
採用
長處
封裝出色。文檔未提及也未發現有特殊Java文法或進階機制限制(明白支援重載)
大量運用於Python自己主動化測試安卓應用,與Java語言親和度更高
支援Python繼承/實現java的抽象類別/介面(介面中靜態成員不被支援)
提供一個近乎萬能的autoclass。反射出一個Java類的代理(能在Python層面實現Java的代理類)
缺點
3.python<-->java se <-->jbpm <-->hibernate<-->mysql原理簡述
use pyjnius connect python and java
java se code uses CLASSPATH include jbpm jars and hibernate jars(must do before import pyjnius)
jbpm uses hibernate in two step
jbpm uses jBPM.proporties to setup and register DataSource in specified db(we specify mysql)
jbpm calls hibernate to operate db, but hard code to act like use H2 db, we force hibernate act like use mysql by passing custom params when create it‘s entiy manager(more details in code)
hibernate operates db, I have find a way to directly control it‘s behavior completely, transparently
Codes speak louder. More details in example.
4. 附Python和Java代碼
完整project代碼地址http://download.csdn.net/detail/secretx/7814991
3.1Python代碼
#coding=utf8import osjavapath = "/home/luodh/workspace/jbpm-6.0.0.Final-bin/*:/home/luodh/workspace/jbpm-6.0.0.Final-bin/lib/*"os.environ[‘CLASSPATH‘] = javapath"""call java code directly"""from jnius import autoclassProcessMain = autoclass(‘com.sample.ProcessMain‘) #.號分隔ProcessMain.pythonCallMeStatic() #ok, before ProcessMain(), can call java static method# ProcessMain.pythonCallMeInstance() #error, before ProcessMain(), can not call java instance methodprocess_main = ProcessMain()process_main.pythonCallMeInstance()process_main.pythonCallMeStatic()ProcessMain.pythonCallMeStatic()ProcessMain.pythonCallMeInstance() # after ProcessMain(), python does not distinguish static/instance methodprint "-----------------------------------------""""use a python proxy class"""from jnius import JavaClass, MetaJavaClass, JavaMethod, JavaField class PythonProxyJavaClass(JavaClass): __javaclass__ = "com/sample/ProcessMain" # /分隔. __metaclass__ = MetaJavaClass # must be this# __javaconstructor__ = ( # 建構函式,源於反編譯# "()V",# )# 建構函式規則尚未確定,文檔有誤 pythonCallMeStatic = JavaMethod("()V", static=True) pythonCallMeInstance = JavaMethod("()V") s1 = JavaField("Ljava/lang/String;", static=True) s2 = JavaField("Ljava/lang/String;") PythonProxyJavaClass.pythonCallMeStatic()# PythonProxyJavaClass.pythonCallMeInstance() # 執行個體化對象之前,不可調用執行個體方法 PythonProxyJavaClass().pythonCallMeStatic() # 執行個體化對象之後,python不區分靜態(類)方法和非靜態(執行個體)方法PythonProxyJavaClass().pythonCallMeInstance() PythonProxyJavaClass.pythonCallMeStatic()PythonProxyJavaClass.pythonCallMeInstance() """python嚴格區分靜態/非靜態Field"""print PythonProxyJavaClass.s1# print PythonProxyJavaClass.s2 # error, 類不與成員變數綁定print PythonProxyJavaClass().s1 # none,執行個體不與靜態變數綁定print PythonProxyJavaClass().s2
3.2 Java代碼(jbpm相關)
package com.sample;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.Properties;import javax.persistence.EntityManagerFactory;import javax.persistence.Persistence;import org.jbpm.test.JBPMHelper;import org.kie.api.KieBase;import org.kie.api.KieServices;import org.kie.api.runtime.KieContainer;import org.kie.api.runtime.KieSession;import org.kie.api.runtime.manager.RuntimeEngine;import org.kie.api.runtime.manager.RuntimeEnvironmentBuilder;import org.kie.api.runtime.manager.RuntimeManager;import org.kie.api.runtime.manager.RuntimeManagerFactory;import org.kie.api.task.TaskService;import org.kie.api.task.model.TaskSummary;public class ProcessMain {public static String s1 = "I‘m static field";public String s2 = "I‘m instance field";public static RuntimeManager manager = null;public static void main(String[] args) {callJBPM(false);System.exit(0);}public void pythonCallMeInstance(){callJBPM(true);}public static void pythonCallMeStatic(){callJBPM(true);}public static void callJBPM(boolean fake){if (fake){System.out.println("I‘m java, python call me to play jbpm. I don‘t know how to include jbpm jars.");return;}KieServices ks = KieServices.Factory.get();KieContainer kContainer = ks.getKieClasspathContainer();//載入kmodule.xmlKieBase kbase = kContainer.getKieBase("kbase");// 依據暴露的名字(kbase標籤的name屬性)擷取知識庫對象if(manager == null) {manager = createRuntimeManager(kbase);// use synchronized static block}RuntimeEngine engine = manager.getRuntimeEngine(null);KieSession ksession = engine.getKieSession();TaskService taskService = engine.getTaskService();// engine一共3介面 getAuditLogServiceksession.startProcess("com.sample.bpmn.hello");// let john execute Task 1List<TaskSummary> list = taskService.getTasksAssignedAsPotentialOwner("john", "en-UK");TaskSummary task = list.get(0);System.out.println("John is executing task " + task.getName());taskService.start(task.getId(), "john");taskService.complete(task.getId(), "john", null);// let mary execute Task 2list = taskService.getTasksAssignedAsPotentialOwner("mary", "en-UK");task = list.get(0);System.out.println("Mary is executing task " + task.getName());taskService.start(task.getId(), "mary");taskService.complete(task.getId(), "mary", null);manager.disposeRuntimeEngine(engine);//System.exit(0);}private static RuntimeManager createRuntimeManager(KieBase kbase) {//因為要擷取task,須要TaskService進行入庫操作,需提前啟動資料庫,準備資料來源//JBPMHelper.startH2Server();//不用h2,則不啟動JBPMHelper.setupDataSource();Map<String, String> map = configHibernate();EntityManagerFactory emf = Persistence.createEntityManagerFactory("org.jbpm.persistence.jpa", map);RuntimeEnvironmentBuilder builder = RuntimeEnvironmentBuilder.Factory.get().newDefaultBuilder().entityManagerFactory(emf).knowledgeBase(kbase);return RuntimeManagerFactory.Factory.get().newSingletonRuntimeManager(builder.get(), "com.sample:example:1.0");//any_non_blank_string}private static Map<String, String> configHibernate(){Map<String, String> map = new HashMap<String, String>();Properties properties = new Properties(); try { properties.load(JBPMHelper.class.getResourceAsStream("/jBPM.properties")); } catch (Throwable t) { // do nothing, use defaults } map.put("hibernate.dialect", properties.getProperty("hibernate.dialect", "org.hibernate.dialect.MySQL5Dialect"));map.put("hibernate.hbm2ddl.auto", properties.getProperty("hibernate.hbm2ddl.auto", "update"));map.put("hibernate.show_sql", properties.getProperty("hibernate.show_sql", "false"));map.put("hibernate.format_sql", properties.getProperty("hibernate.format_sql", "true"));return map;}}
python調用Java代碼,完畢JBPM工作流程application