/*
* Copyright 2000-2013 Enonic AS
* http://www.enonic.com/license
*/
package com.enonic.cms.web.main;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.util.NestedServletException;
import com.enonic.cms.api.client.ClientException;
import com.enonic.cms.api.client.LocalClient;
import com.enonic.cms.api.client.binrpc.BinRpcInvocation;
import com.enonic.cms.api.client.binrpc.BinRpcInvocationResult;
/**
* This class implements the service exporter.
*/
@Controller
public final class BinRpcServiceExporter
{
private final static String CONTENT_TYPE_SERIALIZED_OBJECT = "application/x-java-serialized-object";
private LocalClient client;
@Value("${cms.security.rpc.enabled}")
private boolean rpcEnabled;
@Autowired
@Qualifier("remoteClient")
public void setLocalClient( final LocalClient client )
{
this.client = client;
}
@RequestMapping(value = "/rpc/bin", method = RequestMethod.POST)
public ModelAndView handleRequest( final HttpServletRequest req, final HttpServletResponse res )
throws ServletException, IOException
{
if ( !this.rpcEnabled )
{
BinRpcInvocationResult result = new BinRpcInvocationResult( new ClientException( "RPC service is turned off" ) );
writeInvocationResult( res, result );
return null;
}
try
{
BinRpcInvocation invocation = readInvocation( req );
BinRpcInvocationResult result = invokeAndCreateResult( invocation, this.client );
writeInvocationResult( res, result );
}
catch ( ClassNotFoundException ex )
{
throw new NestedServletException( "Class not found during deserialization", ex );
}
return null;
}
private BinRpcInvocation readInvocation( final HttpServletRequest req )
throws IOException, ClassNotFoundException
{
InputStream in = req.getInputStream();
ObjectInputStream ois = new ObjectInputStream( in );
try
{
Object obj = ois.readObject();
if ( !( obj instanceof BinRpcInvocation ) )
{
throw new IOException(
"Deserialized object needs to be assignable to type [" + BinRpcInvocation.class.getName() + "]: " + obj );
}
else
{
return (BinRpcInvocation) obj;
}
}
finally
{
ois.close();
}
}
private void writeInvocationResult( final HttpServletResponse res, final BinRpcInvocationResult result )
throws IOException
{
res.setContentType( BinRpcServiceExporter.CONTENT_TYPE_SERIALIZED_OBJECT );
OutputStream out = res.getOutputStream();
ObjectOutputStream oos = new ObjectOutputStream( out );
try
{
oos.writeObject( result );
oos.flush();
}
finally
{
oos.close();
}
}
private BinRpcInvocationResult invokeAndCreateResult( final BinRpcInvocation invocation, final Object targetObject )
{
try
{
Object value = invocation.invoke( targetObject );
return new BinRpcInvocationResult( value );
}
catch ( Throwable ex )
{
return new BinRpcInvocationResult( ex );
}
}
}