/*
* Copyright (C) 2014 Intel Corporation
* All rights reserved.
*/
package com.intel.mtwilson.rpc.v2.resource;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.intel.dcsg.cpg.extensions.Extensions;
import com.intel.dcsg.cpg.io.UUID;
import com.intel.dcsg.cpg.rfc822.Message;
import com.intel.dcsg.cpg.util.MultivaluedHashMap;
import com.intel.dcsg.cpg.validation.Fault;
import com.intel.mtwilson.jaxrs2.mediatype.CryptoMediaType;
import com.intel.mtwilson.jaxrs2.mediatype.DataMediaType;
import com.intel.mtwilson.launcher.ws.ext.RPC;
import com.intel.mtwilson.launcher.ws.ext.V2;
import com.intel.mtwilson.rpc.v2.model.Rpc;
import com.intel.mtwilson.rpc.v2.model.RpcPriv;
import com.intel.mtwilson.v2.rpc.RpcInvoker;
import com.intel.mtwilson.v2.rpc.RpcUtil;
import com.thoughtworks.xstream.XStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
//import javax.ejb.Stateless;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MediaType;
//import javax.ws.rs.core.MultivaluedHashMap;
//import com.intel.dcsg.cpg.util.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
import javax.ws.rs.ext.MessageBodyReader;
import javax.ws.rs.ext.MessageBodyWriter;
import org.apache.commons.lang3.StringUtils;
import org.glassfish.jersey.message.MessageBodyWorkers;
/**
* Characteristics of a Remote Procedure Call is that the input and output are
* likely different types, that the client and server may negotiate for the
* processing to occur immediately (synchronous) or to be queued (asynchronous),
* that an RPC consists of a single method that is a verb phrase, and that the
* server is not expected to keep track of past inputs (but it is allowed to
* store them and index them as well as the outputs, of course) - if any storing
* or indexing of RPCs takes places, the interface to that stored data would be
* a resource.
*
* In contrast, a resource has one type and typically has several standard
* operations are defined on that type: create, store (update), retrieve,
* delete, and search which is defined on the collection of that type; a
* resource operation typically happens immediately (but the server may still
* choose to delay it and return an appropriate "accepted" http status code).
*
* @author jbuhacoff
*/
@V2
//@Stateless
@Path("/rpc-async")
public class AsyncRpc extends AbstractRpc {
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(AsyncRpc.class);
// private ObjectMapper mapper; // for debug only
// private RpcRepository repository = new RpcRepository();
public AsyncRpc() {
// mapper = new ObjectMapper();
// mapper.setPropertyNamingStrategy(PropertyNamingStrategy.CAMEL_CASE_TO_LOWER_CASE_WITH_UNDERSCORES);
}
// @Context
// private MessageBodyWorkers workers;
@Path("/{name}")
@POST
@Consumes(MediaType.WILDCARD)
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML, DataMediaType.APPLICATION_YAML, DataMediaType.TEXT_YAML})
public Rpc invokeAsyncRemoteProcedureCall(@PathParam("name") String name, @Context HttpServletRequest request, byte[] input) {
// make sure we have an extension to handle this rpc
RpcAdapter adapter = getAdapter(name);
// convert the client's input into our internal format
Object inputObject = getInput(input, adapter.getInputClass(), request);
// now serialize the input object with xstream; even though we're going to process immediately, we are still going to record the call in the RPC table so we need the xml
byte[] inputXml = toXml(inputObject);
// prepare the rpc task with the input
RpcPriv rpc = new RpcPriv();
rpc.setId(new UUID());
rpc.setName(name);
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);
// queue it (must follow storage to prevent situation where an executing task needs to store an update to the table and it hasn't been stored yet)
// RpcInvoker.getInstance().add(rpc.getId());
Rpc status = new Rpc();
status.copyFrom(rpc);
return status;
}
/*
private String toRfc822(com.intel.dcsg.cpg.util.MultivaluedHashMap<String,String> headers) {
ArrayList<String> lines = new ArrayList<String>();
for(String name : headers.keySet()) {
for(String value : headers.getAll(name)) {
lines.add(String.format("%s: %s", name, value));
}
}
return StringUtils.join(lines, "\n");
}*/
}