Initial attempt at moving over Oscar's Jetty-based HTTP Service implementation
(FELIX-9).
git-svn-id: https://svn.apache.org/repos/asf/incubator/felix/trunk@395268 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/org.apache.felix.http.jetty/src/main/java/org/apache/felix/http/jetty/Activator.java b/org.apache.felix.http.jetty/src/main/java/org/apache/felix/http/jetty/Activator.java
new file mode 100644
index 0000000..76467cd
--- /dev/null
+++ b/org.apache.felix.http.jetty/src/main/java/org/apache/felix/http/jetty/Activator.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+package org.apache.felix.http.jetty;
+
+import java.lang.reflect.Constructor;
+
+import org.mortbay.http.HashUserRealm;
+import org.mortbay.http.HttpServer;
+import org.mortbay.http.SocketListener;
+import org.mortbay.util.Code;
+import org.mortbay.util.InetAddrPort;
+import org.osgi.framework.*;
+import org.osgi.service.http.HttpService;
+import org.mortbay.http.SunJsseListener;
+import org.mortbay.http.JsseListener;
+
+/**
+ * Basic implementation of OSGi HTTP service 1.1.
+ *
+ * TODO:
+ *
+ * - fuller suite of testing and compatibility tests
+ *
+ * - only exposed params are those defined in the OSGi spec. Jetty is
+ * very tunable via params, some of which it may be useful to expose
+ *
+ * - no cacheing is performed on delivered resources. Although not part
+ * of the OSGi spec, it also isn't precluded and would enhance
+ * performance in a high usage environment. Jetty's ResourceHandler
+ * class could be a model for this.
+ *
+ * - scanning the Jetty ResourceHandler class it's clear that there are
+ * many other sophisticated areas to do with resource handling such
+ * as checking date and range fields in the http headers. It's not clear
+ * whether any of these play a part in the OSGi service - the spec
+ * just describes "returning the contents of the URL to the client" which
+ * doesn't state what other HTTP handling might be compliant or desirable
+ */
+public class Activator implements BundleActivator
+{
+ protected static boolean debug = false;
+
+ private BundleContext m_bundleContext = null;
+ private ServiceRegistration m_svcReg = null;
+ private HttpServiceFactory m_httpServ = null;
+ private HttpServer m_server = null;
+
+ private int m_httpPort;
+ private int m_httpsPort;
+
+
+ public void start(BundleContext bundleContext)
+ throws BundleException
+ {
+ m_bundleContext = bundleContext;
+
+ // org.mortbay.util.Loader needs this (used for JDK 1.4 log classes)
+ Thread.currentThread().setContextClassLoader(
+ this.getClass().getClassLoader());
+
+ String optDebug =
+ m_bundleContext.getProperty("org.apache.felix.http.jetty.debug");
+ if (optDebug != null && optDebug.toLowerCase().equals("true"))
+ {
+ Code.setDebug(true);
+ debug = true;
+ }
+
+ // get default HTTP and HTTPS ports as per the OSGi spec
+ try
+ {
+ m_httpPort = Integer.parseInt(m_bundleContext.getProperty(
+ "org.osgi.service.http.port"));
+ }
+ catch (Exception e)
+ {
+ // maybe log a message saying using default?
+ m_httpPort = 80;
+ }
+
+ try
+ {
+ // TODO: work out how/when we should use the HTTPS port
+ m_httpsPort = Integer.parseInt(m_bundleContext.getProperty(
+ "org.osgi.service.http.port.secure"));
+ }
+ catch (Exception e)
+ {
+ // maybe log a message saying using default?
+ m_httpsPort = 443;
+ }
+
+ try
+ {
+ initializeJetty();
+
+ } catch (Exception ex) {
+ //TODO: maybe throw a bundle exception in here?
+ System.out.println("Http2: " + ex);
+ return;
+ }
+
+ m_httpServ = new HttpServiceFactory();
+ m_svcReg = m_bundleContext.registerService(
+ HttpService.class.getName(), m_httpServ, null);
+ }
+
+
+ public void stop(BundleContext bundleContext)
+ throws BundleException
+ {
+ //TODO: wonder if we need to closedown service factory ???
+
+ if (m_svcReg != null)
+ {
+ m_svcReg.unregister();
+ }
+
+ try
+ {
+ m_server.stop();
+ }
+ catch (Exception e)
+ {
+ //TODO: log some form of error
+ }
+ }
+
+ protected void initializeJetty()
+ throws Exception
+ {
+ //TODO: Maybe create a separate "JettyServer" object here?
+ // Realm
+ HashUserRealm realm =
+ new HashUserRealm("OSGi HTTP Service Realm");
+
+ // Create server
+ m_server = new HttpServer();
+ m_server.addRealm(realm);
+
+ // Add a regular HTTP listener
+ SocketListener listener = null;
+ listener = (SocketListener)
+ m_server.addListener(new InetAddrPort(m_httpPort));
+ listener.setMaxIdleTimeMs(60000);
+
+ // See if we need to add an HTTPS listener
+ String enableHTTPS = m_bundleContext.getProperty("org.ungoverned.osgi.bundle.https.enable");
+ if (enableHTTPS != null && enableHTTPS.toLowerCase().equals("true"))
+ {
+ initializeHTTPS();
+ }
+
+ m_server.start();
+ }
+
+ //TODO: Just a basic implementation to give us a working HTTPS port. A better
+ // long-term solution may be to separate out the SSL provider handling,
+ // keystore, passwords etc. into it's own pluggable service
+ protected void initializeHTTPS()
+ throws Exception
+ {
+ String sslProvider = m_bundleContext.getProperty("org.ungoverned.osgi.bundle.https.provider");
+ if (sslProvider == null)
+ {
+ sslProvider = "org.mortbay.http.SunJsseListener";
+ }
+
+ // Set default jetty properties for supplied values. For any not set,
+ // Jetty will fallback to checking system properties.
+ String keystore = m_bundleContext.getProperty("org.ungoverned.osgi.bundle.https.keystore");
+ if (keystore != null)
+ {
+ System.setProperty(JsseListener.KEYSTORE_PROPERTY, keystore);
+ }
+
+ String passwd = m_bundleContext.getProperty("org.ungoverned.osgi.bundle.https.password");
+ if (passwd != null)
+ {
+ System.setProperty(JsseListener.PASSWORD_PROPERTY, passwd);
+ }
+
+ String keyPasswd = m_bundleContext.getProperty("org.ungoverned.osgi.bundle.https.key.password");
+ if (keyPasswd != null)
+ {
+ System.setProperty(JsseListener.KEYPASSWORD_PROPERTY, keyPasswd);
+ }
+
+ //SunJsseListener s_listener = new SunJsseListener(new InetAddrPort(m_httpsPort));
+ Object args[] = { new InetAddrPort(m_httpsPort) };
+ Class argTypes[] = { args[0].getClass() };
+ Class clazz = Class.forName(sslProvider);
+ Constructor cstruct = clazz.getDeclaredConstructor(argTypes);
+ JsseListener s_listener = (JsseListener) cstruct.newInstance(args);
+
+ m_server.addListener(s_listener);
+ s_listener.setMaxIdleTimeMs(60000);
+ }
+
+
+ protected static void debug(String txt)
+ {
+ if (debug)
+ {
+ System.err.println(">>Oscar HTTP: " + txt);
+ }
+ }
+
+ // Inner class to provide basic service factory functionality
+
+ public class HttpServiceFactory implements ServiceFactory
+ {
+ public HttpServiceFactory()
+ {
+ // Initialize the statics for the service implementation.
+ HttpServiceImpl.initializeStatics();
+ }
+
+ public Object getService(Bundle bundle,
+ ServiceRegistration registration)
+ {
+ Object srv = new HttpServiceImpl(bundle, m_server);
+ debug("** http service get:" + bundle + ", service: " + srv);
+ return srv;
+ }
+
+ public void ungetService(Bundle bundle,
+ ServiceRegistration registration, Object service)
+ {
+ debug("** http service unget:" + bundle + ", service: "
+ + service);
+ ((HttpServiceImpl) service).unregisterAll();
+ }
+ }
+
+}
\ No newline at end of file