1 // ======================================================================== 2 // Copyright (c) 2009 Intalio, Inc. 3 // ------------------------------------------------------------------------ 4 // All rights reserved. This program and the accompanying materials 5 // are made available under the terms of the Eclipse Public License v1.0 6 // and Apache License v2.0 which accompanies this distribution. 7 // The Eclipse Public License is available at 8 // http://www.eclipse.org/legal/epl-v10.html 9 // The Apache License v2.0 is available at 10 // http://www.opensource.org/licenses/apache2.0.php 11 // You may elect to redistribute this code under either of these licenses. 12 // Contributors: 13 // Hugues Malphettes - initial API and implementation 14 // ======================================================================== 15 package org.eclipse.jetty.osgi.boot; 16 17 import java.util.Dictionary; 18 import java.util.Hashtable; 19 import java.util.Properties; 20 21 import org.eclipse.jetty.osgi.boot.internal.webapp.JettyContextHandlerExtender; 22 import org.eclipse.jetty.osgi.boot.internal.webapp.JettyContextHandlerServiceTracker; 23 import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker; 24 import org.eclipse.jetty.server.Server; 25 import org.eclipse.jetty.server.handler.ContextHandler; 26 import org.eclipse.jetty.webapp.WebAppContext; 27 import org.osgi.framework.Bundle; 28 import org.osgi.framework.BundleActivator; 29 import org.osgi.framework.BundleContext; 30 import org.osgi.framework.FrameworkUtil; 31 import org.osgi.framework.ServiceRegistration; 32 33 /** 34 * Experiment: bootstrap jetty's complete distrib from an OSGi bundle. Progress: 35 * <ol> 36 * <li>basic servlet [ok]</li> 37 * <li>basic jetty.xml [ok]</li> 38 * <li>basic jetty.xml and jetty-plus.xml [ok]</li> 39 * <li>basic jsp [ok with modifications] 40 * <ul> 41 * <li>Needed to modify the headers of jdt.core-3.1.1 so that its dependency on 42 * eclipse.runtime, eclipse.resources and eclipse.text are optional. Also we 43 * should depend on the latest jdt.core from eclipse-3.5 not from eclipse-3.1.1 44 * although that will require actual changes to jasper as some internal APIs of 45 * jdt.core have changed.</li> 46 * <li>Modifications to org.mortbay.jetty.jsp-2.1-glassfish: made all imports to 47 * ant, xalan and sun packages optional.</li> 48 * </ul> 49 * </li> 50 * <li>jsp with tag-libs [ok]</li> 51 * <li>test-jndi with atomikos and derby inside ${jetty.home}/lib/ext [ok]</li> 52 * </ul> 53 */ 54 public class JettyBootstrapActivator implements BundleActivator 55 { 56 57 private static JettyBootstrapActivator INSTANCE = null; 58 59 public static JettyBootstrapActivator getInstance() 60 { 61 return INSTANCE; 62 } 63 64 private ServiceRegistration _registeredServer; 65 private Server _server; 66 private JettyContextHandlerServiceTracker _jettyContextHandlerTracker; 67 private PackageAdminServiceTracker _packageAdminServiceTracker; 68 69 /** 70 * Setup a new jetty Server, registers it as a service. Setup the Service 71 * tracker for the jetty ContextHandlers that are in charge of deploying the 72 * webapps. Setup the BundleListener that supports the extender pattern for 73 * the jetty ContextHandler. 74 * 75 * @param context 76 */ 77 public void start(BundleContext context) throws Exception 78 { 79 INSTANCE = this; 80 81 // track other bundles and fragments attached to this bundle that we 82 // should activate. 83 _packageAdminServiceTracker = new PackageAdminServiceTracker(context); 84 85 // todo: replace all this by the ManagedFactory so that we can start 86 // multiple jetty servers. 87 _server = new Server(); 88 // expose the server as a service. 89 _registeredServer = context.registerService(_server.getClass().getName(),_server,new Properties()); 90 // the tracker in charge of the actual deployment 91 // and that will configure and start the jetty server. 92 _jettyContextHandlerTracker = new JettyContextHandlerServiceTracker(context,_server); 93 94 // TODO: add a couple more checks on the properties? 95 // kind of nice not to so we can debug what is missing easily. 96 context.addServiceListener(_jettyContextHandlerTracker,"(objectclass=" + ContextHandler.class.getName() + ")"); 97 98 // now ready to support the Extender pattern: 99 JettyContextHandlerExtender jettyContexHandlerExtender = new JettyContextHandlerExtender(); 100 context.addBundleListener(jettyContexHandlerExtender); 101 102 jettyContexHandlerExtender.init(context); 103 104 } 105 106 /* 107 * (non-Javadoc) 108 * 109 * @see 110 * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) 111 */ 112 public void stop(BundleContext context) throws Exception 113 { 114 try 115 { 116 if (_jettyContextHandlerTracker != null) 117 { 118 _jettyContextHandlerTracker.stop(); 119 context.removeServiceListener(_jettyContextHandlerTracker); 120 } 121 if (_packageAdminServiceTracker != null) 122 { 123 _packageAdminServiceTracker.stop(); 124 context.removeServiceListener(_packageAdminServiceTracker); 125 } 126 if (_registeredServer != null) 127 { 128 try 129 { 130 _registeredServer.unregister(); 131 _registeredServer = null; 132 } 133 catch (IllegalArgumentException ill) 134 { 135 // already unregistered. 136 } 137 } 138 } 139 finally 140 { 141 _server.stop(); 142 INSTANCE = null; 143 } 144 } 145 146 /** 147 * Helper method that creates a new org.jetty.webapp.WebAppContext and 148 * registers it as an OSGi service. The tracker 149 * {@link JettyContextHandlerServiceTracker} will do the actual deployment. 150 * 151 * @param context 152 * The current bundle context 153 * @param webappFolderPath 154 * The path to the root of the webapp. Must be a path relative to 155 * bundle; either an absolute path. 156 * @param contextPath 157 * The context path. Must start with "/" 158 * @throws Exception 159 */ 160 public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath) throws Exception 161 { 162 WebAppContext contextHandler = new WebAppContext(); 163 Properties dic = new Properties(); 164 dic.put(OSGiWebappConstants.SERVICE_PROP_WAR,webappFolderPath); 165 dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH,contextPath); 166 contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic); 167 } 168 169 /** 170 * Helper method that creates a new org.jetty.webapp.WebAppContext and 171 * registers it as an OSGi service. The tracker 172 * {@link JettyContextHandlerServiceTracker} will do the actual deployment. 173 * 174 * @param context 175 * The current bundle context 176 * @param webappFolderPath 177 * The path to the root of the webapp. Must be a path relative to 178 * bundle; either an absolute path. 179 * @param contextPath 180 * The context path. Must start with "/" 181 * @param thisBundleInstallationOverride 182 * The location to a folder where the context file is located 183 * This overrides the default behavior that consists of using the 184 * location where the bundle is installed. Useful when in fact 185 * the webapp contributed is not inside a bundle. 186 * @throws Exception 187 */ 188 public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath, Dictionary<String, String> dic) throws Exception 189 { 190 WebAppContext contextHandler = new WebAppContext(); 191 dic.put(OSGiWebappConstants.SERVICE_PROP_WAR,webappFolderPath); 192 dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH,contextPath); 193 contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic); 194 } 195 196 /** 197 * Helper method that creates a new skeleton of a ContextHandler and 198 * registers it as an OSGi service. The tracker 199 * {@link JettyContextHandlerServiceTracker} will do the actual deployment. 200 * 201 * @param contributor 202 * The bundle that registers a new context 203 * @param contextFilePath 204 * The path to the file inside the bundle that defines the 205 * context. 206 * @throws Exception 207 */ 208 public static void registerContext(Bundle contributor, String contextFilePath) throws Exception 209 { 210 registerContext(contributor,contextFilePath,new Hashtable<String, String>()); 211 } 212 213 /** 214 * Helper method that creates a new skeleton of a ContextHandler and 215 * registers it as an OSGi service. The tracker 216 * {@link JettyContextHandlerServiceTracker} will do the actual deployment. 217 * 218 * @param contributor 219 * The bundle that registers a new context 220 * @param contextFilePath 221 * The path to the file inside the bundle that defines the 222 * context. 223 * @param thisBundleInstallationOverride 224 * The location to a folder where the context file is located 225 * This overrides the default behavior that consists of using the 226 * location where the bundle is installed. Useful when in fact 227 * the webapp contributed is not inside a bundle. 228 * @throws Exception 229 */ 230 public static void registerContext(Bundle contributor, String contextFilePath, Dictionary<String, String> dic) throws Exception 231 { 232 ContextHandler contextHandler = new ContextHandler(); 233 dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH,contextFilePath); 234 contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic); 235 } 236 237 public static void unregister(String contextPath) 238 { 239 // todo 240 } 241 242 }