概
述
你可以从这里找到常见问题的解答。
数据库
Shark
怎样与其他数据库进行配置?
结束安装过程后,你将有已建好的
HipersonicSQL
数据库。这还是比较有用的,
Shark
也提供了你其他数据库的选择:
DB2, PostgreSQL, MySQL,....
首先你要停止任何可能正在运行的
Shark
实例(
POJO swing
管理
/worklist
管理器,或
CORBA
服务器)。
编辑
configure.properties
文件并为属性设置参数:
db_loader_job
目录名包含了
Octopus
装载工作,选项有:
db2, hsql, informix, msql, mysql, oracle, postgresql, sybase
db_user
数据库验证用户名
db_passwd
数据库验证密码
db_ext_dirs
包含
JDBC
驱动的
jar
文件目录,如果你需要更多,一个
directory
将被指定
-
通过
${path.separator}
连接它们
${db_loader_job}_JdbcDriver
要使用的
JDBC
驱动的类名
这些项目都被填入了默认值。
${db_loader_job}_Connection_Url
完整的数据库
URL
这些项目也被填入了默认值。
运行
configure.[bat|sh]
注意
当装载新建的数据库时,
Octopus
将抱怨无法卸载索引和表,但这些警告应忽略掉。
怎样清理
Shark
的数据库?
在测试过程中,你想清理数据库并从头开始。为了清理数据库,你可运行
configure.[bat|sh]
文件。如果你不想等待多余的过滤,
war
文件存档的话
-
你应该运行
bin/recreateDB.[bat|sh]
文件。
方法稍后只运行
Octopus
装载工作来卸载以及建立表和索引。
怎样调整数据库访问?
Shark
引擎是个组件包,部分利用
DODS
与数据库交互。
似乎有些控制
DODS
特性的参数很难理解。
DatabaseManager.DB.*.Connection.MaxPoolSize
连接池能承受连接的最大数目。如果你知道程序不需要太多并发连接,它可以安全的减少数目。
DatabaseManager.DB.*.ObjectId.CacheSize
作为组分配和保存在内存中的对象标识符数目。这些标识符被指派给新数据对象添加到数据库。
DatabaseManager.defaults.cache.maxCacheSize
根据对象存储的最大数目限制的缓存大小。当缓存已满,缓存中的对象按照
LRU
(最近使用)原则被替换为新对象。
DatabaseManager.defaults.cache.maxSimpleCacheSize
DatabaseManager.defaults.cache.maxComplexCacheSize
除了主要对象缓存,还有两种查询缓存可用(简单和复杂)。查询缓存也是
LRU
缓存。
DatabaseManager.defaults.maxExecuteTime
每次运行查询都比
maxExecuteTime
打印到(
SQL
语句,执行时间和
maxExecuteTime
)日志文件的时间长。这种方式可在你的程序或引擎内部发现很细微的可能问题。
DatabaseManager.DB.sharkdb.Connection.MaxPoolSize=300
DatabaseManager.DB.sharkdb.ObjectId.CacheSize=200
DatabaseManager.defaults.cache.maxCacheSize=100
DatabaseManager.defaults.cache.maxSimpleCacheSize=50
DatabaseManager.defaults.cache.maxComplexCacheSize=25
DatabaseManager.defaults.maxExecuteTime=200
大量的缓存也不总是带来高性能,这将导致内存的浪费和其他问题。
注意
如果你在相同数据库上运行多个引擎实例(例如
集群),那就既不要
DODS
也不要
Shark
缓存。
客户端接口
怎样使用
Shark
库
客户端程序通过
org.enhydra.shark.api.client
包中的一组接口来访问
Shark
库。首先客户端程序应该配置库或通过调用不带参数的
configure()
方法(接着采用
Shark.conf
文件配置的
jar
),或通过指定文件名(做为
String
或
File
对象)或通过准备并调用
Properties
对象方法。配置完毕后
org.enhydra.shark.Shark.getInstance()
返回一个
SharkInterface
实例。从这点开始,客户端程序开发者偏爱(或任务)知道程序怎样使用库,怎样得到连接和执行指派或得到
AdminInterface
以及管理用户、组、包,
...
例子
1.
不是非常有用的
work-list
管理器
例子的第一行,引擎使用
conf/Shark.conf
文件进行配置。当得到连接和成功连接后,引擎获取
Resource
对象,来确定为用户进行了多少指派(第
4
行)。
Shark.configure("conf/Shark.conf");
SharkConnection sConn = Shark.getInstance().getConneciton();
sConn.connect(userId, passwd, engineName, scope);
if (0 < sConn.getResourceObject().how_many_work_item())
System.err.println("Oh, let these tasks wait until tomorrow!");
}
System.out.println("Job done!");
例子
2.
用户组管理
该范例不能运行。如果你把
Shark
配置为使用
LDAP user-group
组件,但是基于组件的数据库开始时确是空的,所以要做任何实际的工作你都需要定义至少一个组和用户。
Shark.configure();
UserGroupAdministration ugAdmin =
Shark.getInstance().getAdminInterface().getUserGroupAdministration()
ugAdmin.crateGroup("developers","sweat-shop");
ugAdmin.createUser("developers", "user", "secret", "Jane Doe", "some@email.address");
System.out.println("Group and user created!");
例子
3.
装载包到
Shark
库
包的
XPDL
文件位置与包知识库的根路径有关。在你执行该操作之前,通过在客户端对象调用
getDefinedPackagesPath()
方法你将得到所有的包相关路径。首先根据包知识库的根路径,找到你需要包的
XPDL
文件位置,接着要有
PackageAdministation
实例。
String xpdlName = "test.xpdl";
Properties props = new Properties();
props.setProperty("enginename","testSharkInstance");
props.setProperty("EXTERNAL_PACKAGES_REPOSITORY","c:/Shark/repository/xpdls");
Shark.configure(props);
String pkgId = Shark.getInstance().getRepositoryManager().getPackageId(xpdlName);
PackageAdministration pa = Shark.getInstance().getAdminInterface().getPackageAdministration();
if (!pa.isPackageOpened(pkgId)) {
pa.openPackage(xpdlName);
}
System.out.println("Package "+ xpdlName +" is loaded");
例子
4.
构建和开始流程
当加载
XPDL
到
shark
后,再构建它,填入初始化变量值,启动基于
XPDL
定义的流程。
String pkgId="test";
String pDefId1="basic";
String pDefId2="complex";
SharkConnection sConn=Shark.getInstance().getConnection();
sConn.connect("user","secret","","");
WfProcess proc1=sConn.createProcess(pkgId,pDefId1);
WfProcess proc2=sConn.createProcess(pkgId,pDefId2);
proc1.set_process_context("test_var","This is String variable defined in XPDL for the process basic");
proc2.set_process_context("counter",new Long(55));
proc1.start();
proc2.start();
例子
5.
设置变量
成功连接上
Shark
后,获得指派列表,再作些有用的事,比如设置变量和完成该活动。
/*
SharkConnection sConn;
String activityId;
String vName;
String vValue;
*/
WfAssignment a = null;
WfAssignment[] ar = sConn.getResourceObject().get_sequence_work_item(0);
for (int i = 0; i < ar.length; ++i) {
if (activityId.equals(ar[i].activity().key())) {
a = ar[i];
break;
}
}
if (null == a)
throw new BaseException("Activity:"
+ activityId
+" not found in "
+ sConn.getResourceObject().resource_key()
+"'s worklist");
if (!a.get_accepted_status())
throw new BaseException("I don't own activity "+ activityId);
Map _m = new HashMap();
WfActivity activity = a.activity();
Object c = activity.process_context().get(vName);
if (c instanceof Long) {
c = new Long(vValue);
} else {
c = vValue;
}
_m.put(vName, c);
activity.set_result(_m);
activity.complete();
例子
6.
获得基于标准的流程管理器
该范例展示了怎样获得基于标准的流程管理器。范例试图得到包
Id
为
"test"
并且状态是
enabled
的所有流程管理器。
ExecutionAdministration eAdmin=Shark.getInstance().getAdminInterface().getExecutionAdministration();
eAdmin.connect("user","secret","","");
WfProcessMgrIterator pmi=eAdmin.et_iterator_processmgr();
query="packageId.equals(\"test\") && enabled.booleanValue()";
pmi.set_query_expression(query);
WfProcessMgr[] procs=pmi.get_next_n_sequence(0);
例子
7.
获得基于标准的流程
该范例展示了怎样获得由基于标准的流程管理器构建的流程。范例试图得到所有状态为
"open.running"
,并且是十分种之前启动,有
3
个以上的激活活动,有叫做
"myvariable"
且值为
"test"
的
String
类型变量的流程。
/*
WfProcessMgr mgr;
*/
WfProcessIterator wpi=mgr.get_iterator_process ();
query="state.equals(\"open.running\") && startTime.longValue()>(java.lang.System.currentTimeMillis()-10*60*1000) && activeActivitiesNo.longValue()>3 && context_myvariable.equals(\"test\")";
wpi.set_query_expression(query);
WfProcess[] procs=wpi.get_next_n_sequence(0);
例子
8.
使用外部事务
Shark API
的每个方法这样调用分离事务:引擎内部构建,使用,任意提交,最终释放事务。这意味着每个使用
Shark
的简单代码将不知不觉使用很多事务。
有时,外部事务要做些不同的事情,于是
SharkTransaction
被引入进来了。一个程序(的开发者)会因为多种因素选择使用外部事务,比如使用相同数据库保存程序(
work-flow
无关)数据,这是为避免经常构建
/
丢弃事务,
...
当然,这种方法也会有代价:你必须遵从于使用规则。通过调用
Shark.getInstance().createTransaction();
事务被构建,在你释放一个事务之前,程序必须调用
Shark.getInstance().unlockProcesses(st);
通知
Shark
进行内部记帐。如果有任何错误,你必须捕捉
Throwable
(异常)再调用
Shark.getInstance().emptyCaches(st);
。是的,你甚至应该为捕获错误而准备好,另外你将面对未知状态下脱离引擎。
这是利用单一事务进行变量设置的例子。
/*
SharkConnection sConn;
String activityId;
String vName;
String vValue;
*/
SharkTransaction st = Shark.getInstance().createTransaction();
try {
WfAssignment a = null;
WfAssignment[] ar = sConn
.getResourceObject(st)
.get_sequence_work_item(st, 0);
for (int i = 0; i < ar.length; ++i) {
if (activityId.equals(ar[i].activity(st).key(st))) {
a = ar[i];
break;
}
}
if (null == a)
throw new BaseException("Activity:"
+ activityId
+" not found in "
+ sConn.getResourceObject(st).resource_key(st)
+"'s worklist");
if (!a.get_accepted_status(st))
throw new BaseException("I don't own activity "+ activityId);
Map _m = new HashMap();
WfActivity activity = a.activity(st);
Object c = activity.process_context(st).get(vName);
if (c instanceof Long) {
c = new Long(vValue);
} else {
c = vValue;
}
_m.put(vName, c);
activity.set_result(st, _m);
activity.complete(st);
st.commit();
} catch (Throwable t) {
Shark.getInstance().emptyCaches(st);
st.rollback();
if (t instanceof RootException)
throw (RootException)t;
else
throw new RootException(t);
} finally {
try { Shark.getInstance().unlockProcesses(st);} catch (Exception _){}
st.release();
}
XPDL
流程定义
(通过我们的
XPDL
编辑器
JaWE
会使构建
XPDL
变得简单。)
怎样为活动定义
deadline
表达式?
在
shark deadline
表达式中连同所有流程变量,你能使用特殊变量。这些变量的
Java
类型是
java.util.Date
,以下是描述:
PROCESS_STARTED_TIME -
流程开始的时间
ACTIVITY_ACTIVATED_TIME -
当流程流到活动以及为活动构建指派的时间。
ACTIVITY_ACCEPTED_TIME -
第一次为活动指派的接收时间。
注意
如果活动在接收后被拒绝,或根本没有接收,
ACTIVITY_ACCEPTED_TIME
将会设置成最大值。
在构建
deadline
表达式时有些规则:
Deadline
表达式就是
java.util.Date
如果
shark
设置为没有重评估
deadline
,而只是最初评估
deadline
时间期限,
ACTIVITY_ACCEPTED_TIME
不会被用在表达式中,因为它将在以后包含最大时间值。
那些不是流程变量(来自于
XPDL
的
DataField
或
FormalParameter
实体),和先前列出的其中之一有相同
Id
。
一点
deadline
表达式的例子:
// Deadline limit is set to 15 secunds after accepting activity
var d=new java.util.Date();
d.setTime(ACTIVITY_ACCEPTED_TIME.getTime()+15000);
d;
// Deadline limit is set to 5 minutes after activity is started (activated)
var d=new java.util.Date();
d.setTime(ACTIVITY_ACTIVATED_TIME.getTime()+300000);
d;
// Deadline limit is set to 1 hour after process is started
var d=new java.util.Date();
d.setTime(PROCESS_STARTED_TIME.getTime()+3600000);
d;
怎样在
shark
管理程序中定义外部属性来更新
/
查看活动变量
为了更新
shark
管理程序中的活动变量(由
XPDL
定义),
XPDL
活动定义必须包含预先扩充的属性。
假如
XPDL
流程定义包含叫做
"x"
的变量(
XPDL DataField
标记),和叫做
"input_var"
的变量(
XPDL FormalParameter
类型)。
如果在执行活动时你想让管理用户仅仅查看那些变量,你应该定义如下活动扩展属性:
<ExtendedAttribute Name="VariableToProcess_VIEW" Value="x"/>
<ExtendedAttribute Name="VariableToProcess_VIEW" Value="input_var"/>
如果你想要用户更新同样的变量,你应该定义如下活动扩展属性:
<ExtendedAttribute Name="VariableToProcess_UPDATE" Value="x"/>
<ExtendedAttribute Name="VariableToProcess_UPDATE" Value="input_var"/>
在
Shark
中怎样让
XPDL
使用自定义
Java
类做为变量
要做到这些,你应该定义变量作为
XPDL
的外部引用,并把你想要用的完整
Java
类名做为它的属性。比如,像这样:
...
<DataField Id="participants" IsArray="FALSE">
<DataType>
<ExternalReference location="org.enhydra.shark.wrd.Participants"/>
</DataType>
</DataField>
...
...
<FormalParameter Id="participantGroup" Mode="INOUT">
<DataType>
<ExternalReference location="org.enhydra.shark.wrd.Participants"/>
</DataType>
</FormalParameter>
...
也许更好的途径是定义
TypeDeclaration
元素做为其类型。那样的话你就可以随处用到了(当建立程序的
/
子流程的
FormalParameters
时你不用定义适合的
DataType
):
...
<TypeDeclaration Id="participants_type">
<ExternalReference location="org.enhydra.shark.wrd.Participants"/>
</TypeDeclaration>
...
定义
DataField
或
FormalParameter
:
...
<DataField Id="participants" IsArray="FALSE">
<DataType>
<DeclaredType Id="participants_type"/>
</DataType>
</DataField>
...
<FormalParameter Id="participantGroup" Mode="INOUT">
<DataType>
<DeclaredType Id="participants_type"/>
</DataType>
</FormalParameter>
...
通过
ExternalReference
元素指定的类必须在
shark
类路径中。
怎样在
XPDL
中定义变量为
'null'
的初始值
只需简单将
DataField
的
InitialValue
元素写成
"null"
:
<DataField Id="participants" IsArray="FALSE">
<DataType>
<DeclaredType Id="participants_type"/>
</DataType>
<InitialValue>null</InitialValue>
</DataField>
你可使用接口或抽象
java
类做为工作流变量。这些变量的具体实现可由一些
tool agent
构建。
怎样指定脚本语言
Shark
目前支持三种脚本解释器:
JavaScript
,
BeanShell
和
Python
(最后一个未完全测试)。要告诉
shark
哪种脚本语言被用于书写条件式(比如在事务条件中),你应该指定包的
script
元素:
# if you want to use java-like syntax (interpreted by BeanShell), specify:
<Script Type="text/java"/>
# if you want to use java script syntax, specify:
<Script Type="text/javascript"/>
# if you want to use python syntax, specify:
<Script Type="text/pythonscript"/>
如果你没有指定脚本或指定的值不被
shark
支持,
Shark
将会抱怨。
怎样利用
XPDL
为特定的
ToolAgent
直接映射程序定义(不需要在运行期为程序映射)
如果你想直接在
XPDL
中指定
ToolAgent
,
Tool
活动将执行该
ToolAgent
,所以你应该为
XPDL
程序定义设置一些扩展属性。
主要的扩展属性应该在每个程序定义中定义,趋向于映射给名叫
"ToolAgentClass"
的
ToolAgent
,并且它的值应该是被执行的
tool agent
类全名,例如:
<ExtendedAttribute Name="ToolAgentClass" Value="org.enhydra.shark.toolagent.JavaScriptToolAgent"/>
该属性通过
shark
的
tool agent
定义工具阅读,并且它执行基于该属性值的特定
ToolAgent
。
其他外部属性被指定来实现
tool agent
,并通过它们读取。比如
JavaScript
和
BeanShell tool agent
指定了名为
"Script"
的外部属性,而且内容是通过
tool agent
在运行期执行脚本获得的。这种情况下,你就是在用
XPDL
编程了,例如:
<ExtendedAttribute Name="Script" Value="java.lang.System.out.println("I'm going to perform operation c="+a+"*"+b); c=a*b; java.lang.System.out.println("The result is c="+c);"/>
该脚本运行了变量
"a"
和
"b"
的乘法运算,并把结果保存在
"c"
中(那些变量都是
XPDL
程序定义的形参)。
请注意!引用、转贴本文应注明原译者:Rosen Jiang 以及出处:http://www.blogjava.net/rosen