| /******************************************************************************* |
| * 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; |
| } |
| } |
| |
| } |