/*
* Copyright 2011 cruxframework.org.
*
* 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 org.cruxframework.crux.core.server.dispatch;
import java.lang.reflect.Method;
import org.cruxframework.crux.core.i18n.LocaleResolver;
import org.cruxframework.crux.core.i18n.LocaleResolverInitializer;
import org.cruxframework.crux.core.server.dispatch.st.CruxSynchronizerTokenHandler;
import org.cruxframework.crux.core.server.dispatch.st.CruxSynchronizerTokenHandlerFactory;
import org.cruxframework.crux.core.server.dispatch.st.InvalidTokenException;
import org.cruxframework.crux.core.shared.rpc.st.UseSynchronizerToken;
import org.cruxframework.crux.core.utils.RegexpPatterns;
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;
/**
*
* @author Thiago Bustamante
*/
public class RemoteServiceServlet extends com.google.gwt.user.server.rpc.RemoteServiceServlet
{
private static final long serialVersionUID = -5471459247489132091L;
/**
* @see com.google.gwt.user.server.rpc.RemoteServiceServlet#processCall(java.lang.String)
*/
@Override
public String processCall(String payload) throws SerializationException
{
boolean localeInitializedByServlet = false;
try
{
localeInitializedByServlet = initUserLocaleResolver();
Object service = getServiceForRequest(payload);
RPCRequest rpcRequest = RPC.decodeRequest(payload, service.getClass(), this);
onAfterRequestDeserialized(rpcRequest);
//TODO: criar um ponto de injecao de comportamento aki.... para permitir que plugins sejam criados (ex: seguranca, logs, etc)
CruxSynchronizerTokenHandler handler = CruxSynchronizerTokenHandlerFactory.getCruxSynchronizerTokenHandler(getThreadLocalRequest());
boolean useToken = checkSynchonizerToken(rpcRequest, handler);
try
{
return RPC.invokeAndEncodeResponse(service, rpcRequest.getMethod(),
rpcRequest.getParameters(), rpcRequest.getSerializationPolicy());
}
finally
{
if (useToken)
{
String methodFullSignature = handler.getMethodDescription(rpcRequest.getMethod());
handler.endMethod(methodFullSignature);
}
}
}
catch (IncompatibleRemoteServiceException ex)
{
log("An IncompatibleRemoteServiceException was thrown while processing this call.",ex);
return RPC.encodeResponseForFailure(null, ex);
}
finally
{
if (localeInitializedByServlet)
{
clearUserLocaleResolver();
}
}
}
/**
* @param rpcRequest
* @param handler
* @return
* @throws IncompatibleRemoteServiceException
*/
protected boolean checkSynchonizerToken(RPCRequest rpcRequest, CruxSynchronizerTokenHandler handler) throws IncompatibleRemoteServiceException
{
Method method = rpcRequest.getMethod();
if (method.getAnnotation(UseSynchronizerToken.class) != null)
{
String methodFullSignature = handler.getMethodDescription(method);
if (!handler.isMethodRunning(methodFullSignature))
{
try
{
handler.startMethod(methodFullSignature);
return true;
}
catch (InvalidTokenException e)
{
throw new IncompatibleRemoteServiceException(e.getLocalizedMessage(), e);
}
}
else
{
throw new IncompatibleRemoteServiceException("Invalid Synchronizer Token for method ["+methodFullSignature+"]. Possible CSRF attack.");
}
}
return false;
}
/**
*
*/
protected boolean initUserLocaleResolver()
{
if (LocaleResolverInitializer.getLocaleResolver() == null)
{
LocaleResolverInitializer.createLocaleResolverThreadData();
LocaleResolver resolver = LocaleResolverInitializer.getLocaleResolver();
resolver.initializeUserLocale(getThreadLocalRequest());
return true;
}
return false;
}
/**
*
*/
protected void clearUserLocaleResolver()
{
LocaleResolverInitializer.clearLocaleResolverThreadData();
}
/**
* Return the service that will handle this request
* @param encodedRequest
* @return
* @throws IncompatibleRemoteServiceException
*/
protected Object getServiceForRequest(String encodedRequest) throws IncompatibleRemoteServiceException
{
try
{
if (!ServiceFactoryInitializer.isFactoryInitialized())
{
ServiceFactoryInitializer.initialize(getServletContext());
}
// We don't need to verify or parse the encodedRequest because it will be already done by
// RPC.decodeRequest. So, just read the interface name directly
String serviceIntfName = RegexpPatterns.REGEXP_PIPE.split(encodedRequest)[5];
Object service = ServiceFactoryInitializer.getServiceFactory().getService(serviceIntfName);
if (service instanceof RequestAware)
{
((RequestAware)service).setRequest(getThreadLocalRequest());
}
if (service instanceof ResponseAware)
{
((ResponseAware)service).setResponse(getThreadLocalResponse());
}
if (service instanceof SessionAware)
{
((SessionAware)service).setSession(getThreadLocalRequest().getSession());
}
return service;
}
catch (Throwable e)
{
throw new IncompatibleRemoteServiceException(e.getLocalizedMessage(), e);
}
}
}