根据之前的源码分析,我打算先扩展Decider的cohesion模式。
原本Decider类的实现方式:对于Atomic模式,由于ConfirmTransaction消息没有传递Inferiors-list参数,所以可以直接调用jotm中ControlImpl类的commit(boolean)方法来执行事务的提交或是回滚操作(感慨,分析ControlImpl类的实现方式真是一种享受~);对于Cohesion模式,由于标准的jotm项目是不支持这个概念的(应该是BTP独有的模式吧),所以Decider中是写了一个简单的prepare-confirm过程,只有当所有的prepare都返回prepared消息时,再进行confirm操作,如果异常直接返回fault,而没有任何rollback操作。
出于对ControlImpl的实现方式的崇拜,我打算在Decider的Cohesion模式下也使用ControlImpl的commit(boolean)方法。但在ControlImpl的源码分析后发现,Decider类无法将获得的Inferior-list参数传人ControlImpl对象中,而commit(boolean)方法中操作的inferiors list是一个事务中所有的Inferiors,是在Enrolling过程中就加入该对象的相应List对象中的。也就是说ControlImpl无法对指定Resource(jotm中的概念)进行提交操作,要提交只能是一个事务中的全部Resources一起提交。
于是想到写一个子类扩展ControlImpl类。但是这样行不通,ControlImpl类中不少方法是private的,子类中看不到,无法执行相应操作~无奈只能直接改ControlImpl类了,好在jotm项目也是开源的,我也不是做什么公开发表的项目,管他开源协议呢……我添加一个commit(List, boolean)方法,方法体几乎复制原来的实现方式,这样就可以接收指定的Resources了。当然还要对内部调用的其它方法也添加一个有List参数的方法。下面举例do_prepare方法:
private synchronized int do_prepare(List confirmSet, boolean report_heuristics) { if (TraceTm.jotm.isDebugEnabled()) { TraceTm.jotm.debug("report_heuristics="+ report_heuristics); } int errors = 0; int ret = Resource.VOTE_READONLY; List resources=resourceList; if(confirmSet!=null) resources=confirmSet; // Synchronization objects errors = do_before_completion(); if (errors > 0) { if (TraceTm.jotm.isDebugEnabled()) { TraceTm.jotm.debug("before_completion failed -> rollback"); } return Resource.VOTE_ROLLBACK; } // No resource -> just forget transaction. if (resources.size() == 0) { TraceTm.jotm.error("commit: no resource"); mystatus = Status.STATUS_COMMITTED; do_after_completion(); completed(true); return ret; } // Creates a log for that transaction, where we will add all the // resources that replied VOTE_COMMIT to prepare. // Do not flush the log on disk before decision to commit. mylog = new Log(); // Sends prepare to each resource. // In case of prepare on sub-coord. we may have only 1 resource. // In case of phase 1 of the 2PC, we have several resources, because // the case of 1 resource is treated with commit_one_phase (optimization) mystatus = Status.STATUS_PREPARING; for (int i = 0; i < resources.size(); i++) { Resource res = (Resource) resources.get(i); if (errors > 0) { if (TraceTm.jotm.isWarnEnabled()) { TraceTm.jotm.warn("Vote stopped: at least one resource has voted rollback."); } break; } else { // No error yet: Send prepare to the resource. try { if (TraceTm.jotm.isDebugEnabled()) { TraceTm.jotm.debug("send prepare to resource"); } switch (res.prepare()) { case Resource.VOTE_COMMIT : // Log resource mylog.addResource(res); TraceTm.jotm.info("Resource replied commit to prepare"); ret = Resource.VOTE_COMMIT; break; case Resource.VOTE_ROLLBACK : TraceTm.jotm.info("Resource replied rollback to prepare"); ret = Resource.VOTE_ROLLBACK; errors++; break; case Resource.VOTE_READONLY : if (TraceTm.jotm.isDebugEnabled()) { TraceTm.jotm.debug("Resource replied readonly to prepare"); } break; } } catch (HeuristicHazard e) { // Subcoordinator only TraceTm.jotm.error("HeuristicHazard on prepare"); ret = Resource.VOTE_ROLLBACK; errors++; } catch (HeuristicMixed e) { // Subcoordinator only TraceTm.jotm.error("HeuristicMixed on prepare"); ret = Resource.VOTE_ROLLBACK; errors++; } catch (Exception e) { TraceTm.jotm.error("exception on prepare: ", e); ret = Resource.VOTE_ROLLBACK; errors++; } } } if (ret == Resource.VOTE_READONLY) { if (TraceTm.jotm.isDebugEnabled()) { TraceTm.jotm.debug("All resources returned Readonly"); } mystatus = Status.STATUS_COMMITTED; // Synchronization objects do_after_completion(); } if (ret == Resource.VOTE_COMMIT) { mystatus = Status.STATUS_PREPARED; } if (TraceTm.jotm.isDebugEnabled()) { if (TraceTm.jotm.isDebugEnabled()) { TraceTm.jotm.debug("Vote = " + ret); } } return ret; }
这样一来,基本就解决了Decider类对Cohesion模式的支持问题。如果要使用Atomic模式,可以使用原来的commit方法或是添加的commit方法,但List参数传null即可;对于Cohesion模式,调用新添加的方法,传入相应的Resources即可。
但事情还没有结束,简单的改动了两个类后,并没有按我想象的运行。当Decider调用ControlImpl添加的方法时,Axis总是报错:java.lang.reflect.InvocationTargetException;调用原来的方法则没有问题。
开始以为是方法体改动的问题,可回来测试证明问题不在这。网上说是发布后的程序没
有找到需要的类库。可我改过jar包中的相应类了呀……折腾了一天后发现,原来axis的lib目
录下还有一个jar包(jotm-client.jar)里也有ControlImpl类!肯定是持续调用了它里面的
类了。果然删了这个包就好了……