(STITP)jotm-btp的改进(一)

      根据之前的源码分析,我打算先扩展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类!肯定是持续调用了它里面的

类了。果然删了这个包就好了……

你可能感兴趣的:(webservice,transaction,btp)