/** * Copyright 2005-2014 Restlet * * The contents of this file are subject to the terms of one of the following * open source licenses: Apache 2.0 or or EPL 1.0 (the "Licenses"). You can * select the license that you prefer but you may not use this file except in * compliance with one of these Licenses. * * You can obtain a copy of the Apache 2.0 license at * http://www.opensource.org/licenses/apache-2.0 * * You can obtain a copy of the EPL 1.0 license at * http://www.opensource.org/licenses/eclipse-1.0 * * See the Licenses for the specific language governing permissions and * limitations under the Licenses. * * Alternatively, you can obtain a royalty free commercial license with less * limitations, transferable or non-transferable, directly at * http://restlet.com/products/restlet-framework * * Restlet is a registered trademark of Restlet S.A.S. */ package org.restlet.engine.connector; import java.net.InetSocketAddress; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.SynchronousQueue; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import org.restlet.Server; import org.restlet.engine.adapter.HttpServerHelper; import org.restlet.engine.log.LoggingThreadFactory; /** * Abstract Internal web server connector based on com.sun.net.httpserver * package. Here is the list of parameters that are supported. They should be * set in the Server's context before it is started: * <table> * <tr> * <th>Parameter name</th> * <th>Value type</th> * <th>Default value</th> * <th>Description</th> * </tr> * <tr> * <td>minThreads</td> * <td>int</td> * <td>1</td> * <td>Minimum number of worker threads waiting to service calls, even if they * are idle. Technically speaking, this is a core number of threads that are * pre-started.</td> * </tr> * <tr> * <td>maxThreads</td> * <td>int</td> * <td>10</td> * <td>Maximum number of worker threads that can service calls. If this number * is reached then additional calls are queued if the "maxQueued" value hasn't * been reached.</td> * </tr> * <tr> * <td>maxQueued</td> * <td>int</td> * <td>0</td> * <td>Maximum number of calls that can be queued if there aren't any worker * thread available to service them. If the value is '0', then no queue is used * and calls are rejected if no worker thread is immediately available. If the * value is '-1', then an unbounded queue is used and calls are never rejected.<br> * <br> * Note: make sure that this value is consistent with {@link #getMinThreads()} * and the behavior of the {@link ThreadPoolExecutor} configured internally.</td> * </tr> * <tr> * <td>maxThreadIdleTimeMs</td> * <td>int</td> * <td>300 000</td> * <td>Time for an idle thread to wait for an operation before being collected.</td> * </tr> * </table> * * @author Jerome Louvel */ public abstract class NetServerHelper extends HttpServerHelper { /** * Socket this server is listening to. */ private volatile InetSocketAddress address; /** * Indicates if this service is acting in HTTP or HTTPS mode. */ private volatile boolean confidential; /** * Constructor. * * @param server * The server to help. */ public NetServerHelper(Server server) { super(server); } /** * Creates the handler service. * * @return The handler service. */ protected ThreadPoolExecutor createThreadPool() { int maxThreads = getMaxThreads(); int minThreads = getMinThreads(); BlockingQueue<Runnable> queue = null; if (getMaxQueued() == 0) { queue = new SynchronousQueue<Runnable>(); } else if (getMaxQueued() < 0) { queue = new LinkedBlockingQueue<Runnable>(); } else { queue = new ArrayBlockingQueue<Runnable>(getMaxQueued()); } ThreadPoolExecutor result = new ThreadPoolExecutor(minThreads, maxThreads, getMaxThreadIdleTimeMs(), TimeUnit.MILLISECONDS, queue, new LoggingThreadFactory(getLogger(), true)); result.setRejectedExecutionHandler(new RejectedExecutionHandler() { public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { getLogger().warning( "Unable to run the following server-side task: " + r); } }); // Ensure that core threads act like a minimum number of threads result.prestartAllCoreThreads(); return result; } /** * Returns the socket address this server is listening to. * * @return The socket address this server is listening to. */ protected InetSocketAddress getAddress() { return this.address; } /** * Returns the maximum number of calls that can be queued if there aren't * any worker thread available to service them. If the value is '0', then no * queue is used and calls are rejected if no worker thread is immediately * available. If the value is '-1', then an unbounded queue is used and * calls are never rejected.<br> * <br> * Note: make sure that this value is consistent with * {@link #getMinThreads()} and the behavior of the * {@link ThreadPoolExecutor} configured internally. * * @return The maximum number of calls that can be queued. */ public int getMaxQueued() { return Integer.parseInt(getHelpedParameters().getFirstValue( "maxQueued", "0")); } /** * Returns the time for an idle thread to wait for an operation before being * collected. * * @return The time for an idle thread to wait for an operation before being * collected. */ public int getMaxThreadIdleTimeMs() { return Integer.parseInt(getHelpedParameters().getFirstValue( "maxThreadIdleTimeMs", "300000")); } /** * Returns the maximum threads that will service requests. * * @return The maximum threads that will service requests. */ public int getMaxThreads() { return Integer.parseInt(getHelpedParameters().getFirstValue( "maxThreads", "10")); } /** * Returns the minimum threads waiting to service requests. Technically * speaking, this is a core number of threads that are pre-started. * * @return The minimum threads waiting to service requests. */ public int getMinThreads() { return Integer.parseInt(getHelpedParameters().getFirstValue( "minThreads", "1")); } /** * Indicates if this service is acting in HTTP or HTTPS mode. * * @return True if this service is acting in HTTP or HTTPS mode. */ public boolean isConfidential() { return this.confidential; } /** * Sets the socket address this server is listening to. * * @param address * The socket address this server is listening to. */ protected void setAddress(InetSocketAddress address) { this.address = address; } /** * Indicates if this service is acting in HTTP or HTTPS mode. * * @param confidential * True if this service is acting in HTTP or HTTPS mode. */ protected void setConfidential(boolean confidential) { this.confidential = confidential; } @Override public synchronized void start() throws Exception { super.start(); getLogger().info( "Starting the internal " + getProtocols() + " server on port " + getHelped().getPort()); } @Override public synchronized void stop() throws Exception { getLogger().info("Stopping the internal server"); } }