/*************************************************************************** * * * InvocationThread.java * * ------------------- * * date : 01.09.2004 * * copyright : (C) 2004-2008 Distributed and * * Mobile Systems Group * * Lehrstuhl fuer Praktische Informatik * * Universitaet Bamberg * * http://www.uni-bamberg.de/pi/ * * email : sven.kaffille@uni-bamberg.de * * karsten.loesing@uni-bamberg.de * * * * * ***************************************************************************/ /*************************************************************************** * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * A copy of the license can be found in the license.txt file supplied * * with this software or at: http://www.gnu.org/copyleft/gpl.html * * * ***************************************************************************/ package de.uniba.wiai.lspi.chord.com.socket; import java.io.IOException; import java.io.ObjectOutputStream; import java.io.Serializable; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import de.uniba.wiai.lspi.util.logging.Logger; import static de.uniba.wiai.lspi.util.logging.Logger.LogLevel.*; /** * This <code>Thread</code> is used to make a method invocation on a node that * is accessible through sockets over its {@link SocketEndpoint}. * * @author sven * @version 1.0.5 */ class InvocationThread implements Runnable { /** * Name of property which defines the number of threads in pool created by * {@link #createInvocationThreadPool()}. */ protected static final String CORE_POOL_SIZE_PROPERTY_NAME = InvocationThread.class .getName() + ".corepoolsize"; /** * Name of property which defines the maximum number of threads in pool * created by {@link #createInvocationThreadPool()}. */ protected static final String MAX_POOL_SIZE_PROPERTY_NAME = InvocationThread.class .getName() + ".maxpoolsize"; /** * Name of property which defines the time the threads in pool created by * {@link #createInvocationThreadPool()} can stay idle before being * terminated. */ protected static final String KEEP_ALIVE_TIME_PROPERTY_NAME = InvocationThread.class .getName() + ".keepalivetime"; /** * The number of core threads in ThreadPool created by * {@link #createInvocationThreadPool()}. */ private static final int CORE_POOL_SIZE = Integer.parseInt(System .getProperty(CORE_POOL_SIZE_PROPERTY_NAME)); /** * The maximum number of threads in ThreadPool created by * {@link #createInvocationThreadPool()}. */ private static final int MAX_POOL_SIZE = Integer.parseInt(System .getProperty(MAX_POOL_SIZE_PROPERTY_NAME)); /** * The time threads in ThreadPool created by * {@link #createInvocationThreadPool()} can be idle before being * terminated. */ private static final int KEEP_ALIVE_TIME = Integer.parseInt(System .getProperty(KEEP_ALIVE_TIME_PROPERTY_NAME)); /** * The logger for instances of this class. */ private static final Logger logger = Logger .getLogger(InvocationThread.class); private static final boolean debug = logger.isEnabledFor(DEBUG); /** * The request that has to be handled by this InvocationThread. Represents * the method to be invoked. */ private Request request; /** * The {@link RequestHandler} that started this thread. */ private RequestHandler handler; /** * The {@link ObjectOutputStream} to write the results of the invocation to. */ private ObjectOutputStream out; /** * * @param handler1 * Reference to {@link RequestHandler} that started this. * @param request1 * The {@link Request} that caused this invocation to be started. * @param out1 * The stream to which to write the result of the invocation. */ InvocationThread(RequestHandler handler1, Request request1, ObjectOutputStream out1) { this.handler = handler1; this.request = request1; this.out = out1; // schedule this for execution this.handler.getEndpoint().scheduleInvocation(this); if (debug) { logger.debug("InvocationThread scheduled for request " + request1); } } public String toString() { StringBuffer sb = new StringBuffer(); sb.append("[Invocation of "); sb.append(MethodConstants.getMethodName(this.request.getRequestType())); sb.append("] Request: "); sb.append(this.request); return sb.toString(); } /** * This <code>run</code>-method invokes the Method that is assigned to it * by {@link Request} provided in its * {@link #InvocationThread(RequestHandler, Request, ObjectOutputStream) constructor}. */ public void run() { if (debug) { logger.debug(this + " started"); } int requestType = this.request.getRequestType(); String methodName = MethodConstants.getMethodName(requestType); if (debug) { logger.debug("Request received. Requested method: " + methodName); } /* and try to execute the requested method */ try { if (debug) { logger.debug("Trying to invoke method " + methodName); } Serializable result = this.handler.invokeMethod(requestType, this.request.getParameters()); /* Send result of requested method back to requestor. */ Response response = new Response(Response.REQUEST_SUCCESSFUL, requestType, this.request.getReplyWith()); response.setResult(result); synchronized (this.out) { this.out.writeObject(response); this.out.flush(); this.out.reset(); } logger.debug("Method invoked and result has been sent."); } catch (IOException e) { if (this.handler.connected) { logger.warn("Could not send response. Disconnecting!", e); this.handler.disconnect(); } /* else socket has been closed */ } catch (Exception t) { if (debug) { logger.debug("Throwable occured during execution of request " + MethodConstants.getMethodName(requestType) + "!"); } this.handler.sendFailureResponse(t, "Could not execute request! " + "Reason unknown! Maybe this helps: " + t.getMessage(), this.request); } // this.request = null; this.handler = null; this.out = null; if (debug) { logger.debug(this + " finished"); } } /** * Creates a ThreadPool that is used by the {@link SocketEndpoint} to * execute instances of this class. * * @return A ThreadPool that is used by the {@link SocketEndpoint} to * execute instances of this class. */ static ThreadPoolExecutor createInvocationThreadPool() { return new ThreadPoolExecutor(CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>(), new ThreadFactory() { private static final String name = "InvocationExecution-"; public Thread newThread(Runnable r) { Thread newThread = new Thread(r); newThread.setName(name + newThread.getName()); return newThread; } }); } }