blob: 20bd058543be4d0113df25d134e573b4e1e76a35 [file] [log] [blame]
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +00001/*
Richard S. Hall435c20c2006-09-28 20:11:35 +00002 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
Richard S. Hallfe8e5602006-04-19 15:23:22 +00009 *
Richard S. Hall435c20c2006-09-28 20:11:35 +000010 * http://www.apache.org/licenses/LICENSE-2.0
Richard S. Hallfe8e5602006-04-19 15:23:22 +000011 *
Richard S. Hall435c20c2006-09-28 20:11:35 +000012 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
Richard S. Hallfe8e5602006-04-19 15:23:22 +000018 */
19package org.apache.felix.http.jetty;
20
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +000021
Richard S. Hallfe8e5602006-04-19 15:23:22 +000022import java.lang.reflect.Constructor;
23
24import org.mortbay.http.HashUserRealm;
25import org.mortbay.http.HttpServer;
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +000026import org.mortbay.http.JsseListener;
Richard S. Hallfe8e5602006-04-19 15:23:22 +000027import org.mortbay.http.SocketListener;
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +000028import org.mortbay.jetty.servlet.OsgiServletHandler;
29import org.mortbay.jetty.servlet.ServletHttpContext;
Richard S. Hallfe8e5602006-04-19 15:23:22 +000030import org.mortbay.util.Code;
31import org.mortbay.util.InetAddrPort;
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +000032import org.osgi.framework.Bundle;
33import org.osgi.framework.BundleActivator;
34import org.osgi.framework.BundleContext;
35import org.osgi.framework.BundleException;
36import org.osgi.framework.ServiceFactory;
37import org.osgi.framework.ServiceRegistration;
Richard S. Hallfe8e5602006-04-19 15:23:22 +000038import org.osgi.service.http.HttpService;
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +000039
Richard S. Hallfe8e5602006-04-19 15:23:22 +000040
41/**
42 * Basic implementation of OSGi HTTP service 1.1.
43 *
44 * TODO:
45 *
46 * - fuller suite of testing and compatibility tests
47 *
48 * - only exposed params are those defined in the OSGi spec. Jetty is
49 * very tunable via params, some of which it may be useful to expose
50 *
51 * - no cacheing is performed on delivered resources. Although not part
52 * of the OSGi spec, it also isn't precluded and would enhance
53 * performance in a high usage environment. Jetty's ResourceHandler
54 * class could be a model for this.
55 *
56 * - scanning the Jetty ResourceHandler class it's clear that there are
57 * many other sophisticated areas to do with resource handling such
58 * as checking date and range fields in the http headers. It's not clear
59 * whether any of these play a part in the OSGi service - the spec
60 * just describes "returning the contents of the URL to the client" which
61 * doesn't state what other HTTP handling might be compliant or desirable
62 */
63public class Activator implements BundleActivator
64{
65 protected static boolean debug = false;
66
67 private BundleContext m_bundleContext = null;
68 private ServiceRegistration m_svcReg = null;
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +000069 private HttpServiceFactory m_httpServ = null;
Richard S. Hallfe8e5602006-04-19 15:23:22 +000070 private HttpServer m_server = null;
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +000071 private OsgiServletHandler m_hdlr = null;
Richard S. Hallfe8e5602006-04-19 15:23:22 +000072
73 private int m_httpPort;
74 private int m_httpsPort;
75
76
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +000077 public void start( BundleContext bundleContext ) throws BundleException
Richard S. Hallfe8e5602006-04-19 15:23:22 +000078 {
79 m_bundleContext = bundleContext;
80
81 // org.mortbay.util.Loader needs this (used for JDK 1.4 log classes)
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +000082 Thread.currentThread().setContextClassLoader( this.getClass().getClassLoader() );
83
84 String optDebug = m_bundleContext.getProperty( "org.apache.felix.http.jetty.debug" );
85 if ( optDebug != null && optDebug.toLowerCase().equals( "true" ) )
Richard S. Hallfe8e5602006-04-19 15:23:22 +000086 {
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +000087 Code.setDebug( true );
Richard S. Hallfe8e5602006-04-19 15:23:22 +000088 debug = true;
89 }
90
91 // get default HTTP and HTTPS ports as per the OSGi spec
92 try
93 {
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +000094 m_httpPort = Integer.parseInt( m_bundleContext.getProperty( "org.osgi.service.http.port" ) );
Richard S. Hallfe8e5602006-04-19 15:23:22 +000095 }
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +000096 catch ( Exception e )
Richard S. Hallfe8e5602006-04-19 15:23:22 +000097 {
98 // maybe log a message saying using default?
99 m_httpPort = 80;
100 }
101
102 try
103 {
104 // TODO: work out how/when we should use the HTTPS port
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000105 m_httpsPort = Integer.parseInt( m_bundleContext.getProperty( "org.osgi.service.http.port.secure" ) );
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000106 }
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000107 catch ( Exception e )
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000108 {
109 // maybe log a message saying using default?
110 m_httpsPort = 443;
111 }
112
113 try
114 {
115 initializeJetty();
116
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000117 }
118 catch ( Exception ex )
119 {
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000120 //TODO: maybe throw a bundle exception in here?
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000121 System.out.println( "Http2: " + ex );
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000122 return;
123 }
124
125 m_httpServ = new HttpServiceFactory();
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000126 m_svcReg = m_bundleContext.registerService( HttpService.class.getName(), m_httpServ, null );
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000127 }
128
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000129
130 public void stop( BundleContext bundleContext ) throws BundleException
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000131 {
132 //TODO: wonder if we need to closedown service factory ???
133
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000134 if ( m_svcReg != null )
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000135 {
136 m_svcReg.unregister();
137 }
138
139 try
140 {
141 m_server.stop();
142 }
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000143 catch ( Exception e )
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000144 {
145 //TODO: log some form of error
146 }
147 }
148
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000149
150 protected void initializeJetty() throws Exception
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000151 {
152 //TODO: Maybe create a separate "JettyServer" object here?
153 // Realm
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000154 HashUserRealm realm = new HashUserRealm( "OSGi HTTP Service Realm" );
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000155
156 // Create server
157 m_server = new HttpServer();
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000158 m_server.addRealm( realm );
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000159
160 // Add a regular HTTP listener
161 SocketListener listener = null;
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000162 listener = ( SocketListener ) m_server.addListener( new InetAddrPort( m_httpPort ) );
163 listener.setMaxIdleTimeMs( 60000 );
164
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000165 // See if we need to add an HTTPS listener
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000166 String enableHTTPS = m_bundleContext.getProperty( "org.ungoverned.osgi.bundle.https.enable" );
167 if ( enableHTTPS != null && enableHTTPS.toLowerCase().equals( "true" ) )
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000168 {
169 initializeHTTPS();
170 }
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000171
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000172 m_server.start();
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000173
174 // setup the Jetty web application context shared by all Http services
175 ServletHttpContext hdlrContext = new ServletHttpContext();
176 hdlrContext.setContextPath( "/" );
177 //TODO: was in original code, but seems we shouldn't serve
178 // resources in servlet context
179 //hdlrContext.setServingResources(true);
180 hdlrContext.setClassLoader( getClass().getClassLoader() );
181 debug( " adding handler context : " + hdlrContext );
182 m_server.addContext( hdlrContext );
183
184 m_hdlr = new OsgiServletHandler();
185 hdlrContext.addHandler( m_hdlr );
186
187 try
188 {
189 hdlrContext.start();
190 }
191 catch ( Exception e )
192 {
193 // make sure we unwind the adding process
194 System.err.println( "Exception Starting Jetty Handler Context: " + e );
195 e.printStackTrace( System.err );
196 }
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000197 }
198
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000199
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000200 //TODO: Just a basic implementation to give us a working HTTPS port. A better
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000201 // long-term solution may be to separate out the SSL provider handling,
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000202 // keystore, passwords etc. into it's own pluggable service
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000203 protected void initializeHTTPS() throws Exception
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000204 {
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000205 String sslProvider = m_bundleContext.getProperty( "org.ungoverned.osgi.bundle.https.provider" );
206 if ( sslProvider == null )
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000207 {
208 sslProvider = "org.mortbay.http.SunJsseListener";
209 }
210
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000211 // Set default jetty properties for supplied values. For any not set,
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000212 // Jetty will fallback to checking system properties.
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000213 String keystore = m_bundleContext.getProperty( "org.ungoverned.osgi.bundle.https.keystore" );
214 if ( keystore != null )
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000215 {
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000216 System.setProperty( JsseListener.KEYSTORE_PROPERTY, keystore );
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000217 }
218
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000219 String passwd = m_bundleContext.getProperty( "org.ungoverned.osgi.bundle.https.password" );
220 if ( passwd != null )
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000221 {
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000222 System.setProperty( JsseListener.PASSWORD_PROPERTY, passwd );
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000223 }
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000224
225 String keyPasswd = m_bundleContext.getProperty( "org.ungoverned.osgi.bundle.https.key.password" );
226 if ( keyPasswd != null )
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000227 {
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000228 System.setProperty( JsseListener.KEYPASSWORD_PROPERTY, keyPasswd );
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000229 }
230
231 //SunJsseListener s_listener = new SunJsseListener(new InetAddrPort(m_httpsPort));
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000232 Object args[] =
233 { new InetAddrPort( m_httpsPort ) };
234 Class argTypes[] =
235 { args[0].getClass() };
236 Class clazz = Class.forName( sslProvider );
237 Constructor cstruct = clazz.getDeclaredConstructor( argTypes );
238 JsseListener s_listener = ( JsseListener ) cstruct.newInstance( args );
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000239
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000240 m_server.addListener( s_listener );
241 s_listener.setMaxIdleTimeMs( 60000 );
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000242 }
243
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000244
245 protected static void debug( String txt )
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000246 {
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000247 if ( debug )
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000248 {
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000249 System.err.println( ">>Oscar HTTP: " + txt );
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000250 }
251 }
252
253 // Inner class to provide basic service factory functionality
254
255 public class HttpServiceFactory implements ServiceFactory
256 {
257 public HttpServiceFactory()
258 {
259 // Initialize the statics for the service implementation.
260 HttpServiceImpl.initializeStatics();
261 }
262
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000263
264 public Object getService( Bundle bundle, ServiceRegistration registration )
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000265 {
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000266 Object srv = new HttpServiceImpl( bundle, m_server, m_hdlr );
267 debug( "** http service get:" + bundle + ", service: " + srv );
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000268 return srv;
269 }
270
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000271
272 public void ungetService( Bundle bundle, ServiceRegistration registration, Object service )
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000273 {
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000274 debug( "** http service unget:" + bundle + ", service: " + service );
275 ( ( HttpServiceImpl ) service ).unregisterAll();
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000276 }
277 }
Felix Meschbergerb76cfdb2007-09-28 14:13:22 +0000278
Richard S. Hallfe8e5602006-04-19 15:23:22 +0000279}