Thursday 23 August 2012

Transactional Pattern to be followed in form handlers

Below is an article that I found very useful for understanding the transactional pattern that need to be followed in form handlers. Thanks to Oracle Knowledge Base :)


Code that modifies ATG Commerce Object must follow a specific transactional pattern to avoid exceptions and dead locks. The transactional pattern is implemented by the form handlers that work with order objects.Same transactional pattern can be followed in other form handlers as well

ATG Commerce form handlers that modify Order objects typically extends atg.commerce.order.purchase.PurchaseProcessFormHandler class. This subclass of atg.droplet.GenericFormHander is an abstract class that implements transaction management through its beforeSet, afterSet, and handler methods.

beforeSet - Called once before any form handler property is set or the handle method is called. It implements the following transactional steps:


If the formhandler's useLocksAroundTransactions property is true (default), obtain a transaction lock before the transaction is created.
This prevents a user from modifying an order in multiple concurrent threads. The lock name used defaults to the current profile ID. For more information, see the API documentation for atg.commerce.util.TransactionLockFactory. (Note that use of locking has a small performance impact.)
Check for an existing transaction and, if no transaction exists, create one.

 public boolean beforeSet(DynamoHttpServletRequest pRequest,
DynamoHttpServletResponse pResponse) throws DropletFormException
{
  try {
    acquireTransactionLock(pRequest);
  }
  catch (DeadlockException de) {

    // We are going to log the exception here and then ignore it because
    // the worst that should happen is that the user will get a concurrent
    // update exception if two threads try to modify the same order, and we
    // can recover from that.

    if (isLoggingError())
      logError(de);
  }

  Transaction t = ensureTransaction();
  if (t != null)
    setTransactionCreated(pRequest, pResponse);

  if (isLoggingDebug()) {
    if (t != null)
      logDebug("beforeSet created transaction " + t);
    else
      logDebug("beforeSet did not create a transaction.");
  }

  return super.beforeSet(pRequest,pResponse);
}


The handler methods implement the following transactional steps:

   a) Synchronize on the Order object.
    b) Execute logic for modifying the Order object.  For example, the CartModifierFormHandler subclass   has a handleAddItemToOrder method that executes the logic of adding an item to an order.
  c)  Call the OrderManager object’s updateOrder method to save the order data to the repository.
  d) End the synchronization.

The following example shows the handleAddItemToOrder method of the CartModifierFormHandler:



public boolean handleAddItemToOrder (DynamoHttpServletRequest pRequest,
DynamoHttpServletResponse pResponse)
  throws ServletException, IOException
{
  RepeatingRequestMonitor rrm = getRepeatingRequestMonitor();
  String myHandleMethod = "CartModifierOrderFormHandler.handleAddItemToOrder";
  if ((rrm == null) || (rrm.isUniqueRequestEntry(myHandleMethod)))
  {
    Transaction tr = null;
    try {
      tr = ensureTransaction();
      if (getUserLocale() == null) setUserLocale(getUserLocale(pRequest, pResponse));

      //If any form errors found, redirect to error URL:
      if (! checkFormRedirect(null, getAddItemToOrderErrorURL(), pRequest, pResponse))
        return false;

      synchronized(getOrder()) {
        preAddItemToOrder(pRequest, pResponse);

        //If any form errors found, redirect to error URL:
        if (! checkFormRedirect(null, getAddItemToOrderErrorURL(), pRequest, pResponse))
          return false;

        addItemToOrder(pRequest, pResponse);

        //If any form errors found, redirect to error URL:
        if (! checkFormRedirect(null, getAddItemToOrderErrorURL(), pRequest, pResponse))
          return false;

        postAddItemToOrder(pRequest, pResponse);

        updateOrder(getOrder(), MSG_ERROR_UPDATE_ORDER, pRequest, pResponse);
      } // synchronized

      //If NO form errors are found, redirect to the success URL.
      //If form errors are found, redirect to the error URL.
      return checkFormRedirect (getAddItemToOrderSuccessURL(), getAddItemToOrderErrorURL(), pRequest, pResponse);
    }
    finally {
      if (tr != null) commitTransaction(tr);
      if (rrm != null)
        rrm.removeRequestEntry(myHandleMethod);
    }
  }
  else {
    return false;
  }
}

afterSet Method

This method is called once after all form handler processing is completed. It implements the following transactional steps:

    Commit or roll back any transaction that was created in the beforeSet method.  If the transaction was already in place before the beforeSet method was called, the afterSet method does not end the transaction automatically; this is the application’s responsibility.  If a transaction lock was acquired in the beforeSet method, release the lock.
    The following example shows the afterSet method of the PurchaseProcessFormHandler:

public boolean afterSet(DynamoHttpServletRequest pRequest,
DynamoHttpServletResponse pResponse) throws DropletFormException
{
  try
  {
    Transaction t = getCurrentTransaction();

    if (isLoggingDebug()) {
      if (t != null)
        logDebug("afterSet sees currentTransaction as " + t);
      else
        logDebug("afterSet sees no current transaction.");
    }

    // Try to keep the response to this page from being cached.
    ServletUtil.setNoCacheHeaders(pResponse);

    if (t != null && isTransactionCreated(pRequest, pResponse)) {
      if (isLoggingDebug())
        logDebug("afterSet committing transaction " + t);
      commitTransaction(t);
      unsetTransactionCreated(pRequest, pResponse);
    }
  }

Sunday 12 August 2012

Java client for invoking a RESTful service

Below is a sample REST Java client written using Apache Commons HttpClient. Though the same can be achieved using java.net classes HttpClient is preferred as it provides higher and more functional  level of abstraction.



import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StringWriter;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.methods.GetMethod;

import atg.core.util.StringUtils;
import atg.nucleus.GenericService;

/**
 * @author kshabarinath
 * This is a sample REST client which is used to access a service exposed using URL pattern
 *
 */


public static void main(String[] args) {
String requestURL = "http://www.thomas-bayer.com/sqlrest/CUSTOMER/999";
HttpClient client = new HttpClient();
GetMethod method = new GetMethod(requestURL);
String line;
InputStream rstream;
try {
int statusCode = client.executeMethod(method);
String response = getResponseBody(method);
System.out.println("RESPONSE::"+response);
} catch(HttpException e){
e.printStackTrace();

}catch (IOException e) {

// TODO Auto-generated catch block
e.printStackTrace();
}finally{
method.releaseConnection();
}
}



private static String getResponseBody(GetMethod method){
if(method!=null && method.hasBeenUsed()){
BufferedReader in = null;
StringWriter stringOut = new StringWriter();
BufferedWriter dumpOut = new BufferedWriter(stringOut,8192);
try{
in=new BufferedReader(new InputStreamReader(method.getResponseBodyAsStream()));
String line = "";
while((line=in.readLine())!=null){
dumpOut.write(line);
dumpOut.newLine();
}
}catch(IOException e){
e.printStackTrace();
}finally{
try{
dumpOut.flush();
dumpOut.close();
if(in!=null){
in.close();
}
}catch(IOException e){
e.printStackTrace();
}
}
return stringOut.toString();
}
return null;
}

OUTPUT of the Program


RESPONSE::<?xml version="1.0"?><CUSTOMER xmlns:xlink="http://www.w3.org/1999/xlink">
    <ID>999</ID>
    <FIRSTNAME>Sylvia</FIRSTNAME>
    <LASTNAME>Ott</LASTNAME>
    <STREET>361 College Av.</STREET>
    <CITY>Viena</CITY>
</CUSTOMER>