View Javadoc

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 }