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  
20  import org.eclipse.jetty.osgi.boot.internal.serverfactory.DefaultJettyAtJettyHomeHelper;
21  import org.eclipse.jetty.osgi.boot.internal.serverfactory.JettyServerServiceTracker;
22  import org.eclipse.jetty.osgi.boot.internal.webapp.IWebBundleDeployerHelper;
23  import org.eclipse.jetty.osgi.boot.internal.webapp.JettyContextHandlerServiceTracker;
24  import org.eclipse.jetty.osgi.boot.internal.webapp.WebBundleTrackerCustomizer;
25  import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
26  import org.eclipse.jetty.server.Server;
27  import org.eclipse.jetty.server.handler.ContextHandler;
28  import org.eclipse.jetty.webapp.WebAppContext;
29  import org.osgi.framework.Bundle;
30  import org.osgi.framework.BundleActivator;
31  import org.osgi.framework.BundleContext;
32  import org.osgi.framework.BundleException;
33  import org.osgi.framework.FrameworkUtil;
34  import org.osgi.framework.ServiceRegistration;
35  import org.osgi.util.tracker.BundleTracker;
36  
37  /**
38   * Experiment: bootstrap jetty's complete distrib from an OSGi bundle. Progress:
39   * <ol>
40   * <li>basic servlet [ok]</li>
41   * <li>basic jetty.xml [ok]</li>
42   * <li>basic jetty.xml and jetty-plus.xml [ok]</li>
43   * <li>basic jsp [ok with modifications]
44   * <ul>
45   * <li>Needed to modify the headers of jdt.core-3.1.1 so that its dependency on
46   * eclipse.runtime, eclipse.resources and eclipse.text are optional. Also we
47   * should depend on the latest jdt.core from eclipse-3.5 not from eclipse-3.1.1
48   * although that will require actual changes to jasper as some internal APIs of
49   * jdt.core have changed.</li>
50   * <li>Modifications to org.mortbay.jetty.jsp-2.1-glassfish: made all imports to
51   * ant, xalan and sun packages optional.</li>
52   * </ul>
53   * </li>
54   * <li>jsp with tag-libs [ok]</li>
55   * <li>test-jndi with atomikos and derby inside ${jetty.home}/lib/ext [ok]</li>
56   * </ul>
57   */
58  public class JettyBootstrapActivator implements BundleActivator
59  {
60  
61      private static JettyBootstrapActivator INSTANCE = null;
62  
63      public static JettyBootstrapActivator getInstance()
64      {
65          return INSTANCE;
66      }
67  
68      private ServiceRegistration _registeredServer;
69  
70      private Server _server;
71  
72      private JettyContextHandlerServiceTracker _jettyContextHandlerTracker;
73  
74      private PackageAdminServiceTracker _packageAdminServiceTracker;
75  
76      private BundleTracker _webBundleTracker;
77  
78      private BundleContext _bundleContext;
79  
80      // private ServiceRegistration _jettyServerFactoryService;
81      private JettyServerServiceTracker _jettyServerServiceTracker;
82  
83      /**
84       * Setup a new jetty Server, registers it as a service. Setup the Service
85       * tracker for the jetty ContextHandlers that are in charge of deploying the
86       * webapps. Setup the BundleListener that supports the extender pattern for
87       * the jetty ContextHandler.
88       * 
89       * @param context
90       */
91      public void start(BundleContext context) throws Exception
92      {
93          INSTANCE = this;
94          _bundleContext = context;
95  
96          // track other bundles and fragments attached to this bundle that we
97          // should activate.
98          _packageAdminServiceTracker = new PackageAdminServiceTracker(context);
99  
100         _jettyServerServiceTracker = new JettyServerServiceTracker();
101         context.addServiceListener(_jettyServerServiceTracker, "(objectclass=" + Server.class.getName() + ")");
102 
103         // Register the Jetty Server Factory as a ManagedServiceFactory:
104         // Properties jettyServerMgdFactoryServiceProps = new Properties();
105         // jettyServerMgdFactoryServiceProps.put("pid",
106         // OSGiWebappConstants.MANAGED_JETTY_SERVER_FACTORY_PID);
107         // _jettyServerFactoryService = context.registerService(
108         // ManagedServiceFactory.class.getName(), new
109         // JettyServersManagedFactory(),
110         // jettyServerMgdFactoryServiceProps);
111 
112         _jettyContextHandlerTracker = new JettyContextHandlerServiceTracker(_jettyServerServiceTracker);
113 
114         // the tracker in charge of the actual deployment
115         // and that will configure and start the jetty server.
116         context.addServiceListener(_jettyContextHandlerTracker, "(objectclass=" + ContextHandler.class.getName() + ")");
117 
118         // see if we shoult start a default jetty instance right now.
119         DefaultJettyAtJettyHomeHelper.startJettyAtJettyHome(context);
120 
121         // now ready to support the Extender pattern:
122         _webBundleTracker = new BundleTracker(context, Bundle.ACTIVE | Bundle.STOPPING, new WebBundleTrackerCustomizer());
123         _webBundleTracker.open();
124 
125     }
126 
127     /*
128      * (non-Javadoc)
129      * 
130      * @see
131      * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
132      */
133     public void stop(BundleContext context) throws Exception
134     {
135         try
136         {
137 
138             if (_webBundleTracker != null)
139             {
140                 _webBundleTracker.close();
141                 _webBundleTracker = null;
142             }
143             if (_jettyContextHandlerTracker != null)
144             {
145                 _jettyContextHandlerTracker.stop();
146                 context.removeServiceListener(_jettyContextHandlerTracker);
147                 _jettyContextHandlerTracker = null;
148             }
149             if (_jettyServerServiceTracker != null)
150             {
151                 _jettyServerServiceTracker.stop();
152                 context.removeServiceListener(_jettyServerServiceTracker);
153                 _jettyServerServiceTracker = null;
154             }
155             if (_packageAdminServiceTracker != null)
156             {
157                 _packageAdminServiceTracker.stop();
158                 context.removeServiceListener(_packageAdminServiceTracker);
159                 _packageAdminServiceTracker = null;
160             }
161             if (_registeredServer != null)
162             {
163                 try
164                 {
165                     _registeredServer.unregister();
166                 }
167                 catch (IllegalArgumentException ill)
168                 {
169                     // already unregistered.
170                 }
171                 finally
172                 {
173                     _registeredServer = null;
174                 }
175             }
176             // if (_jettyServerFactoryService != null)
177             // {
178             // try
179             // {
180             // _jettyServerFactoryService.unregister();
181             // }
182             // catch (IllegalArgumentException ill)
183             // {
184             // // already unregistered.
185             // }
186             // finally
187             // {
188             // _jettyServerFactoryService = null;
189             // }
190             // }
191 
192         }
193         finally
194         {
195             if (_server != null)
196             {
197                 _server.stop();
198             }
199             INSTANCE = null;
200         }
201     }
202 
203     /**
204      * Helper method that creates a new org.jetty.webapp.WebAppContext and
205      * registers it as an OSGi service. The tracker
206      * {@link JettyContextHandlerServiceTracker} will do the actual deployment.
207      * 
208      * @param contributor The bundle
209      * @param webappFolderPath The path to the root of the webapp. Must be a
210      *            path relative to bundle; either an absolute path.
211      * @param contextPath The context path. Must start with "/"
212      * @throws Exception
213      */
214     public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath) throws Exception
215     {
216         checkBundleActivated();
217         WebAppContext contextHandler = new WebAppContext();
218         Dictionary dic = new Hashtable();
219         dic.put(OSGiWebappConstants.SERVICE_PROP_WAR, webappFolderPath);
220         dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH, contextPath);
221         String requireTldBundle = (String) contributor.getHeaders().get(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
222         if (requireTldBundle != null)
223         {
224             dic.put(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE, requireTldBundle);
225         }
226         contributor.getBundleContext().registerService(ContextHandler.class.getName(), contextHandler, dic);
227     }
228 
229     /**
230      * Helper method that creates a new org.jetty.webapp.WebAppContext and
231      * registers it as an OSGi service. The tracker
232      * {@link JettyContextHandlerServiceTracker} will do the actual deployment.
233      * 
234      * @param contributor The bundle
235      * @param webappFolderPath The path to the root of the webapp. Must be a
236      *            path relative to bundle; either an absolute path.
237      * @param contextPath The context path. Must start with "/"
238      * @param dic TODO: parameter description
239      * @throws Exception
240      */
241     public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath, Dictionary<String, String> dic) throws Exception
242     {
243         checkBundleActivated();
244         WebAppContext contextHandler = new WebAppContext();
245         dic.put(OSGiWebappConstants.SERVICE_PROP_WAR, webappFolderPath);
246         dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH, contextPath);
247         contributor.getBundleContext().registerService(ContextHandler.class.getName(), contextHandler, dic);
248     }
249 
250     /**
251      * Helper method that creates a new skeleton of a ContextHandler and
252      * registers it as an OSGi service. The tracker
253      * {@link JettyContextHandlerServiceTracker} will do the actual deployment.
254      * 
255      * @param contributor The bundle that registers a new context
256      * @param contextFilePath The path to the file inside the bundle that
257      *            defines the context.
258      * @throws Exception
259      */
260     public static void registerContext(Bundle contributor, String contextFilePath) throws Exception
261     {
262         registerContext(contributor, contextFilePath, new Hashtable<String, String>());
263     }
264 
265     /**
266      * Helper method that creates a new skeleton of a ContextHandler and
267      * registers it as an OSGi service. The tracker
268      * {@link JettyContextHandlerServiceTracker} will do the actual deployment.
269      * 
270      * @param contributor The bundle that registers a new context
271      * @param contextFilePath The path to the file inside the bundle that
272      *            defines the context.
273      * @param dic TODO: parameter description
274      * @throws Exception
275      */
276     public static void registerContext(Bundle contributor, String contextFilePath, Dictionary<String, String> dic) throws Exception
277     {
278         checkBundleActivated();
279         ContextHandler contextHandler = new ContextHandler();
280         dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH, contextFilePath);
281         dic.put(IWebBundleDeployerHelper.INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE, Boolean.TRUE.toString());
282         contributor.getBundleContext().registerService(ContextHandler.class.getName(), contextHandler, dic);
283     }
284 
285     public static void unregister(String contextPath)
286     {
287         // todo
288     }
289 
290     /**
291      * Since org.eclipse.jetty.osgi.boot does not have a lazy activation policy
292      * when one fo the static methods to register a webapp is called we should
293      * make sure that the bundle is started.
294      */
295     private static void checkBundleActivated()
296     {
297         if (INSTANCE == null)
298         {
299             Bundle thisBundle = FrameworkUtil.getBundle(JettyBootstrapActivator.class);
300             try
301             {
302                 thisBundle.start();
303             }
304             catch (BundleException e)
305             {
306                 // nevermind.
307             }
308         }
309     }
310 
311     /**
312      * @return The bundle context for this bundle.
313      */
314     public static BundleContext getBundleContext()
315     {
316         checkBundleActivated();
317         return INSTANCE._bundleContext;
318     }
319 
320 }