/* * Copyright (c) 2008, 2009, 2011, 2012, 2016 Eike Stepper (Berlin, Germany) 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: * Eike Stepper - initial API and implementation */ package org.eclipse.net4j.http.internal.server; import org.eclipse.net4j.connector.IConnector; import org.eclipse.net4j.http.common.IHTTPConnector; import org.eclipse.net4j.http.internal.common.HTTPConnector; import org.eclipse.net4j.http.internal.server.bundle.OM; import org.eclipse.net4j.http.internal.server.messages.Messages; import org.eclipse.net4j.http.server.IHTTPAcceptor; import org.eclipse.net4j.http.server.INet4jTransportServlet; import org.eclipse.net4j.util.StringUtil; import org.eclipse.net4j.util.concurrent.Worker; import org.eclipse.net4j.util.io.ExtendedDataInputStream; import org.eclipse.net4j.util.io.ExtendedDataOutputStream; import org.eclipse.net4j.util.lifecycle.LifecycleUtil; import org.eclipse.net4j.util.om.log.OMLogger; import org.eclipse.net4j.util.om.trace.ContextTracer; import org.eclipse.net4j.util.security.IRandomizer; import org.eclipse.spi.net4j.Acceptor; import org.eclipse.spi.net4j.InternalConnector; import java.io.IOException; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; /** * @author Eike Stepper */ public class HTTPAcceptor extends Acceptor implements IHTTPAcceptor, INet4jTransportServlet.RequestHandler { public static final int DEFAULT_CONNECTOR_ID_LENGTH = 32; public static final int DEFAULT_MAX_IDLE_TIME = 30 * 60 * 1000; // 30 minutes private static final ContextTracer TRACER = new ContextTracer(OM.DEBUG, HTTPAcceptor.class); private IRandomizer randomizer; private INet4jTransportServlet servlet; private int connectorIDLength = DEFAULT_CONNECTOR_ID_LENGTH; private int maxIdleTime = DEFAULT_MAX_IDLE_TIME; private Map<String, HTTPServerConnector> httpConnectors = new HashMap<String, HTTPServerConnector>(); private Worker cleaner = new Worker() { @Override protected void work(WorkContext context) throws Exception { int pause = cleanIdleConnectors(); context.nextWork(pause); } @Override protected String getThreadName() { return "HTTPAcceptorCleaner"; } }; public HTTPAcceptor() { } public IRandomizer getRandomizer() { return randomizer; } public void setRandomizer(IRandomizer randomizer) { this.randomizer = randomizer; } public INet4jTransportServlet getServlet() { return servlet; } public void setServlet(INet4jTransportServlet servlet) { if (this.servlet != null) { this.servlet.setRequestHandler(null); } this.servlet = servlet; if (this.servlet != null) { this.servlet.setRequestHandler(this); } } public int getConnectorIDLength() { return connectorIDLength; } public void setConnectorIDLength(int connectorIDLength) { this.connectorIDLength = connectorIDLength; } public int getMaxIdleTime() { return maxIdleTime; } public void setMaxIdleTime(int maxIdleTime) { this.maxIdleTime = maxIdleTime; } public IHTTPConnector[] getHTTPConnectors() { List<IHTTPConnector> result = new ArrayList<IHTTPConnector>(); for (IConnector acceptedConnector : getAcceptedConnectors()) { IHTTPConnector connector = (IHTTPConnector)acceptedConnector; result.add(connector); } return result.toArray(new IHTTPConnector[result.size()]); } public IHTTPConnector[] handleList(String connectorID) { if (StringUtil.isEmpty(connectorID)) { return getHTTPConnectors(); } return new IHTTPConnector[] { httpConnectors.get(connectorID) }; } public IHTTPConnector handleConnect(String userID) { String connectorID = createConnectorID(userID); HTTPServerConnector connector = createServerConnector(); prepareConnector(connector); connector.setConnectorID(connectorID); connector.setUserID(userID); addConnector(connector); connector.activate(); return connector; } public void handleDisonnect(String connectorID) { HTTPConnector connector = httpConnectors.get(connectorID); if (connector == null) { throw new IllegalArgumentException("Invalid connectorID: " + connectorID); //$NON-NLS-1$ } connector.deactivate(); } public void handleOperations(String connectorID, ExtendedDataInputStream in, ExtendedDataOutputStream out) throws IOException { HTTPServerConnector connector = httpConnectors.get(connectorID); if (connector == null) { throw new IllegalArgumentException("Invalid connectorID: " + connectorID); //$NON-NLS-1$ } connector.readInputOperations(in); connector.writeOutputOperations(out); } @Override public String toString() { return "HTTPAcceptor"; //$NON-NLS-1$ } @Override public void addConnector(InternalConnector connector) { super.addConnector(connector); HTTPServerConnector httpConnector = (HTTPServerConnector)connector; httpConnectors.put(httpConnector.getConnectorID(), httpConnector); } @Override public void removeConnector(IConnector connector) { HTTPConnector httpConnector = (HTTPConnector)connector; httpConnectors.remove(httpConnector.getConnectorID()); super.removeConnector(connector); } @Override protected void doBeforeActivate() throws Exception { super.doBeforeActivate(); checkState(randomizer, "randomizer"); //$NON-NLS-1$ checkState(connectorIDLength > 0, "Constraint violated: connectorIDLength > 0"); //$NON-NLS-1$ checkState(maxIdleTime >= 100, "Constraint violated: maxIdleTime >= 100"); //$NON-NLS-1$ } @Override protected void doActivate() throws Exception { super.doActivate(); cleaner.setDaemon(true); cleaner.activate(); } @Override protected void doDeactivate() throws Exception { LifecycleUtil.deactivate(cleaner, OMLogger.Level.WARN); super.doDeactivate(); } protected String createConnectorID(String userID) { return randomizer.nextString(connectorIDLength, "0123456789ABCDEF"); //$NON-NLS-1$ } protected HTTPServerConnector createServerConnector() { return new HTTPServerConnector(this); } protected int cleanIdleConnectors() { long now = System.currentTimeMillis(); IConnector[] connectors = getAcceptedConnectors(); if (TRACER.isEnabled()) { TRACER.format("Checking {0} HTTP server connectors for idle time: {1,time}", connectors.length, new Date()); //$NON-NLS-1$ } for (IConnector connector : connectors) { HTTPServerConnector serverConnector = (HTTPServerConnector)connector; long lastTraffic = serverConnector.getLastTraffic(); long idleTime = now - lastTraffic; if (idleTime > maxIdleTime) { serverConnector.deactivate(); OM.LOG.info(Messages.getString("HTTPAcceptor.8") + serverConnector); //$NON-NLS-1$ } } return maxIdleTime; } }