| /******************************************************************************* |
| * Copyright (c) 2008, 2015 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| package org.eclipse.help.internal.server; |
| |
| import java.util.Dictionary; |
| import java.util.Hashtable; |
| import java.util.logging.Level; |
| import java.util.logging.Logger; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.equinox.http.jetty.JettyConfigurator; |
| import org.eclipse.equinox.http.jetty.JettyConstants; |
| import org.eclipse.help.internal.base.BaseHelpSystem; |
| import org.eclipse.help.internal.base.HelpBasePlugin; |
| import org.eclipse.help.server.HelpServer; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleException; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.framework.ServiceReference; |
| |
| |
| public class JettyHelpServer extends HelpServer { |
| |
| private abstract class WorkerThread extends Thread { |
| private Throwable exception; |
| |
| public WorkerThread(String name) { |
| super(name); |
| } |
| |
| public synchronized void setException(Throwable status) { |
| this.exception = status; |
| } |
| |
| public synchronized Throwable getException() { |
| return exception; |
| } |
| } |
| |
| private final class StartServerThread extends WorkerThread { |
| |
| private final String webappName; |
| |
| public StartServerThread(String webappName) { |
| super("Start Help Server"); //$NON-NLS-1$ |
| this.webappName = webappName; |
| } |
| |
| @Override |
| public void run() { |
| try { |
| final Dictionary<String, Object> d = new Hashtable<>(); |
| final int SESSION_TIMEOUT_INTERVAL_IN_SECONDS = 30*60; // 30 minutes |
| configurePort(); |
| d.put("http.port", Integer.valueOf(getPortParameter())); //$NON-NLS-1$ |
| |
| // set the base URL |
| d.put("context.path", getContextPath()); //$NON-NLS-1$ |
| d.put("other.info", getOtherInfo()); //$NON-NLS-1$ |
| d.put(JettyConstants.CONTEXT_SESSIONINACTIVEINTERVAL, Integer.valueOf(SESSION_TIMEOUT_INTERVAL_IN_SECONDS)); |
| |
| // suppress Jetty INFO/DEBUG messages to stderr |
| Logger.getLogger("org.mortbay").setLevel(Level.WARNING); //$NON-NLS-1$ |
| |
| if (bindServerToHostname()) { |
| d.put("http.host", getHost()); //$NON-NLS-1$ |
| } |
| |
| JettyConfigurator.startServer(webappName, d); |
| } catch (Throwable t) { |
| setException(t); |
| } |
| } |
| } |
| |
| private final class StopServerThread extends WorkerThread { |
| |
| private final String webappName; |
| |
| public StopServerThread(String webappName) { |
| super("Stop Help Server"); //$NON-NLS-1$ |
| this.webappName = webappName; |
| } |
| |
| @Override |
| public void run() { |
| try { |
| JettyConfigurator.stopServer(webappName); |
| port = -1; |
| } catch (Throwable t) { |
| setException(t); |
| } |
| } |
| } |
| |
| |
| private String host; |
| protected int port = -1; |
| protected static final int AUTO_SELECT_JETTY_PORT = 0; |
| |
| @Override |
| public void start(final String webappName) throws Exception { |
| WorkerThread startRunnable = new StartServerThread(webappName); |
| execute(startRunnable); |
| checkBundle(); |
| } |
| |
| /* |
| * Ensures that the bundle with the specified name and the highest available |
| * version is started and reads the port number |
| */ |
| protected void checkBundle() throws InvalidSyntaxException, BundleException { |
| Bundle bundle = Platform.getBundle("org.eclipse.equinox.http.registry"); //$NON-NLS-1$ |
| if (bundle == null) { |
| throw new BundleException("org.eclipse.equinox.http.registry"); //$NON-NLS-1$ |
| } |
| if (bundle.getState() == Bundle.RESOLVED) { |
| bundle.start(Bundle.START_TRANSIENT); |
| } |
| if (port == -1) { |
| // Jetty selected a port number for us |
| ServiceReference<?>[] reference = bundle.getBundleContext().getServiceReferences("org.osgi.service.http.HttpService", "(other.info=" + getOtherInfo() + ')'); //$NON-NLS-1$ //$NON-NLS-2$ |
| Object assignedPort = reference[0].getProperty("http.port"); //$NON-NLS-1$ |
| port = Integer.parseInt((String)assignedPort); |
| } |
| } |
| |
| @Override |
| public void stop(final String webappName) throws CoreException { |
| try { |
| WorkerThread stopRunnable = new StopServerThread(webappName); |
| execute(stopRunnable); |
| } |
| catch (Exception e) { |
| HelpBasePlugin.logError("An error occured while stopping the help server", e); //$NON-NLS-1$ |
| } |
| } |
| |
| private void execute(WorkerThread runnable) throws Exception { |
| boolean interrupted = false; |
| Thread thread = runnable; |
| thread.setDaemon(true); |
| thread.start(); |
| while(true) { |
| try { |
| thread.join(); |
| break; |
| } catch (InterruptedException e) { |
| interrupted = true; |
| } |
| } |
| if (interrupted) |
| Thread.currentThread().interrupt(); |
| |
| Throwable t = runnable.getException(); |
| |
| if (t != null) { |
| if (t instanceof Exception) { |
| throw (Exception)t; |
| } |
| throw (Error) t; |
| } |
| } |
| |
| @Override |
| public int getPort() { |
| return port; |
| } |
| |
| private void configurePort() { |
| if (port == -1) { |
| String portCommandLineOverride = HelpBasePlugin.getBundleContext().getProperty("server_port"); //$NON-NLS-1$ |
| if (portCommandLineOverride != null && portCommandLineOverride.trim().length() > 0) { |
| try { |
| port = Integer.parseInt(portCommandLineOverride); |
| } |
| catch (NumberFormatException e) { |
| String msg = "Help server port specified in VM arguments is invalid (" + portCommandLineOverride + ")"; //$NON-NLS-1$ //$NON-NLS-2$ |
| HelpBasePlugin.logError(msg, e); |
| } |
| } |
| } |
| } |
| |
| /* |
| * Get the port number which will be passed to Jetty |
| */ |
| protected int getPortParameter() { |
| if (port == -1) { |
| return AUTO_SELECT_JETTY_PORT; |
| } |
| return port; |
| } |
| |
| @Override |
| public String getHost() { |
| if (host == null) { |
| String hostCommandLineOverride = HelpBasePlugin.getBundleContext().getProperty("server_host"); //$NON-NLS-1$ |
| if (hostCommandLineOverride != null && hostCommandLineOverride.trim().length() > 0) { |
| host = hostCommandLineOverride; |
| } |
| else { |
| host = "127.0.0.1"; //$NON-NLS-1$ |
| } |
| } |
| return host; |
| } |
| |
| protected String getOtherInfo() { |
| return "org.eclipse.help"; //$NON-NLS-1$ |
| } |
| |
| protected String getContextPath() { |
| return "/help"; //$NON-NLS-1$ |
| } |
| |
| public boolean bindServerToHostname() { |
| if (BaseHelpSystem.getMode() == BaseHelpSystem.MODE_WORKBENCH) { |
| return true; |
| } |
| String host = HelpBasePlugin.getBundleContext().getProperty("server_host"); //$NON-NLS-1$ |
| return host != null && host.trim().length() > 0; |
| } |
| |
| } |