python调用Java代码,完成JBPM工作流application

1.缘由

有一庞大Python django web工程,要引入工作流引擎,像OA一样,方便的流程控制与管理。Python或django关于工作流的开源插件,稀少,而且弱爆了,最终选用java的开源框架JBPM。为了使Python工程整合Java框架,尝试过jbpm-console提供的 REST, 以失败告终,最终选用Python 直接调用Java代码,操作JBPM.


1.1python工程REST与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方法或属性是Python关键字时,无法访问
    • 无法访问不在包下面(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的代理类)

  • 缺点

    • windows安装十分困难,无预编译版本,估计必须GCC(MinGW, vs08, vs10均失败)

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代码

完整工程代码地址http://download.csdn.net/detail/secretx/7814991


3.1Python代码

#coding=utf8

import os
javapath = "/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 autoclass

ProcessMain = autoclass('com.sample.ProcessMain')  #.号分隔
ProcessMain.pythonCallMeStatic()     #ok,    before ProcessMain(), can call java static method
# ProcessMain.pythonCallMeInstance() #error, before ProcessMain(), can not call java instance method

process_main = ProcessMain()
process_main.pythonCallMeInstance()
process_main.pythonCallMeStatic()

ProcessMain.pythonCallMeStatic()
ProcessMain.pythonCallMeInstance()  # after ProcessMain(), python does not distinguish static/instance method
print "-----------------------------------------"



"""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.xml

		KieBase 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接口 getAuditLogService



		ksession.startProcess("com.sample.bpmn.hello");



		// let john execute Task 1

		List<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 2

		list = 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;

	}



}




  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值