AIAIO: Our Blog

AIAIO: Our Blog

The pulse of Alexander Interactive

Archive for April, 2011

A Simple Java REST Client with Apache Commons HttpClient

I recently needed to build a RESTful web service client for my Java application. I wanted something simple and I had a particular set of requirements I wanted to code around (like being able to return the original request parameters along with the response) so the leaner the the actual client the better. After a little research I decided to go with a solution built on Apache Commons HttpClient which provides a rich set of abstractions for client side http interactions. I like HttpClient because it provides a higher and more functional level of abstraction than underlying java.net classes but at the same time allows you to code around whatever Http idioms you want (simple request/response, conversational services, data submission etc.) without alot of bridge code like annotations or library specific interface implementations.

Since I needed to both asynchronously POST data to a restful endpoint as well as perform GET request against another endpoint,  I abstracted all of the parameter bundling and message sending into a single processRequest() method instead of implementing separate post/get code. I also standardized the return type to a Map containing the objects I needed for my app e.g. the request parameters, the actual response and the HTTP response code (REQUEST_PARAMS, RESPONSE_BODY and RESPONSE_STATUS respectively):

processRequest():

public Map<String, Object> processRequest(String serviceUrl,
                        String sendMethod, Map<String, String> params)
{
                if (StringUtils.isBlank(serviceUrl)) {
                    throw new AiServiceException("Service URL is required");
                }
                // Essentially return a new HttpClient(), but can be pulled from Spring context
                HttpClient httpclient = getHttpClient();
                HttpMethod method = getHttpMethodFromString(sendMethod);//See Details Below
                method.setPath(serviceUrl);
                httpclient.getParams().setParameter("http.protocol.version",HttpVersion.HTTP_1_1);
                httpclient.getParams().setParameter("http.socket.timeout", Integer.valueOf(responseTimeOut));
                httpclient.getParams().setParameter("http.protocol.content-charset",charSet);
                setRequestParams(method, params);
                HashMap<String, Object> responseObject = new HashMap<String, Object>();
                try {
                        int responseCode = httpclient.executeMethod(method);
                        String respBody=getResponseBody(method);// See details Below
                        responseObject.put(REQUEST_PARAMS, params);
                        responseObject.put(RESPONSE_BODY, respBody);
                        responseObject.put(RESPONSE_STATUS, responseCode);
                        return responseObject;
                } catch (Exception e) {
                        logger.error("Error Sending REST Request [URL:"+serviceUrl+",METHOD:"+sendMethod+",PARAMS:"+params+"]", e);
                        throw new AiServiceException(e);
                } finally {
                        method.releaseConnection();
                }
        }

To make this work I  wrote a method parse an actual HttpMethod Object from a given string:
getHttpMethodFromString():

private HttpMethod getHttpMethodFromString(String methodString) {
		if (StringUtils.isNotBlank(methodString)) {
			org.springframework.http.HttpMethod parsedMethod = org.springframework.http.HttpMethod
					.valueOf(methodString.toUpperCase());
			switch (parsedMethod) {//Add other methods as needed PUT, DELETE etc.
			case GET:
				return new GetMethod();
			case POST:
				return new PostMethod();
			default:
				return new GetMethod();
			}
		}
		return new GetMethod();
	}

Finally I needed to make sure to read the entire response before returning it to caller:
getResponseBody():

protected String getResponseBody(HttpMethod method){
		//Ensure we have read entire response body by reading from buffered stream
		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) {
				logger.error("Error Reading Response Stream",e);
				throw new AiServiceException(e);
			}finally{
				try {
					dumpOut.flush();
					dumpOut.close();
					if(in!=null)
						in.close();
				} catch (IOException e) {
					logger.warn("Error Closing Response Stream",e);
				}
			}
			return StringEscapeUtils.unescapeHtml(stringOut.toString());
		}
		return null;
	}

The newer Apache HttpComponents Project offers some evolutionary features over HttpClient like Plug-able authentication mechanisms, but the code shown above based on the legacy HttpClient libs works very well for my needs and is easily upgradeable should the need arise.

Technology

Jira Tabs: Open all those Jira’s at once!

Ever want to open all the Jira’s on the screen (search and filter views) in new tabs? Jess does, I do, and you should too!

For firefox and chrome we now have the JiraTabs bookmark button.

Drag this link up to your bookmarks bar: JiraTabs. Then, whenever you are on a filter or search view of Jira’s, click the button and all the jira’s on your screen will open up in new tabs

Demo:

Any updates will be made here.

Technology

Ai and Canopy are Proud to Sponsor Greenwich Village Little League

As long-time fans of all things baseball – most of us root for the Yankees (some for the Mets, we’re not naming names), Ai is happy to sponsor a Greenwich Village Little League Dodgers of the Jr. Minors Division!  Our very own Canopy Commerce decided to get in on the act too and is the proud sponsor of the GVLL Giants of the T-Ball Division.  Nothing like bragging rights to keep things lively at the office.  Play ball!

 

Ai

Extending a Magento Controller

We’re ajaxing part of the Magento shopping cart so we need to modify/extend some of the cart controller functionality. Sometimes when modifying controller’s you have to worry about updating the routes. For this, we don’t need to, we still want all the urls to be used the same way.

app/code/local/Ai/Checkout/etc/config.xml:

<config>
    <modules>
        <Ai_Checkout>
             <version>0.0.1</version>
        </Ai_Checkout>
    </modules>
...
    <frontend>
        <routers>
            <checkout>
                <use>standard</use>
                <args>
                    <module>Ai_Checkout</module>
                    <frontName>checkout</frontName>
                </args>
            </checkout>
        </routers>
    </frontend>
</config>

app/code/local/Ai/Checkout/controllers/CartController.php:

require_once Mage::getModuleDir('controllers', 'Mage_Checkout') . DS . 'CartController.php';

class Ai_Checkout_CartController extends Mage_Checkout_CartController
{
   public function updatePostAction()
    {
    	Mage::log("NEW CONTROLLER", null, 'tim.log');
        try {
Technology

Skynet Becomes Self Aware Tonight

Terminator: The Sarah Connor ChroniclesEdit Terminator: The Sarah Connor Chronicles section

As a result of temporal interference by Sarah Connor, her son JohnMiles Dyson, and the T-800[2] destroyingCyberdyne headquarters and all backups of the research in 1995, the date for Judgment day is moved back to here.[3] Skynet is destined to go online a few days earlier on April 192011 at 20:11

Funny Stuff

Cuttin’ Through the Clutta Like A Knife Through Butta

As the economy slowly pulls itself out of the recession, retailers are trying to connect with consumers in different ways.  Reuters reports that Best Buy is scaling back its trademark “big box” stores, focusing instead on “mobile” retail locations and bolstering their online presence.  However, The New York Times reported last week that many brick-and-mortar stores are back to embracing size and clutter.  While piling up the goods may be great for B&Ms, this strategy usually fails to translate in the expanding ecommerce world.

Online there exist far better strategies for engaging consumers than drowning them in a sea of digital clutter. We advise our clients to embrace simplicity, proven behavioral strategies and technology like dynamic personalization. Few if any brick-and-mortar stores can make quick, store-wide changes like what can be done online.  Digital optimization strategies allow our clients to take risks and experiment with their online offering, to adjust quickly based on real-time feedback, and then to experiment some more.

We have empowered many clients with this strategy, and it works.  For example, our de-cluttering redesign of PexSupply resulted in a 33% jump in conversions, and 45% increase in total orders.  Take a look at the difference after the break.

Business

Amping Up Apple’s Compare Grid

Apple recently launched a nifty DHTML comparison grid to help customers find the best Mac for them. The comparison grid features drag-n-drop capability, so that you can compare items you might be thinking about side by side, as depicted below:

Let’s take things up a notch, using some comparison features Ai has implemented for our clients.

The first thing to deal with is the large amount of text describing the product specs. While detailed specs are great, quick scannability suffers with the way Apple has implemented them.  In order to make things more scannable, Ai would:

  1. Move to a model where the spec definition is listed in the lefthand column, and checkmarks are used to indicate whether a specific model (column) has the spec or not.
  2. Show more detailed information about a spec using DHTML expand/collapse widgets.

This quick addition of progressive disclosure of detailed information in the grid enables quick scanning of specs while still allowing users to get detailed information if they so desire. Check out the videos below to see how Ai implemented just this approach two different ways for Bizfilings:

View the live Bizfilings Comparison Grid and Product Comparison Screen

Next, let’s take Apple’s concept of DHTML drag-n-drop one step further. Several years ago, Ai implemented a sophisticated course comparison grid for Kaplan Test Prep & Admissions. This grid allowed the user to drag-n-drop to reorder, and also to add/remove items from the comparison grid. Check it out here:

One thing we could change now – the x’s to remove items from the grid can be presented on mouseover, eliminating some visual cruft.

Voila! Apple’s Mac comparison grid, Ai’ified.

UX

Moving Gmail Gadgets to the Right Side

I started using Remember the Milk recently but didn’t want the gmail gadget to be so far down on the left hand side of my screen. There is no built in way to move gadgets to the right hand side with the exception of chat (labels used to do this but was removed in favor of drag in drop back in late 2009).

If you don’t have anything in the right hand column, enable Right-Side Chat from Gmail Labs. We are going to add in some custom css to gmail so install either Stylist for Chrome or Stylish for Firefox.

Add the following style:

div.TZ:nth-child(8) {
    position:absolute !important;
    right:0px;
    top:165px;
    width:164px;
}

In chrome you can also restrict the domain to mail.google.com. For me, the Remember the Milk gadget was the 8th child. Play with this until it looks right for you. You may also have to play with the “top” element depending on how much room your chat gadget takes up

Technology

Bowling at 300 New York

The Ai crew headed down to Chelsea Piers for some bowling last Thursday – completely disregarding the office imperative regarding glass houses.

I personally decided to take a humane approach with the pins, leaving a near perfect homeostasis in their natural parquet habitat.  Other members of the team were not so kind:

Dave “Quiet Thunder” Napolitan put up a stellar debut game of 162.  This barely edged out the night’s most consistent act, Jess “The Paleo Pin Pulverizer” Levy, who treated the tenth frame like her dinner plate, laying down straight turkey.

Check out the pictures on our Flickr stream.

The Paleo Pin Pulverizer

Ai