/**
* Copyright (C) 2013 DaiKit.com - daikit4gxt module (admin@daikit.com)
*
* Project home : http://code.daikit.com/daikit4gxt
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.daikit.daikit4gxt.server.gwtspring;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.ServletConfigAware;
import com.google.gwt.user.client.rpc.IncompatibleRemoteServiceException;
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.server.rpc.RPC;
import com.google.gwt.user.server.rpc.RPCRequest;
import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.google.gwt.user.server.rpc.UnexpectedException;
/**
* Spring HandlerAdapter to dispatch GWT-RPC requests. <br>
*
* <a href="http://technophiliac.wordpress.com/2008/08/24/giving-gwt-a-spring-in-its-step/">http://technophiliac.
* wordpress.com/2008/08/24/giving-gwt-a-spring-in-its-step/</a>
*
* @author Thibaut CASELLI
*
*/
public class GwtRpcRemoteServletWrapper extends RemoteServiceServlet implements ServletConfigAware
{
private static Log log = LogFactory.getLog(GwtRpcRemoteServletWrapper.class);
private static ThreadLocal<Object> handlerHolder = new ThreadLocal<Object>();
private static ThreadLocal<HttpServletRequest> requestHolder = new ThreadLocal<HttpServletRequest>();
private static ThreadLocal<HttpServletResponse> responseHolder = new ThreadLocal<HttpServletResponse>();
private static final long serialVersionUID = -7421136737990135393L;
// IMPLEMENTATION OF HANDLER_ADAPTER
/**
* Forward request to {@link RemoteServiceServlet}
*
* @param request
* @param response
* @param handler
* @throws Exception
*/
public void handleRequest(final HttpServletRequest request, final HttpServletResponse response, final Object handler)
throws Exception
{
try
{
requestHolder.set(request);
responseHolder.set(response);
handlerHolder.set(handler);
doPost(request, response);
}
finally
{
requestHolder.set(null);
responseHolder.set(null);
handlerHolder.set(null);
}
}
// @Override
// protected void doUnexpectedFailure(final Throwable e)
// {
// super.doUnexpectedFailure(e);
// }
// protected void doUnexpectedFailure(Throwable e) {
// try {
// getThreadLocalResponse().reset();
// } catch (IllegalStateException ex) {
// /*
// * If we can't reset the request, the only way to signal that something
// * has gone wrong is to throw an exception from here. It should be the
// * case that we call the user's implementation code before emitting data
// * into the response, so the only time that gets tripped is if the object
// * serialization code blows up.
// */
// throw new RuntimeException("Unable to report failure", e);
// }
// ServletContext servletContext = getServletContext();
// RPCServletUtils.writeResponseForUnexpectedFailure(servletContext,
// getThreadLocalResponse(), e);
// }
// CUSTOM METHOD
protected Object getCurrentHandler()
{
return handlerHolder.get();
}
/**
* Get current {@link HttpServletRequest}
*
* @return current {@link HttpServletRequest}
*/
public HttpServletRequest getRequest()
{
return requestHolder.get();
}
/**
* Get current {@link HttpServletResponse}
*
* @return current {@link HttpServletResponse}
*/
public HttpServletResponse getResponse()
{
return responseHolder.get();
}
// OVERRIDE RemoteServiceServlet
@Override
public String processCall(final String payload) throws SerializationException
{
/*
* The code below is borrowed from RemoteServiceServet.processCall, with the following changes:
*
* 1) Changed object for decoding and invocation to be the handler (versus the original 'this')
*/
try
{
if (log.isDebugEnabled())
{
log.debug("currentHandler = [" + getCurrentHandler().getClass() + "], payload = [" + payload);
}
final RPCRequest rpcRequest = RPC.decodeRequest(payload, getCurrentHandler().getClass(), this);
if (log.isDebugEnabled())
{
log.debug("rpcRequest = [" + rpcRequest + "] rpcRequest.getSerializationPolicy() = ["
+ rpcRequest.getSerializationPolicy() + "]");
}
onAfterRequestDeserialized(rpcRequest);
final String response = RPC.invokeAndEncodeResponse(getCurrentHandler(), rpcRequest.getMethod(),
rpcRequest.getParameters(), rpcRequest.getSerializationPolicy());
if (log.isDebugEnabled())
{
log.debug("response = [" + response + "]");
}
return response;
}
catch (final IncompatibleRemoteServiceException ex)
{
if (log.isErrorEnabled())
{
log.error("Error in gwtRpcHandler :", ex);
}
return RPC.encodeResponseForFailure(null, ex);
}
catch (final UnexpectedException ex)
{
if (log.isErrorEnabled())
{
log.error("Error in GwtRpcRemoteServletWrapper :", ex);
}
return "An unexpected exception was thrown on server side. A service method, "
+ "being invoked by GWT RPC, throws a checked exception that is not in the service method's signature. "
+ "Such exceptions are 'unexpected' and the specific exception will be the cause of the UnexpectedException. Cause=[ "
+ (ex.getCause() == null ? "null" : ex.getCause()) + " ]";
}
}
@Override
public void setServletConfig(final ServletConfig config)
{
try
{
log.debug("Initialize GwtRpcRemoteServletWrapper with config : " + config);
super.init(config);
}
catch (final ServletException e)
{
log.error("Error during GwtRpcRemoteServletWrapper intitialization :", e);
}
}
}