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