/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2012 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.util; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.rmi.Remote; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import com.servoy.j2db.persistence.RepositoryException; /** * Invocation handler that runs all methods in a thread, so thread locals of the calling thread do not conflict with the thread locals used in the call. * * @author rgansevles * * @since 6.1 */ public class ThreadingRemoteInvocationHandler<T extends Remote> extends AbstractRemoteInvocationHandler<T> { private static ExecutorService threadPool = Executors.newCachedThreadPool(); private ThreadingRemoteInvocationHandler(T remote) { super(remote); } public static <T extends Remote> T createThreadingRemoteInvocationHandler(T obj) { if (obj == null) { return null; } return createThreadingRemoteInvocationHandler(obj, getRemoteInterfaces(obj.getClass())); } @SuppressWarnings("unchecked") public static <T extends Remote> T createThreadingRemoteInvocationHandler(T obj, Class< ? >[] interfaces) { if (obj == null) { return null; } return (T)Proxy.newProxyInstance(obj.getClass().getClassLoader(), interfaces, new ThreadingRemoteInvocationHandler<T>(obj)); } /* * Invoke methods in a separate thread. * * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) */ public Object invoke(Object proxy, final Method method, final Object[] args) throws Throwable { final Object[] result = { null }; final Throwable[] throwable = { null }; Runnable methodRunner = new Runnable() { public void run() { try { result[0] = invokeMethod(method, args); } catch (Throwable t) { throwable[0] = t; } finally { synchronized (this) { this.notifyAll(); } } } }; synchronized (methodRunner) { threadPool.execute(methodRunner); try { methodRunner.wait(); } catch (InterruptedException e) { Debug.error(e); throw new RepositoryException(e.getMessage()); } } if (throwable[0] != null) { throw throwable[0]; } return result[0]; } }