/*
* Copyright (C) 2014 Intel Corporation
* All rights reserved.
*/
package com.intel.mtwilson.rpc.v2.resource;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.intel.dcsg.cpg.io.UUID;
import com.intel.mtwilson.launcher.ws.ext.RPC;
import com.intel.mtwilson.rpc.v2.model.Rpc;
import com.intel.mtwilson.rpc.v2.model.RpcPriv;
import com.thoughtworks.xstream.XStream;
import java.lang.annotation.Annotation;
import java.nio.charset.Charset;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.POST;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.Response;
/**
* Base class for RPC resources to extend for automatic async functionality.
*
* Subclasses must be annotated with
*
* @RPC,
* @Path, and
* @V2
*
* @author jbuhacoff
*/
public class AbstractRpcResource {
private XStream xstream = new XStream();
private ObjectMapper mapper; // for debug only
protected RpcRepository repository = new RpcRepository();
@Context
private HttpServletRequest request;
@Context
private HttpServletResponse response;
protected boolean isAsync() {
String async = request.getHeader("Asynchronous");
return async != null && async.equalsIgnoreCase("true");
}
/**
* Web service methods in subclasses should look like this:
*
* <code>
*
* @Path("/rpc-resource-name")<br/>
* @POST<br/>
* @Consumes(...)<br/>
* @Produces(...)<br/>
* public OutputType invokeRpcName(InputType input) { <br/>
* if( isAsync() ) {<br/>
* storeAsyncRpc(input);<br/>
* return null;<br/>
* }<br/>
* doSomething();<br/>
* return output;<br/>
* }<br/>
* </code>
*
* The rpc-resource-name, InputType, OutputType, and invokeRpcName in the
* example would be replaced with concrete names in the subclass.
*
* @param inputObject
*/
protected void storeAsyncRpc(Object inputObject) {
// save rpc name, input (subclass must include headers and query string in that data structure if they are needed) to database so rpc invoker can execute it later
byte[] inputXml = toXml(inputObject);
// prepare the rpc task with the input
RpcPriv rpc = new RpcPriv();
rpc.setId(new UUID());
rpc.setName(getRpcName());
rpc.setInput(inputXml);
// com.intel.dcsg.cpg.util.MultivaluedHashMap<String,String> headers = RpcUtil.convertHeadersToMultivaluedMap(request);
// rpc.setInputHeaders(toRfc822(headers));
rpc.setStatus(Rpc.Status.QUEUE);
// store it
repository.create(rpc);
// prepare an HTTP 202 Accepted response with headers to confirm async processing and link to status (and output - which won't be available until status indicates "OUTPUT")
response.addHeader("Asynchronous", "true");
response.addHeader("Link", String.format("</rpcs/%s>; rel=status", rpc.getId()));
response.addHeader("Link", String.format("</rpcs/%s>/output; rel=output", rpc.getId()));
response.setStatus(Response.Status.ACCEPTED.getStatusCode());
}
protected String getRpcName() {
RPC rpcAnnotation = getClass().getAnnotation(RPC.class);
return rpcAnnotation.value();
}
// copied from AbstractRpc class
protected byte[] toXml(Object inputObject) {
return xstream.toXML(inputObject).getBytes(Charset.forName("UTF-8"));
}
}