java - ATG: Update Order Pattern -
it has been known must use following pattern in order update order in atg form-handlers
doesn't inherit 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 exception during processing of order: {0}", getorder().getid()); } { try { transactiondemarcation.end(shouldrollback); } catch (final transactiondemarcationexception tde) { vlogerror(tde, "transactiondemarcationexception during finally: {0}", tde.getmessage()); } { vlogdebug("ending transaction orderid: {0}", order.getid()); } } } catch (final deadlockexception de) { vlogerror(de, "there has been exception during processing of order: {0}", order.getid()); } catch (final transactiondemarcationexception tde) { vlogerror(tde, "there has been exception during processing of order: {0}", order.getid()); } { try { if (acquirelock) { lockmanager.releasewritelock(getorder().getprofileid(), thread.currentthread(), true); } } catch (final throwable th) { vlogerror(th, "there has been error during release of write lock: {0}", th.getmessage()); } }
in theory, formhandler
inherits purchaseprocessformhandler implements following steps ootb:
acquire locallockmanager in order avoid concurrent threads modify same order:
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 exception during processing of order: {0}", order.getid()); }
create new transaction:
try { transactiondemarcation transactiondemarcation = new transactiondemarcation(); transactionmanager transactionmanager = gettransactionmanager(); transactiondemarcation.begin(transactionmanager, transactiondemarcation.required); } catch (final transactiondemarcationexception tde) { vlogerror(tde, "there has been exception during processing of order: {0}", order.getid()); }
ending transaction being used:
try { transactionmanager transactionmanager = gettransactionmanager(); transaction transaction = transactionmanager.gettransaction(); // if transaction elegible commiting: transactionmanager.commit(); transaction.commit(); // otherwise transactionmanager.rollback(); transaction.rollback(); } catch (final exception ex) { error = true; vlogerror(ex, "there has been exception during processing of order: {0}", order.getid()); } { // handle error }
release lock being used transaction:
finally { clientlockmanager lockmanager = getlocallockmanager(); lockmanager.releasewritelock(profile.getrepositoryid(), thread.currentthread(), true); }
as per atg documentation, following methods implement behaviour descripted above:
method: beforeset
called before setx methods on form set when form modifies properties of form handler submitted. creates transaction if necessary @ beginning of form submission process, optionally obtaining local lock prevent multiple forms creating transactions may modify same order.
- steps: 1 & 2
method: afterset
called after setx methods on form set when form modifies properties of form handler submitted. commits or rolls transaction created in beforeset, , releases lock acquired @ time.
- steps: 3 & 4
such have handle following procedures in order update order:
syncronize block of code that's going used
order updating
in order avoid thread concurrency.synchronized (getorder()) { ... ... ... }
perform order modifications:
synchronized (getorder()) { getorder().setxxx(); getorder().removexxx(); }
update order (
updateorder
pipeline chain invoked):synchronized (getorder()) { ... ... ... getordermanager().updateorder(order); }
this pretty straightforward, unless have edit order in of following scenarios:
- form handlers or custom form handler not in
purchaseprocessformhandler
's hierachy. - helpers or tools classes.
- processors
- atg rest web services
- &c
if so, have implement transactional pattern within components.
questions!
- is there other pattern known use instead of using transactional pattern?
- would possible implement/override
beforeset
&afterset
methods in formhandlers same way atg inpurchaseprocessformhandler
- are aware of other approach?
the series of steps have outlined above prescribed series of steps updating order.
feel free factor out in way find useful. ensure when update order, you, or inherited code, have performed requisite steps.
one common way atg similar factoring given method, x(...)
, have prex(...)
, dox(...)
, , postx(...)
method. can create abstract class boilerplate code in prex()
, postx()
methods, maybe declared final, , have dox()
declared abstract. component inherit abstract class , must implement dox()
method. may need handle exceptions explicitly well.
this is, essentially, standard form handlers (under different names).
for example;
public final void x(...) { prex(...); // call pre method try { dox(...); // call method } catch (xexception xe) { // handle error } postx(...); // call post method } protected final void prex(...) { // need before customer code } protected final void postx(...) { // need after customer code } protected abstract void dox(...) throws xexception;
another thing do, instead of inheriting abstract class, define annotation has boilerplate code.
a third thing do, in similar way, lot harder shoehorn atg code, might define aspect or method invocation interceptor using third party frameworks.
however, once again, whatever do, , it, ensure follow steps.