Small example showing how "atg.commerce.order.InvalidVersionException" is thrown when coding is done improperly.
In below example: one of the order property is udpated and updateOrder is called. In below case InvalidVersionException is thrown.
Note: Please go through http://atgkid.blogspot.com/2011/11/regarding-concurrentupdateexception-and.html
to know more about InvalidVersionException and ConcurrentUpdateException.
In logs -
atg.commerce.order.InvalidVersionException: This order (2368070835) is out of date. Changes have been made to the order and the operation should be resubmitted.
Order version 15, Repository item version 16.
at atg.commerce.order.OrderManager.updateOrder(OrderManager.java:2670)
at com.TestOrderDroplet.service(TestOrderDroplet.java:26)
at atg.servlet.DynamoServlet.service(DynamoServlet.java:123)
at atg.taglib.dspjsp.DropletTag.invokeServlet(DropletTag.java:349)
at atg.taglib.dspjsp.DropletTag.doAfterBody(DropletTag.java:616)
at org.apache.jsp.test_jsp._jspx_meth_dsp_005fdroplet_005f0(test_jsp.java:138)
at org.apache.jsp.test_jsp._jspx_meth_dsp_005fpage_005f0(test_jsp.java:98)
at org.apache.jsp.test_jsp._jspService(test_jsp.java:67)
Why above exception is thrown?
During "order.setStoreNumber(59151)" value is updated in order table, updateItem is called and order item version is updated (but Order (session) object does'nt know about version change)
During "updateOrder" - ATG OOTB will compare Order (session) object version with order item version, since both are not equal - InvalidVersionException is thrown.
How can we avoid such type of exception?
By having a transaction while update order. Go through below example.
**** debug Thu Feb 14 11:17:38 CST 2013 1360862258581 /com/TestOrderDroplet Before set - order version : 28
**** debug Thu Feb 14 11:17:39 CST 2013 1360862259957 /com/TestOrderDroplet Before set - order item version: 28
**** debug Thu Feb 14 11:17:42 CST 2013 1360862262224 /com/TestOrderDroplet After set - order version : 28
**** debug Thu Feb 14 11:17:43 CST 2013 1360862263115 /com/TestOrderDroplet After set order item version: 28
**** debug Thu Feb 14 11:17:44 CST 2013 1360862264475 /com/TestOrderDroplet After updateOrder - order version : 30
**** debug Thu Feb 14 11:17:45 CST 2013 1360862265225 /com/TestOrderDroplet After updateOrder order item version: 30
Why above code will work without "InvalidVersionException" exception?
During "order.setStoreNumber(59151)" since transaction is in place, value is NOT updated yet in database or in item cache, so item version is NOT updated.
During "updateOrder" - ATG OOTB will compare Order (session) object version with order item version, in this case both are equal (since both are not updated yet).
ATG OOTB pipeline "updateOrder" is executed and ProcSaveOrderObject will call updateItem on orderItem, which will update the item version.
once whole pipeline is executed at the end of the updateOrder method - order (session) object is updated with order Item version.So once updateOrder is finished both order (session) object version and order item version will be in sync.
Hope this helps!!
In below example: one of the order property is udpated and updateOrder is called. In below case InvalidVersionException is thrown.
Note: Please go through http://atgkid.blogspot.com/2011/11/regarding-concurrentupdateexception-and.html
to know more about InvalidVersionException and ConcurrentUpdateException.
public class TestOrderDroplet extends DynamoServlet {
@Override
public void service(DynamoHttpServletRequest req,
DynamoHttpServletResponse res) throws ServletException, IOException {
OrderHolder ordholder = (OrderHolder) req.resolveName("/atg/commerce/ShoppingCart");
OrderManager ordMgr = (OrderManager) req.resolveName("/atg/commerce/order/OrderManager");
WalgreensOrderImpl order = (WalgreensOrderImpl) ordholder.getCurrent();
// a custom persistent property called storeNumber at order level
order.setStoreNumber(59151);
try {
ordMgr.updateOrder(order);
} catch (CommerceException e) {
e.printStackTrace();
}
}
}
In jsp - test.jsp - Just calling above droplet@Override
public void service(DynamoHttpServletRequest req,
DynamoHttpServletResponse res) throws ServletException, IOException {
OrderHolder ordholder = (OrderHolder) req.resolveName("/atg/commerce/ShoppingCart");
OrderManager ordMgr = (OrderManager) req.resolveName("/atg/commerce/order/OrderManager");
WalgreensOrderImpl order = (WalgreensOrderImpl) ordholder.getCurrent();
// a custom persistent property called storeNumber at order level
order.setStoreNumber(59151);
try {
ordMgr.updateOrder(order);
} catch (CommerceException e) {
e.printStackTrace();
}
}
}
<%@ taglib uri="dsp" prefix="dsp"%>
<dsp:page>
<dsp:droplet name="/com/TestOrderDroplet">
</dsp:droplet>
</dsp:page>
When above page is accessed<dsp:page>
<dsp:droplet name="/com/TestOrderDroplet">
</dsp:droplet>
</dsp:page>
In logs -
atg.commerce.order.InvalidVersionException: This order (2368070835) is out of date. Changes have been made to the order and the operation should be resubmitted.
Order version 15, Repository item version 16.
at atg.commerce.order.OrderManager.updateOrder(OrderManager.java:2670)
at com.TestOrderDroplet.service(TestOrderDroplet.java:26)
at atg.servlet.DynamoServlet.service(DynamoServlet.java:123)
at atg.taglib.dspjsp.DropletTag.invokeServlet(DropletTag.java:349)
at atg.taglib.dspjsp.DropletTag.doAfterBody(DropletTag.java:616)
at org.apache.jsp.test_jsp._jspx_meth_dsp_005fdroplet_005f0(test_jsp.java:138)
at org.apache.jsp.test_jsp._jspx_meth_dsp_005fpage_005f0(test_jsp.java:98)
at org.apache.jsp.test_jsp._jspService(test_jsp.java:67)
Why above exception is thrown?
During "order.setStoreNumber(59151)" value is updated in order table, updateItem is called and order item version is updated (but Order (session) object does'nt know about version change)
During "updateOrder" - ATG OOTB will compare Order (session) object version with order item version, since both are not equal - InvalidVersionException is thrown.
How can we avoid such type of exception?
By having a transaction while update order. Go through below example.
public class TestOrderDroplet extends DynamoServlet {
@Override
public void service(DynamoHttpServletRequest req,
DynamoHttpServletResponse res) throws ServletException, IOException {
OrderHolder ordholder = (OrderHolder) req.resolveName("/atg/commerce/ShoppingCart");
OrderManager ordMgr = (OrderManager) req.resolveName("/atg/commerce/order/OrderManager");
MutableRepository repo = (MutableRepository) req.resolveName("/atg/commerce/order/OrderRepository");
TransactionManager tManger = (TransactionManager) req.resolveName("/atg/dynamo/transaction/TransactionManager");
WalgreensOrderImpl order = (WalgreensOrderImpl) ordholder.getCurrent();
// added for transaction
TransactionDemarcation td =new TransactionDemarcation();
boolean rollback = false;
try {
// transaction beginning
td.begin(tManger,TransactionDemarcation.REQUIRES_NEW);
RepositoryItem orderItem = repo.getItemForUpdate(order.getId(), "order");
logDebug("Before set - order version : "+order.getVersion());
logDebug("Before set - order item version: "+orderItem.getPropertyValue("version"));
order.setStoreNumber(59151);
// Note: if you call updateItem on order item, order item version will be increased
// but order (session) object is not, so if you call udpateItem here
// during update order, InvalidVersionException is thrown even with transaction in place.
// repo.updateItem((MutableRepositoryItem)orderItem);
logDebug("After set - order version : "+order.getVersion());
logDebug("After set order item version: "+orderItem.getPropertyValue("version"));
ordMgr.updateOrder(order);
logDebug("After updateOrder - order version : "+order.getVersion());
logDebug("After updateOrder order item version: "+orderItem.getPropertyValue("version"));
} catch (Exception e) {
e.printStackTrace();
rollback = true;
}
try {
// transaction end
td.end(rollback);
} catch (TransactionDemarcationException e) {
e.printStackTrace();
}
}
}
In logs - @Override
public void service(DynamoHttpServletRequest req,
DynamoHttpServletResponse res) throws ServletException, IOException {
OrderHolder ordholder = (OrderHolder) req.resolveName("/atg/commerce/ShoppingCart");
OrderManager ordMgr = (OrderManager) req.resolveName("/atg/commerce/order/OrderManager");
MutableRepository repo = (MutableRepository) req.resolveName("/atg/commerce/order/OrderRepository");
TransactionManager tManger = (TransactionManager) req.resolveName("/atg/dynamo/transaction/TransactionManager");
WalgreensOrderImpl order = (WalgreensOrderImpl) ordholder.getCurrent();
// added for transaction
TransactionDemarcation td =new TransactionDemarcation();
boolean rollback = false;
try {
// transaction beginning
td.begin(tManger,TransactionDemarcation.REQUIRES_NEW);
RepositoryItem orderItem = repo.getItemForUpdate(order.getId(), "order");
logDebug("Before set - order version : "+order.getVersion());
logDebug("Before set - order item version: "+orderItem.getPropertyValue("version"));
order.setStoreNumber(59151);
// Note: if you call updateItem on order item, order item version will be increased
// but order (session) object is not, so if you call udpateItem here
// during update order, InvalidVersionException is thrown even with transaction in place.
// repo.updateItem((MutableRepositoryItem)orderItem);
logDebug("After set - order version : "+order.getVersion());
logDebug("After set order item version: "+orderItem.getPropertyValue("version"));
ordMgr.updateOrder(order);
logDebug("After updateOrder - order version : "+order.getVersion());
logDebug("After updateOrder order item version: "+orderItem.getPropertyValue("version"));
} catch (Exception e) {
e.printStackTrace();
rollback = true;
}
try {
// transaction end
td.end(rollback);
} catch (TransactionDemarcationException e) {
e.printStackTrace();
}
}
}
**** debug Thu Feb 14 11:17:38 CST 2013 1360862258581 /com/TestOrderDroplet Before set - order version : 28
**** debug Thu Feb 14 11:17:39 CST 2013 1360862259957 /com/TestOrderDroplet Before set - order item version: 28
**** debug Thu Feb 14 11:17:42 CST 2013 1360862262224 /com/TestOrderDroplet After set - order version : 28
**** debug Thu Feb 14 11:17:43 CST 2013 1360862263115 /com/TestOrderDroplet After set order item version: 28
**** debug Thu Feb 14 11:17:44 CST 2013 1360862264475 /com/TestOrderDroplet After updateOrder - order version : 30
**** debug Thu Feb 14 11:17:45 CST 2013 1360862265225 /com/TestOrderDroplet After updateOrder order item version: 30
Why above code will work without "InvalidVersionException" exception?
During "order.setStoreNumber(59151)" since transaction is in place, value is NOT updated yet in database or in item cache, so item version is NOT updated.
During "updateOrder" - ATG OOTB will compare Order (session) object version with order item version, in this case both are equal (since both are not updated yet).
ATG OOTB pipeline "updateOrder" is executed and ProcSaveOrderObject will call updateItem on orderItem, which will update the item version.
once whole pipeline is executed at the end of the updateOrder method - order (session) object is updated with order Item version.So once updateOrder is finished both order (session) object version and order item version will be in sync.
Hope this helps!!
Nice blog. Also check out ATG blogs at http://ourownjava.com/atg
ReplyDeleteNIce
ReplyDelete