blob: 464362a504a51be4ceac5db66641910a8c3e67fd [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2012 EclipseSource and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* EclipseSource - initial API and implementation
******************************************************************************/
package org.eclipse.rap.rwt.internal.lifecycle;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.eclipse.rap.rwt.internal.service.ContextProvider;
import org.eclipse.rap.rwt.internal.service.ServiceContext;
import org.eclipse.rap.rwt.internal.service.ServiceStore;
import org.eclipse.rap.rwt.internal.util.ClassUtil;
import org.eclipse.rap.rwt.service.UISession;
import org.eclipse.swt.internal.widgets.IDisplayAdapter;
import org.eclipse.swt.widgets.Display;
public final class ContextUtil {
private static final ClassLoader CLASS_LOADER = ContextUtil.class.getClassLoader();
private static final HttpServletResponse FAKE_RESPONSE = createFakeResponse();
private static final Class<?> FAKE_REQUEST_CLASS = getRequestProxyClass();
private ContextUtil() {
// prevent instantiation
}
public static void runNonUIThreadWithFakeContext( Display display, Runnable runnable ) {
UISession uiSession = display.getAdapter( IDisplayAdapter.class ).getUISession();
runNonUIThreadWithFakeContext( uiSession, runnable );
}
public static void runNonUIThreadWithFakeContext( UISession uiSession, Runnable runnable ) {
// Don't replace local variables by method calls, since the context may
// change during the methods execution.
boolean useDifferentContext = ContextProvider.hasContext()
&& ContextProvider.getUISession() != uiSession;
ServiceContext contextBuffer = null;
// TODO [fappel]: The context handling's getting very awkward in case of
// having the context mapped instead of stored it in
// the ContextProvider's ThreadLocal (see ContextProvider).
// Because of this the wasMapped variable is used to
// use the correct way to restore the buffered context.
// See whether this can be done more elegantly and supplement
// the test cases...
boolean wasMapped = false;
if( useDifferentContext ) {
contextBuffer = ContextProvider.getContext();
wasMapped = ContextProvider.releaseContextHolder();
}
boolean useFakeContext = !ContextProvider.hasContext();
if( useFakeContext ) {
ContextProvider.setContext( createFakeContext( uiSession ) );
}
try {
runnable.run();
} finally {
if( useFakeContext ) {
ContextProvider.disposeContext();
}
if( useDifferentContext ) {
if( wasMapped ) {
ContextProvider.setContext( contextBuffer, Thread.currentThread() );
} else {
ContextProvider.setContext( contextBuffer );
}
}
}
}
public static ServiceContext createFakeContext( UISession uiSession ) {
HttpServletRequest request = createFakeRequest( uiSession );
ServiceContext result = new ServiceContext( request, FAKE_RESPONSE, uiSession );
result.setServiceStore( new ServiceStore() );
return result;
}
private static HttpServletRequest createFakeRequest( UISession uiSession ) {
InvocationHandler invocationHandler = new RequestInvocationHandler( uiSession );
Class[] paramTypes = new Class[] { InvocationHandler.class };
Object[] paramValues = new Object[] { invocationHandler };
Object fakeRequest = ClassUtil.newInstance( FAKE_REQUEST_CLASS, paramTypes, paramValues );
return ( HttpServletRequest )fakeRequest;
}
private static Class<?> getRequestProxyClass() {
return Proxy.getProxyClass( CLASS_LOADER, new Class<?>[] { HttpServletRequest.class } );
}
private static HttpServletResponse createFakeResponse() {
Class[] interfaces = new Class[] { HttpServletResponse.class };
ResponseInvocationHandler invocationHandler = new ResponseInvocationHandler();
Object proxy = Proxy.newProxyInstance( CLASS_LOADER, interfaces, invocationHandler );
return ( HttpServletResponse )proxy;
}
private static final class ResponseInvocationHandler implements InvocationHandler {
public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable {
throw new UnsupportedOperationException();
}
}
private static class RequestInvocationHandler implements InvocationHandler {
private final UISession uiSession;
RequestInvocationHandler( UISession uiSession ) {
this.uiSession = uiSession;
}
public Object invoke( Object proxy, Method method, Object[] args ) throws Throwable {
Object result;
if( "getSession".equals( method.getName() ) ) {
result = uiSession.getHttpSession();
} else if( "getLocale".equals( method.getName() ) ) {
result = null;
} else {
throw new UnsupportedOperationException();
}
return result;
}
}
}