« - »

The Approval Service: Posting the Decision

22 February 2008

Whenever an action is taken on a Request for Approval (RFA), that action needs to be communicated back to the originating system. After all, the whole point of the service is to get the appropriate party to pass judgment on the items passed to the service, so once that decision has been reached, it needs to be passed back to the originating host. We will accomplish this with an HTTP POST to the URI of the item to be approved, which we can do in Java with a little help from Apache‘s HTTP Client:

HttpClient was started in 2001 as a subproject of the Jakarta Commons, based on code developed by the Jakarta Slide project. It was promoted out of the Commons in 2004, graduating to a separate Jakarta project. In 2005, the HttpComponents project at Jakarta was created, with the task of developing a successor to HttpClient 3.x and to maintain the existing codebase until the new one is ready to take over. The Commons project, cradle of HttpClient, left Jakarta in 2007 to become an independent Top Level Project. Later in the same year, the HttpComponents project also left Jakarta to become an independent Top Level Project, taking the responsibility for maintaining HttpClient with it.

Posting to another service is somewhat of a self-contained, stand-alone operation, so I set this code aside in a utility module that I called the RestServiceManager:

package org.restafarian.approval.data;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.PostMethod;

/**
 * <p>Manages connections to remote services.</p>
 */
public class RestServiceManager {

  /**
   * <p>Posts to the specified REST Web Service.</p>
   * 
   * @param url the address of the service
   * @param parameters the mapped parameters to be posted
   * @return a Map containing two elements: 1) the HTTP 
   * Response Code and 2) the response body
   */
  public static Map post(String url, Map parameters,
         HttpServletRequest req) {
    Map returnData = new HashMap();

    returnData.put("statusCode", new Integer(0));
    HttpClient client = new HttpClient();
    PostMethod post = new PostMethod(url);
    Cookie[] cookies = req.getCookies();
    if (cookies != null && cookies.length > 0) {
      post.getParams().setCookiePolicy(CookiePolicy.RFC_2109);
      for (int x=0; x<cookies.length; x++) {
        if (!"JSESSIONID".equalsIgnoreCase(cookies[x].getName())) {
              post.setRequestHeader("Cookie", cookies[x].getName() +
                   "=" + cookies[x].getValue());
        }
      }
    }
    int size = 0;
    if (parameters != null) {
      size = parameters.size();
    }
    NameValuePair[] dataToPost = new NameValuePair[size];
    if (size > 0) {
      int index = 0;
      Iterator i = parameters.keySet().iterator();
      while (i.hasNext()) {
        String name = (String) i.next();
        dataToPost[index] = new NameValuePair(name, 
             (String) parameters.get(name));
        index++;
      }
    }
    post.setRequestBody(dataToPost);
    try {
      int statusCode = client.executeMethod(post);
      returnData.put("statusCode", new Integer(statusCode));
      returnData.put("responseBody", post.getResponseBodyAsString());
    } catch (Exception e) {
      returnData.put("exception", e);
      e.printStackTrace();
    }

    return returnData;
  }
}

To invoke this process from the RequestForApprovalServlet to notify the originating system, I modified the updateRequestForApproval() method to include the following changes and additions:

// notify host system
Map parameters = new HashMap();
parameters.put("action", req.getParameter("action"));
parameters.put("notes", notes);
Map response = RestServiceManager.post(rfa.getPayloadURI(),
      parameters, req);
int statusCode = ((Integer) response.get("statusCode")).intValue();
if (statusCode == 200) {
  sendRequestForApproval(id, req, res);
} else {
  // log error, if enabled
  if (log.isErrorEnabled()) {
    log.error("Error posting to URI: " + rfa.getPayloadURI() +
         "; Status code: " + statusCode, (Exception)
         response.get("exception"));
  }
  // send error
  sendError(req, res, 500, "There was a technical error while
       attempting to update this resource. Details of this error
       have been logged on the server.");
}

That just about wraps up the end-to-end process for the entire service. I still need to go back and do whatever I need to do to resolve my Betwixt mapping problem with the HTTP PUT process, and I’d also like to do a little something with the Date format (maybe ISO8601), and there’s always additional reports and other queries, but I’m not sure that there’s much else to do here. Of course, I still need to mock up some kind of example originating system so that we can test the thing fully from end-to-end, but other than that, I think this one is just about done.


http://blog.restafarian.org/2008/02/the-approval-service-posting-the-decision/

Comments are closed.

Sorry, the comment form is closed at this time.