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      private Server _server;
70      private JettyContextHandlerServiceTracker _jettyContextHandlerTracker;
71      private PackageAdminServiceTracker _packageAdminServiceTracker;
72      private BundleTracker _webBundleTracker;
73      private BundleContext _bundleContext;
74      
75  //    private ServiceRegistration _jettyServerFactoryService;
76      private JettyServerServiceTracker _jettyServerServiceTracker;
77      
78  
79      /**
80       * Setup a new jetty Server, registers it as a service. Setup the Service
81       * tracker for the jetty ContextHandlers that are in charge of deploying the
82       * webapps. Setup the BundleListener that supports the extender pattern for
83       * the jetty ContextHandler.
84       * 
85       * @param context
86       */
87      public void start(BundleContext context) throws Exception
88      {
89          INSTANCE = this;
90          _bundleContext = context;
91  
92          // track other bundles and fragments attached to this bundle that we
93          // should activate.
94          _packageAdminServiceTracker = new PackageAdminServiceTracker(context);
95  
96      	_jettyServerServiceTracker = new JettyServerServiceTracker();
97          context.addServiceListener(_jettyServerServiceTracker,"(objectclass=" + Server.class.getName() + ")");
98  
99          //Register the Jetty Server Factory as a ManagedServiceFactory:
100 //          Properties jettyServerMgdFactoryServiceProps = new Properties(); 
101 //          jettyServerMgdFactoryServiceProps.put("pid", OSGiWebappConstants.MANAGED_JETTY_SERVER_FACTORY_PID);
102 //          _jettyServerFactoryService = context.registerService(
103 //          		ManagedServiceFactory.class.getName(),  new JettyServersManagedFactory(),
104 //          		jettyServerMgdFactoryServiceProps);
105     
106         _jettyContextHandlerTracker = new JettyContextHandlerServiceTracker(_jettyServerServiceTracker);
107 
108         // the tracker in charge of the actual deployment
109         // and that will configure and start the jetty server.
110         context.addServiceListener(_jettyContextHandlerTracker,"(objectclass=" + ContextHandler.class.getName() + ")");
111 
112         //see if we shoult start a default jetty instance right now.
113         DefaultJettyAtJettyHomeHelper.startJettyAtJettyHome(context);
114         
115         // now ready to support the Extender pattern:        
116         _webBundleTracker = new BundleTracker(context,
117         		Bundle.ACTIVE | Bundle.STOPPING, new WebBundleTrackerCustomizer());
118         _webBundleTracker.open();
119         
120     }
121 
122     /*
123      * (non-Javadoc)
124      * 
125      * @see
126      * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
127      */
128     public void stop(BundleContext context) throws Exception
129     {
130         try
131         {
132         	
133         	if (_webBundleTracker != null)
134         	{
135         		_webBundleTracker.close();
136         		_webBundleTracker = null;
137         	}
138             if (_jettyContextHandlerTracker != null)
139             {
140                 _jettyContextHandlerTracker.stop();
141                 context.removeServiceListener(_jettyContextHandlerTracker);
142                 _jettyContextHandlerTracker = null;
143             }
144             if (_jettyServerServiceTracker != null)
145             {
146             	_jettyServerServiceTracker.stop();
147                 context.removeServiceListener(_jettyServerServiceTracker);
148                 _jettyServerServiceTracker = null;
149             }
150             if (_packageAdminServiceTracker != null)
151             {
152                 _packageAdminServiceTracker.stop();
153                 context.removeServiceListener(_packageAdminServiceTracker);
154                 _packageAdminServiceTracker = null;
155             }
156             if (_registeredServer != null)
157             {
158                 try
159                 {
160                     _registeredServer.unregister();
161                 }
162                 catch (IllegalArgumentException ill)
163                 {
164                     // already unregistered.
165                 }
166                 finally
167                 {
168                 	_registeredServer = null;
169                 }
170             }
171 //        	if (_jettyServerFactoryService != null)
172 //        	{
173 //                try
174 //                {
175 //                	_jettyServerFactoryService.unregister();
176 //                }
177 //                catch (IllegalArgumentException ill)
178 //                {
179 //                    // already unregistered.
180 //                }
181 //                finally
182 //                {
183 //                	_jettyServerFactoryService = null;
184 //                }
185 //        	}
186 
187         }
188         finally
189         {
190             if (_server != null)
191             {
192             	_server.stop();
193             }
194             INSTANCE = null;
195         }
196     }
197 
198     /**
199      * Helper method that creates a new org.jetty.webapp.WebAppContext and
200      * registers it as an OSGi service. The tracker
201      * {@link JettyContextHandlerServiceTracker} will do the actual deployment.
202      * 
203      * @param contributor
204      *            The bundle
205      * @param webappFolderPath
206      *            The path to the root of the webapp. Must be a path relative to
207      *            bundle; either an absolute path.
208      * @param contextPath
209      *            The context path. Must start with "/"
210      * @throws Exception
211      */
212     public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath) throws Exception
213     {
214     	checkBundleActivated();
215     	WebAppContext contextHandler = new WebAppContext();
216         Dictionary dic = new Hashtable();
217         dic.put(OSGiWebappConstants.SERVICE_PROP_WAR,webappFolderPath);
218         dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH,contextPath);
219         String requireTldBundle = (String)contributor.getHeaders().get(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
220         if (requireTldBundle != null) {
221         	dic.put(OSGiWebappConstants.SERVICE_PROP_REQUIRE_TLD_BUNDLE, requireTldBundle);
222         }
223         contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic);
224     }
225 
226     /**
227      * Helper method that creates a new org.jetty.webapp.WebAppContext and
228      * registers it as an OSGi service. The tracker
229      * {@link JettyContextHandlerServiceTracker} will do the actual deployment.
230      * 
231      * @param contributor
232      *            The bundle
233      * @param webappFolderPath
234      *            The path to the root of the webapp. Must be a path relative to
235      *            bundle; either an absolute path.
236      * @param contextPath
237      *            The context path. Must start with "/"
238      * @param dic
239      *        TODO: parameter description
240      * @throws Exception
241      */
242     public static void registerWebapplication(Bundle contributor, String webappFolderPath, String contextPath, Dictionary<String, String> dic) throws Exception
243     {
244     	checkBundleActivated();
245         WebAppContext contextHandler = new WebAppContext();
246         dic.put(OSGiWebappConstants.SERVICE_PROP_WAR,webappFolderPath);
247         dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH,contextPath);
248         contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic);
249     }
250 
251     /**
252      * Helper method that creates a new skeleton of a ContextHandler and
253      * registers it as an OSGi service. The tracker
254      * {@link JettyContextHandlerServiceTracker} will do the actual deployment.
255      * 
256      * @param contributor
257      *            The bundle that registers a new context
258      * @param contextFilePath
259      *            The path to the file inside the bundle that defines the
260      *            context.
261      * @throws Exception
262      */
263     public static void registerContext(Bundle contributor, String contextFilePath) throws Exception
264     {
265         registerContext(contributor,contextFilePath,new Hashtable<String, String>());
266     }
267 
268     /**
269      * Helper method that creates a new skeleton of a ContextHandler and
270      * registers it as an OSGi service. The tracker
271      * {@link JettyContextHandlerServiceTracker} will do the actual deployment.
272      * 
273      * @param contributor
274      *            The bundle that registers a new context
275      * @param contextFilePath
276      *            The path to the file inside the bundle that defines the
277      *            context.
278      * @param dic
279      *          TODO: parameter description
280      * @throws Exception
281      */
282     public static void registerContext(Bundle contributor, String contextFilePath, Dictionary<String, String> dic) throws Exception
283     {
284     	checkBundleActivated();
285         ContextHandler contextHandler = new ContextHandler();
286         dic.put(OSGiWebappConstants.SERVICE_PROP_CONTEXT_FILE_PATH,contextFilePath);
287         dic.put(IWebBundleDeployerHelper.INTERNAL_SERVICE_PROP_UNKNOWN_CONTEXT_HANDLER_TYPE,Boolean.TRUE.toString());
288         contributor.getBundleContext().registerService(ContextHandler.class.getName(),contextHandler,dic);
289     }
290 
291     public static void unregister(String contextPath)
292     {
293         // todo
294     }
295     
296     /**
297      * Since org.eclipse.jetty.osgi.boot does not have a lazy activation policy
298      * when one fo the static methods to register a webapp is called we should make sure that
299      * the bundle is started.
300      */
301     private static void checkBundleActivated()
302     {
303         if (INSTANCE == null)
304         {
305             Bundle thisBundle = FrameworkUtil.getBundle(JettyBootstrapActivator.class);
306             try
307             {
308                 thisBundle.start();
309             }
310             catch (BundleException e)
311             {
312                 // nevermind.
313             }
314         }
315     }
316     
317     /**
318      * @return The bundle context for this bundle.
319      */
320     public static BundleContext getBundleContext()
321     {
322         checkBundleActivated();
323         return INSTANCE._bundleContext;
324     }
325     
326 
327 }