Using OpenBox API @ Box.net with Spring

Box.net is an enterprise service which offers businesses a document collaboration tool in the cloud.  It’s straightforward to get access to box.net’s API’s.  Just sign up with a free account if you don’t have one, and then create a OpenBox application at http://developer.box.net to obtain an API key for use in your applications.

I was trying out their API’s recently, and found it’s works well with Spring framework.  Therefore, I decided to create an application to see how easy it is to use Box.net in Java.  The example uses mainly Spring’s RestTemplate and Spring MVC.  Using RestTemplate with Box.net’s API isn’t different than using it with other restful Web Services, and I have also covered it’s usage a few times in my previous posts.  The source can be found on GitHub at https://github.com/barryku/SpringCloud/tree/master/BoxApp/BoxNet.  The excellent Restful Web Service support in Spring framework makes it easy to work with any cloud services in Java.  You may find there’s no need need of any Java API for using Box.net’s Restful Web Services if you already use Spring in your projects.

There’s a live demo I put on AWS Beanstalk at http://boxnet.elasticbeanstalk.com that you can try when it’s running. Click on the home icon will take you back to the root folder.

The more challenging part of the example, on the other hand, is handling Box.net’s authentication flow.  The OAuth like authentication flow is explained in detail at http://developers.box.net/w/page/12923915/ApiAuthentication.  I use Spring MVC to handle the 3-legged authentication flow, and the same mechanism can be easily adapted to handle other OAuth or OAuth-like authentications.  The authToken is stored as an HTTP session attribute to be reused for subsequent requests.  It doesn’t the following steps when the first time user accesses the application,

  1. store the request url in the HTTP session
  2. forward to “auth” controller to do user authentication as followed,
    1. use API key to get the request token(ticket) via RestTemplate
    2. redirect user to Box.net’s authentication page with the ticket
  3. handle callback from Box.net using “boxnet” controller
  4. save authToken to session
  5. redirect user back to the saved request url

step 1 – 2

@RequestMapping("/folders/{folderId}")
public String getAssetListWithFolderId(@PathVariable("folderId") String folderId, Model model,
		@RequestHeader(value="output-format", defaultValue="none") String ouputFormat,
		 HttpSession session, HttpServletRequest req) {
	session.setAttribute(SESSION_ACTION, req.getPathInfo());
	List<Asset> assets = null;
	repositoryService.setAuthToken((String) session.getAttribute(SESSION_AUTH_TOKEN));
	try {
		log.debug("get folder: " + folderId);
		assets = repositoryService.getAssetList(folderId);
	} catch (UnauthenticatedException ae) {
		return "forward:" + getAuthUrl(ae);
	}

	log.info("assets count: " + assets.size());
	model.addAttribute("homeUrl","/" + MVC_CONTEXT + "/assets");
	model.addAttribute("assets", assets);
	if ("json".equals(ouputFormat)) {
		return "jsonView";
	} else {
		return "assetList";
	}
}

step 2A – 2B (auth controller)

@RequestMapping("/auth")
public String doAuth(@RequestParam(value="requestUrl", required=false) String requestUrl,
		@RequestParam(value="authUrl", required=false) String authUrl) {
	log.debug("get request token via:" + requestUrl);
	Source response = restTemplate.getForObject(requestUrl, Source.class);
	String requestToken = xpathTemplate.evaluateAsString("//ticket", response);
	return "redirect:" + authUrl + requestToken;
}

step 3 – 5 (boxnet controller)

@RequestMapping("/boxnet")
public String boxnetCallback(@RequestParam(value="auth_token") String authToken,
		HttpSession session) {
	session.setAttribute(SESSION_AUTH_TOKEN, authToken);
	String action = (String) session.getAttribute(SESSION_ACTION);
	log.info("after auth, forward to:" + action);
	return "forward:/" + MVC_CONTEXT + action;
}

In my application, I also used Spring’s XpathTemplate to parse the XML output from box.net’s restful API’s.  It will be nice if they can add JSON output later, so it can be consumed without doing XML parsing or JAXB.  The following is my implementation class which uses get_account_tree to retrieve contents of a given folder on box.net,

private static final String URI_GET_ACCOUNT_TREE = "{resetUrl}&action=get_account_tree&folder_id={folderId}&params[]=onelevel&params[]=nozip&auth_token={authToken}";

public List<Asset> getAssetList(String path)
			throws UnauthenticatedException {
		checkAuthentication();

		List<Asset> assets = new ArrayList<Asset>();

		//path will replace the vars in the restRequest URI template, i.e. {restUrl} and {folderId}
		Source response = restTemplate.getForObject(URI_GET_ACCOUNT_TREE, Source.class, restUrl, path, authToken);
		List<FileItem> files = xpathTemplate.evaluate("//files/file", response, new NodeMapper<FileItem>() {
			@Override
			public FileItem mapNode(Node node, int nodeNum) throws DOMException {
				Element element = (Element) node;
				FileItem bfile = new FileItem();
				bfile.setId(element.getAttribute("id"));
				bfile.setFileName(element.getAttribute("file_name"));
				return bfile;
			}
		});

		.....
	}

I configured my implementation class (a Spring bean) as followed,

    <bean id="xpathTemplate" class="org.springframework.xml.xpath.Jaxp13XPathTemplate"/>
    <bean id="restTemplate" class="org.springframework.web.client.RestTemplate"/>
    <bean id="boxnetRepositoryService" class="com.barryku.boxnet.service.impl.RepositoryBoxNetImpl">
		<property name="downloadUrl" value="${box.net.downloadUrl}"/>
		<property name="requestUrl" value="${box.net.requestUrl}${box.net.apiKey}"/>
		<property name="authUrl" value="${box.net.authUrl}"/>
		<property name="restUrl" value="${box.net.restUrl}${box.net.apiKey}"/>
		<property name="restTemplate" ref="restTemplate"/>
		<property name="xpathTemplate" ref="xpathTemplate"/>
	</bean>
This entry was posted in Cloud and tagged . Bookmark the permalink.

3 Responses to Using OpenBox API @ Box.net with Spring

  1. Pingback: Simple XML with Android and Box.net | Agile SOA Cloud

  2. Pingback: Alexander1

  3. Pingback: Alexander7

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>