View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 Mort Bay Consulting Pty. Ltd.
4   //  ------------------------------------------------------------------------
5   //  All rights reserved. This program and the accompanying materials
6   //  are made available under the terms of the Eclipse Public License v1.0
7   //  and Apache License v2.0 which accompanies this distribution.
8   //
9   //      The Eclipse Public License is available at
10  //      http://www.eclipse.org/legal/epl-v10.html
11  //
12  //      The Apache License v2.0 is available at
13  //      http://www.opensource.org/licenses/apache2.0.php
14  //
15  //  You may elect to redistribute this code under either of these licenses.
16  //  ========================================================================
17  //
18  
19  package org.eclipse.jetty.osgi.boot;
20  
21  import java.io.File;
22  import java.net.URL;
23  import java.util.Dictionary;
24  import java.util.HashMap;
25  
26  import org.eclipse.jetty.deploy.App;
27  import org.eclipse.jetty.deploy.AppProvider;
28  import org.eclipse.jetty.deploy.DeploymentManager;
29  import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
30  import org.eclipse.jetty.osgi.boot.internal.webapp.BundleFileLocatorHelperFactory;
31  import org.eclipse.jetty.osgi.boot.utils.OSGiClassLoader;
32  import org.eclipse.jetty.server.handler.ContextHandler;
33  import org.eclipse.jetty.util.component.AbstractLifeCycle;
34  import org.eclipse.jetty.util.log.Log;
35  import org.eclipse.jetty.util.log.Logger;
36  import org.eclipse.jetty.util.resource.JarResource;
37  import org.eclipse.jetty.util.resource.Resource;
38  import org.eclipse.jetty.xml.XmlConfiguration;
39  import org.osgi.framework.Bundle;
40  
41  
42  
43  
44  /**
45   * AbstractContextProvider
46   *
47   * Base class for DeploymentManager Providers that can deploy ContextHandlers into 
48   * Jetty that have been discovered via OSGI either as bundles or services.
49   * 
50   */
51  public abstract class AbstractContextProvider extends AbstractLifeCycle implements AppProvider
52  {
53      private static final Logger LOG = Log.getLogger(AbstractContextProvider.class);
54      
55      private DeploymentManager _deploymentManager;    
56      
57      private ServerInstanceWrapper _serverWrapper;
58      
59      
60      
61      
62      /* ------------------------------------------------------------ */
63      /**
64       * OSGiApp
65       *
66       *
67       */
68      public class OSGiApp extends AbstractOSGiApp
69      {
70          private String _contextFile;
71          private ContextHandler _contextHandler;
72          private boolean _configured = false;
73          
74          public OSGiApp(DeploymentManager manager, AppProvider provider, String originId, Bundle bundle, String contextFile)
75          {
76              super(manager, provider, bundle, originId);
77              _contextFile = contextFile;
78          }
79          
80          public OSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String contextFile, String originId)
81          {
82              super(manager, provider, bundle, properties, originId);
83              _contextFile = contextFile;
84          }
85                 
86          public String getContextFile ()
87          {
88              return _contextFile;
89          }
90          
91          public void setHandler(ContextHandler h)
92          {
93              _contextHandler = h;
94          }
95         
96          public ContextHandler createContextHandler()
97          throws Exception
98          {
99              configureContextHandler();
100             return _contextHandler;
101         }
102 
103         public void configureContextHandler()
104         throws Exception
105         {
106             if (_configured)
107                 return;
108 
109             _configured = true;
110             
111             //Override for bundle root may have been set
112             String bundleOverrideLocation = (String)_properties.get(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE);
113             if (bundleOverrideLocation == null)
114                 bundleOverrideLocation = (String)_properties.get(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE);
115 
116             //Location on filesystem of bundle or the bundle override location
117             File bundleLocation = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(_bundle);
118             File root = (bundleOverrideLocation==null?bundleLocation:new File(bundleOverrideLocation));
119             Resource rootResource = Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(root.toURI().toURL()));
120             
121             //try and make sure the rootResource is useable - if its a jar then make it a jar file url
122             if (rootResource.exists()&& !rootResource.isDirectory() && !rootResource.toString().startsWith("jar:"))
123             {
124                Resource jarResource = JarResource.newJarResource(rootResource);
125                if (jarResource.exists() && jarResource.isDirectory())
126                    rootResource = jarResource;
127             }
128             
129             //Set the base resource of the ContextHandler, if not already set, can also be overridden by the context xml file
130             if (_contextHandler != null && _contextHandler.getBaseResource() == null)
131             {
132                 _contextHandler.setBaseResource(rootResource);
133             }
134 
135             //Use a classloader that knows about the common jetty parent loader, and also the bundle                  
136             OSGiClassLoader classLoader = new OSGiClassLoader(getServerInstanceWrapper().getParentClassLoaderForWebapps(), _bundle);
137 
138             //if there is a context file, find it and apply it
139             if (_contextFile == null && _contextHandler == null)
140                 throw new IllegalStateException("No context file or ContextHandler");
141 
142             if (_contextFile != null)
143             {   
144                 //apply the contextFile, creating the ContextHandler, the DeploymentManager will register it in the ContextHandlerCollection
145                 Resource res = null;
146 
147                 //try to find the context file in the filesystem
148                 if (_contextFile.startsWith("/"))
149                     res = getFileAsResource(_contextFile);
150 
151                 //try to find it relative to jetty home
152                 if (res == null)
153                 {
154                     //See if the specific server we are related to has jetty.home set
155                     String jettyHome = (String)getServerInstanceWrapper().getServer().getAttribute(OSGiServerConstants.JETTY_HOME);
156                     if (jettyHome != null)
157                         res = getFileAsResource(jettyHome, _contextFile);
158 
159                     //try to see if a SystemProperty for jetty.home is set
160                     if (res == null)
161                     {
162                         jettyHome =  System.getProperty(OSGiServerConstants.JETTY_HOME);
163 
164                         if (jettyHome != null)
165                         {
166                             if (jettyHome.startsWith("\"") || jettyHome.startsWith("'"))
167                                 jettyHome = jettyHome.substring(1);
168                             if (jettyHome.endsWith("\"") || (jettyHome.endsWith("'")))
169                                 jettyHome = jettyHome.substring(0,jettyHome.length()-1);
170 
171                             res = getFileAsResource(jettyHome, _contextFile); 
172                             if (LOG.isDebugEnabled()) LOG.debug("jetty home context file:"+res);
173                         }
174                     }
175                 }
176 
177                 //try to find it relative to an override location that has been specified
178                 if (res == null)
179                 {                 
180                     if (bundleOverrideLocation != null)
181                     { 
182                         res = getFileAsResource(Resource.newResource(bundleOverrideLocation).getFile(), _contextFile);
183                         if (LOG.isDebugEnabled()) LOG.debug("Bundle override location context file:"+res);
184                     }
185                 }         
186 
187                 //try to find it relative to the bundle in which it is being deployed
188                 if (res == null)
189                 {
190                     if (_contextFile.startsWith("./"))
191                         _contextFile = _contextFile.substring(1);
192 
193                     if (!_contextFile.startsWith("/"))
194                         _contextFile = "/" + _contextFile;
195 
196                     URL contextURL = _bundle.getEntry(_contextFile);
197                     if (contextURL != null)
198                         res = Resource.newResource(contextURL);
199                 }
200 
201                 //apply the context xml file, either to an existing ContextHandler, or letting the
202                 //it create the ContextHandler as necessary
203                 if (res != null)
204                 { 
205                     ClassLoader cl = Thread.currentThread().getContextClassLoader();
206 
207                     LOG.debug("Context classloader = " + cl);
208                     try
209                     {
210                         Thread.currentThread().setContextClassLoader(classLoader);
211                         
212                         XmlConfiguration xmlConfiguration = new XmlConfiguration(res.getInputStream());
213                         HashMap properties = new HashMap();
214                         //put the server instance in
215                         properties.put("Server", getServerInstanceWrapper().getServer());
216                         //put in the location of the bundle root
217                         properties.put("bundle.root", rootResource.toString());
218                         
219                         // insert the bundle's location as a property.
220                         xmlConfiguration.getProperties().putAll(properties);
221 
222                         if (_contextHandler == null)
223                             _contextHandler = (ContextHandler) xmlConfiguration.configure();
224                         else
225                             xmlConfiguration.configure(_contextHandler);
226                     }
227                     finally
228                     {
229                         Thread.currentThread().setContextClassLoader(cl);
230                     }
231                 }
232             }
233 
234             //Set up the class loader we created
235             _contextHandler.setClassLoader(classLoader);
236             
237             
238             //If a bundle/service property specifies context path, let it override the context xml
239             String contextPath = (String)_properties.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
240             if (contextPath == null)
241                 contextPath = (String)_properties.get(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH);
242             if (contextPath != null)
243                 _contextHandler.setContextPath(contextPath);    
244             
245             //osgi Enterprise Spec r4 p.427
246             _contextHandler.setAttribute(OSGiWebappConstants.OSGI_BUNDLECONTEXT, _bundle.getBundleContext());
247             
248             //make sure we protect also the osgi dirs specified by OSGi Enterprise spec
249             String[] targets = _contextHandler.getProtectedTargets();
250             int length = (targets==null?0:targets.length);
251             
252             String[] updatedTargets = null;
253             if (targets != null)
254             {
255                 updatedTargets = new String[length+OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length];
256                 System.arraycopy(targets, 0, updatedTargets, 0, length);
257                 
258             }
259             else
260                 updatedTargets = new String[OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length];
261             System.arraycopy(OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS, 0, updatedTargets, length, OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length);
262             _contextHandler.setProtectedTargets(updatedTargets);
263            
264         }
265 
266 
267         private Resource getFileAsResource (String dir, String file)
268         {
269             Resource r = null;
270             try
271             {
272                 File asFile = new File (dir, file);
273                 if (asFile.exists())
274                     r = Resource.newResource(asFile);
275             }
276             catch (Exception e)
277             {
278                 r = null;
279             } 
280             return r;
281         }
282         
283         private Resource getFileAsResource (String file)
284         {
285             Resource r = null;
286             try
287             {
288                 File asFile = new File (file);
289                 if (asFile.exists())
290                     r = Resource.newResource(asFile);
291             }
292             catch (Exception e)
293             {
294                 r = null;
295             } 
296             return r;
297         }
298         
299         private Resource getFileAsResource (File dir, String file)
300         {
301             Resource r = null;
302             try
303             {
304                 File asFile = new File (dir, file);
305                 if (asFile.exists())
306                     r = Resource.newResource(asFile);
307             } 
308             catch (Exception e)
309             {
310                 r = null;
311             } 
312             return r;
313         }
314     }
315     
316     /* ------------------------------------------------------------ */
317     public AbstractContextProvider(ServerInstanceWrapper wrapper)
318     {
319         _serverWrapper = wrapper;
320     }
321     
322     
323     /* ------------------------------------------------------------ */
324     public ServerInstanceWrapper getServerInstanceWrapper()
325     {
326         return _serverWrapper;
327     }
328     
329     /* ------------------------------------------------------------ */
330     /** 
331      * @see org.eclipse.jetty.deploy.AppProvider#createContextHandler(org.eclipse.jetty.deploy.App)
332      */
333     public ContextHandler createContextHandler(App app) throws Exception
334     {
335         if (app == null)
336             return null;
337         if (!(app instanceof OSGiApp))
338             throw new IllegalStateException(app+" is not a BundleApp");
339         
340         //Create a ContextHandler suitable to deploy in OSGi
341         ContextHandler h = ((OSGiApp)app).createContextHandler();           
342         return h;
343     }
344     
345     /* ------------------------------------------------------------ */
346     public void setDeploymentManager(DeploymentManager deploymentManager)
347     {
348         _deploymentManager = deploymentManager;
349     }
350     
351     /* ------------------------------------------------------------ */
352     public DeploymentManager getDeploymentManager()
353     {
354         return _deploymentManager;
355     }
356 }