// ======================================================================== // Copyright (c) 2009 Intalio, Inc. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // You may elect to redistribute this code under either of these licenses. // Contributors: // Hugues Malphettes - initial API and implementation // ======================================================================== package org.eclipse.jetty.osgi.boot; import java.util.Dictionary; import java.util.Hashtable; import org.eclipse.jetty.osgi.boot.internal.serverfactory.DefaultJettyAtJettyHomeHelper; import org.eclipse.jetty.osgi.boot.internal.serverfactory.JettyServerServiceTracker; import org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper; import org.eclipse.jetty.osgi.boot.internal.webapp.JettyContextHandlerServiceTracker; import org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleTrackerCustomizer; import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.handler.ContextHandler; import org.eclipse.jetty.webapp.WebAppContext; import org.osgi.framework.Bundle; import org.osgi.framework.BundleActivator; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; import org.osgi.framework.FrameworkUtil; import org.osgi.framework.ServiceRegistration; import org.osgi.util.tracker.BundleTracker; /** * Experiment: bootstrap jetty's complete distrib from an OSGi bundle. Progress: * <ol> * <li>basic servlet [ok]</li> * <li>basic jetty.xml [ok]</li> * <li>basic jetty.xml and jetty-plus.xml [ok]</li> * <li>basic jsp [ok with modifications] * <ul> * <li>Needed to modify the headers of jdt.core-3.1.1 so that its dependency on * eclipse.runtime, eclipse.resources and eclipse.text are optional. Also we * should depend on the latest jdt.core from eclipse-3.5 not from eclipse-3.1.1 * although that will require actual changes to jasper as some internal APIs of * jdt.core have changed.</li> * <li>Modifications to org.mortbay.jetty.jsp-2.1-glassfish: made all imports to * ant, xalan and sun packages optional.</li> * </ul> * </li> * <li>jsp with tag-libs [ok]</li> * <li>test-jndi with atomikos and derby inside ${jetty.home}/lib/ext [ok]</li> * </ul> */ public class JettyBootstrapActivator implements BundleActivator { private static JettyBootstrapActivator INSTANCE = null; public static JettyBootstrapActivator getInstance() { return INSTANCE; } private ServiceRegistration _registeredServer; private Server _server; private JettyContextHandlerServiceTracker _jettyContextHandlerTracker; private PackageAdminServiceTracker _packageAdminServiceTracker; private BundleTracker _webBundleTracker; private BundleContext _bundleContext; // private ServiceRegistration _jettyServerFactoryService; private JettyServerServiceTracker _jettyServerServiceTracker; /** * Setup a new jetty Server, registers it as a service. Setup the Service * tracker for the jetty ContextHandlers that are in charge of deploying the * webapps. Setup the BundleListener that supports the extender pattern for * the jetty ContextHandler. * * @param context */ public void start(BundleContext context) throws Exception { INSTANCE = this; _bundleContext = context; // track other bundles and fragments attached to this bundle that we // should activate. _packageAdminServiceTracker = new PackageAdminServiceTracker(context); _jettyServerServiceTracker = new JettyServerServiceTracker(); context.addServiceListener(_jettyServerServiceTracker,"(objectclass=" + Server.class.getName() + ")"); //Register the Jetty Server Factory as a ManagedServiceFactory: // Properties jettyServerMgdFactoryServiceProps = new Properties(); // jettyServerMgdFactoryServiceProps.put("pid", OSGiWebappConstants.MANAGED_JETTY_SERVER_FACTORY_PID); // _jettyServerFactoryService = context.registerService( // ManagedServiceFactory.class.getName(), new JettyServersManagedFactory(), // jettyServerMgdFactoryServiceProps); _jettyContextHandlerTracker = new JettyContextHandlerServiceTracker(_jettyServerServiceTracker); // the tracker in charge of the actual deployment // and that will configure and start the jetty server. context.addServiceListener(_jettyContextHandlerTracker,"(objectclass=" + ContextHandler.class.getName() + ")"); //see if we shoult start a default jetty instance right now. DefaultJettyAtJettyHomeHelper.startJettyAtJettyHome(context); // now ready to support the Extender pattern: _webBundleTracker = new BundleTracker(context, Bundle.ACTIVE | Bundle.STOPPING, new WebBundleTrackerCustomizer()); _webBundleTracker.open(); } /* * (non-Javadoc) * * @see * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) */ public void stop(BundleContext context) throws Exception { try { if (_webBundleTracker != null) { _webBundleTracker.close(); _webBundleTracker = null; } if (_jettyContextHandlerTracker != null) { _jettyContextHandlerTracker.stop(); context.removeServiceListener(_jettyContextHandlerTracker); _jettyContextHandlerTracker = null; } if (_jettyServerServiceTracker != null) { _jettyServerServiceTracker.stop(); context.removeServiceListener(_jettyServerServiceTracker); _jettyServerServiceTracker = null; } if (_packageAdminServiceTracker != null) { _packageAdminServiceTracker.stop(); context.removeServiceListener(_packageAdminServiceTracker); _packageAdminServiceTracker = null; } if (_registeredServer != null) { try { _registeredServer.unregister(); } catch (IllegalArgumentException ill) { // already unregistered. } finally { _registeredServer = null; } } // if (_jettyServerFactoryService != null) // { // try // { // _jettyServerFactoryService.unregister(); // } // catch (IllegalArgumentException ill) // { // // already unregistered. // } // finally // { // _jettyServerFactoryService = null; // } // } } finally { if (_server != null) { _server.stop(); } INSTANCE = null; } } /** * Helper method that creates a new org.jetty.webapp.WebAppContext and * registers it as an OSGi service. The tracker * {@link JettyContextHandlerServiceTracker} will do the actual deployment. * * @param contributor * The bundle * @param webappFolderPath * The path to the root of the webapp. Must be a path relative to * bundle; either an absolute path. * @param contextPath * The context path. Must start with "/" * @throws Exception */ public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath) throws Exception { checkBundleActivated(); WebAppContext contextHandler = new WebAppContext(); Dictionary dic = new Hashtable(); dic.put(OSGiWebappConstants.SERVICE_PROP_WAR,webappFolderPath); dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH,contextPath); String requireTldBundle = (String)contributor.getHeaders().get(OSGiWebappConstants.REQUIRE_TLD_BUNDLE); if (requireTldBundle != null) { dic.put(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE, requireTldBundle); } contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic); } /** * Helper method that creates a new org.jetty.webapp.WebAppContext and * registers it as an OSGi service. The tracker * {@link JettyContextHandlerServiceTracker} will do the actual deployment. * * @param contributor * The bundle * @param webappFolderPath * The path to the root of the webapp. Must be a path relative to * bundle; either an absolute path. * @param contextPath * The context path. Must start with "/" * @param dic * TODO: parameter description * @throws Exception */ public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath, Dictionary<String, String> dic) throws Exception { checkBundleActivated(); WebAppContext contextHandler = new WebAppContext(); dic.put(OSGiWebappConstants.SERVICE_PROP_WAR,webappFolderPath); dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH,contextPath); contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic); } /** * Helper method that creates a new skeleton of a ContextHandler and * registers it as an OSGi service. The tracker * {@link JettyContextHandlerServiceTracker} will do the actual deployment. * * @param contributor * The bundle that registers a new context * @param contextFilePath * The path to the file inside the bundle that defines the * context. * @throws Exception */ public static void registerContext(Bundle contributor, String contextFilePath) throws Exception { registerContext(contributor,contextFilePath,new Hashtable<String, String>()); } /** * Helper method that creates a new skeleton of a ContextHandler and * registers it as an OSGi service. The tracker * {@link JettyContextHandlerServiceTracker} will do the actual deployment. * * @param contributor * The bundle that registers a new context * @param contextFilePath * The path to the file inside the bundle that defines the * context. * @param dic * TODO: parameter description * @throws Exception */ public static void registerContext(Bundle contributor, String contextFilePath, Dictionary<String, String> dic) throws Exception { checkBundleActivated(); ContextHandler contextHandler = new ContextHandler(); dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH,contextFilePath); dic.put(IWebBundleDeployerHelper.INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE,Boolean.TRUE.toString()); contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic); } public static void unregister(String contextPath) { // todo } /** * Since org.eclipse.jetty.osgi.boot does not have a lazy activation policy * when one fo the static methods to register a webapp is called we should make sure that * the bundle is started. */ private static void checkBundleActivated() { if (INSTANCE == null) { Bundle thisBundle = FrameworkUtil.getBundle(JettyBootstrapActivator.class); try { thisBundle.start(); } catch (BundleException e) { // nevermind. } } } /** * @return The bundle context for this bundle. */ public static BundleContext getBundleContext() { checkBundleActivated(); return INSTANCE._bundleContext; } }