ATG:更新订单模式

时间:2016-06-01 23:03:58

标签: java java-ee atg oracle-commerce

众所周知,您必须使用以下模式才能更新ATG Form-Handlers中不会从 PurchaseProcessFormHanlder 继承的订单:

boolean acquireLock = false;
ClientLockManager lockManager = getLocalLockManager();

try {
    acquireLock = !lockManager.hasWriteLock(profile.getRepositoryId(), Thread.currentThread());
    if (acquireLock) {
        lockManager.acquireWriteLock(profile.getRepositoryId(), Thread.currentThread());
    }

    boolean shouldRollback = false;

    TransactionDemarcation transactionDemarcation = new TransactionDemarcation();
    TransactionManager transactionManager = getTransactionManager();

    transactionDemarcation.begin(transactionManager, TransactionDemarcation.REQUIRED);

    try {
        synchronized (getOrder()) {
            ...
            ...
            ...
        }
    } catch (final Exception ex) {
        shouldRollback = true;
        vlogError(ce, "There has been an exception during processing of order: {0}", getOrder().getId());
    } finally { 
        try {
            transactionDemarcation.end(shouldRollback);
        } catch (final TransactionDemarcationException tde) {
            vlogError(tde, "TransactionDemarcationException during finally: {0}", tde.getMessage());
        } finally {
            vlogDebug("Ending Transaction for orderId: {0}", order.getId());
        }
    }
} catch (final DeadlockException de) {
    vlogError(de, "There has been an exception during processing of order: {0}", order.getId());
} catch (final TransactionDemarcationException tde) {
    vlogError(tde, "There has been an exception during processing of order: {0}", order.getId());
} finally {
    try {
        if (acquireLock) {
            lockManager.releaseWriteLock(getOrder().getProfileId(), Thread.currentThread(), true);
        }
    } catch (final Throwable th) {
        vlogError(th, "There has been an error during release of write lock: {0}", th.getMessage());
    }
}

理论上,从 PurchaseProcessFormHandler 继承的任何FormHandler已经实现了以下步骤OOTB:

  1. 获取 LocalLockManager 以避免并发线程修改相同的顺序:

    try {
        acquireLock = !lockManager.hasWriteLock(profile.getRepositoryId(), Thread.currentThread());
        if (acquireLock) {
            lockManager.acquireWriteLock(profile.getRepositoryId(), Thread.currentThread());
        }
    } catch (final DeadlockException de) {
        vlogError(de, "There has been an exception during processing of order: {0}", order.getId());
    }
    
  2. 创建新的交易

    try {
        TransactionDemarcation transactionDemarcation = new TransactionDemarcation();
        TransactionManager transactionManager = getTransactionManager();
    
        transactionDemarcation.begin(transactionManager, TransactionDemarcation.REQUIRED);
    } catch (final TransactionDemarcationException tde) {
        vlogError(tde, "There has been an exception during processing of order: {0}", order.getId());
    }
    
  3. 结束使用的交易

    try {
        TransactionManager transactionManager = getTransactionManager();
        Transaction transaction = transactionManager.getTransaction();
    
        // If transaction is elegible for commiting: 
        transactionManager.commit();
        transaction.commit();
    
        // otherwise
        transactionManager.rollback();
        transaction.rollback();
    } catch (final Exception ex) {
        error = true;
        vlogError(ex, "There has been an exception during processing of order: {0}", order.getId());
    } finally {
        // handle the error
    }
    
  4. 释放用于交易的锁

    finally {
        ClientLockManager lockManager = getLocalLockManager();
        lockManager.releaseWriteLock(profile.getRepositoryId(), Thread.currentThread(), true);
    }
    
  5. 根据ATG文档,以下方法实现上述描述的行为:

    1. 方法:beforeSet

        

      在提交修改此表单处理程序属性的表单时,设置此表单上的任何setX方法之前调用。如有必要,在表单提交过程开始时创建事务,可选择获取本地锁定以防止多个表单创建可能修改相同订单的事务。

      • 步骤:1& 2
    2. 方法:afterSet

        

      在提交修改此表单处理程序属性的表单时,设置此表单上的任何setX方法后调用。提交或回滚在beforeSet中创建的任何事务,并释放当时获取的任何锁。

      • 步骤:3& 4
    3. 例如,您只需处理以下程序即可更新订单:

      1. Syncronize 将用于order updating的代码块,以避免线程并发。

        synchronized (getOrder()) {
            ...
            ...
            ...
        }
        
      2. 执行订单修改

        synchronized (getOrder()) {
            getOrder().setXXX();
            getOrder().removeXXX();
        }
        
      3. 更新订单(将调用updateOrder管道链):

        synchronized (getOrder()) {
            ...
            ...
            ...
            getOrderManager().updateOrder(order);
        }
        
      4. 这非常简单,除非您必须在以下任何情况下编辑订单:

        • 不在PurchaseProcessFormHandler层次结构中的表单处理程序或自定义表单处理程序。
        • 助手或工具类。
        • 处理器
        • ATG REST Web服务
        • 和C

        如果是这样,您必须在组件中实施交易模式

        的问题!

        • 是否已知使用其他模式而不是使用事务模式?
        • 是否可以实施/覆盖beforeSet& FormHandlers中的afterSet方法与ATG在PurchaseProcessFormHandler
        • 中的方法完全相同
        • 您是否了解其他任何方法?

1 个答案:

答案 0 :(得分:0)

您在上面列出的一系列步骤是更新订单的规定系列步骤。

随意以任何有用的方式将其分解出来。只需确保在更新订单时,您或您继承的代码已执行必要的步骤。

ATG执行类似因子分析的一种常见方法是针对给定方法,例如X(...),您将拥有preX(...)doX(...)postX(...)方法。您可以使用preX()postX()方法中的所有样板代码创建一个抽象类,甚至可以声明为final,并将doX()声明为abstract。然后,您的组件将从抽象类继承,并且必须实现doX()方法。您可能还需要明确处理异常。

这基本上就是标准表单处理程序的作用(以不同的名称)。

例如;

public final void X(...) {
  preX(...); // call the pre method

  try {
    doX(...); // call the do method
  } catch (XException xe) {
    // handle error
  }

  postX(...); // call the post method
}

protected final void preX(...) {
  // do everything you need to do before your customer code
}

protected final void postX(...) {
  // do everything you need to do after your customer code
}

protected abstract void doX(...) throws XException;

您可以做的另一件事是定义一个包含所有样板代码的注释,而不是从抽象类继承。

你能做的第三件事,就是以类似的方式,但更难以在你的ATG代码中窃取,可能是使用第三方框架定义方面或方法调用拦截器。

然而,无论你做什么,无论你做什么,只要确保你遵循所有步骤。