View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2016 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.util.Dictionary;
23  import java.util.HashMap;
24  
25  import org.eclipse.jetty.deploy.App;
26  import org.eclipse.jetty.deploy.AppProvider;
27  import org.eclipse.jetty.deploy.DeploymentManager;
28  import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
29  import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
30  import org.eclipse.jetty.osgi.boot.utils.OSGiClassLoader;
31  import org.eclipse.jetty.server.handler.ContextHandler;
32  import org.eclipse.jetty.util.component.AbstractLifeCycle;
33  import org.eclipse.jetty.util.log.Log;
34  import org.eclipse.jetty.util.log.Logger;
35  import org.eclipse.jetty.util.resource.JarResource;
36  import org.eclipse.jetty.util.resource.Resource;
37  import org.eclipse.jetty.xml.XmlConfiguration;
38  import org.osgi.framework.Bundle;
39  
40  
41  
42  
43  /**
44   * AbstractContextProvider
45   *
46   * Base class for DeploymentManager Providers that can deploy ContextHandlers into 
47   * Jetty that have been discovered via OSGI either as bundles or services.
48   * 
49   */
50  public abstract class AbstractContextProvider extends AbstractLifeCycle implements AppProvider
51  {
52      private static final Logger LOG = Log.getLogger(AbstractContextProvider.class);
53      
54      private DeploymentManager _deploymentManager;    
55      
56      private ServerInstanceWrapper _serverWrapper;
57      
58      
59      
60      
61      /* ------------------------------------------------------------ */
62      /**
63       * OSGiApp
64       *
65       *
66       */
67      public class OSGiApp extends AbstractOSGiApp
68      {
69          private String _contextFile;
70          private ContextHandler _contextHandler;
71          private boolean _configured = false;
72          
73          public OSGiApp(DeploymentManager manager, AppProvider provider, String originId, Bundle bundle, String contextFile)
74          {
75              super(manager, provider, bundle, originId);
76              _contextFile = contextFile;
77          }
78          
79          public OSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String contextFile, String originId)
80          {
81              super(manager, provider, bundle, properties, originId);
82              _contextFile = contextFile;
83          }
84                 
85          public String getContextFile ()
86          {
87              return _contextFile;
88          }
89          
90          public void setHandler(ContextHandler h)
91          {
92              _contextHandler = h;
93          }
94         
95          public ContextHandler createContextHandler()
96          throws Exception
97          {
98              configureContextHandler();
99              return _contextHandler;
100         }
101 
102         public void configureContextHandler()
103         throws Exception
104         {
105             if (_configured)
106                 return;
107 
108             _configured = true;
109             
110             //Override for bundle root may have been set
111             String bundleOverrideLocation = (String)_properties.get(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE);
112             if (bundleOverrideLocation == null)
113                 bundleOverrideLocation = (String)_properties.get(OSGiWebappConstants.SERVICE_PROP_BUNDLE_INSTALL_LOCATION_OVERRIDE);
114 
115             //Location on filesystem of bundle or the bundle override location
116             File bundleLocation = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(_bundle);
117             File root = (bundleOverrideLocation==null?bundleLocation:new File(bundleOverrideLocation));
118             Resource rootResource = Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(root.toURI().toURL()));
119             
120             //try and make sure the rootResource is useable - if its a jar then make it a jar file url
121             if (rootResource.exists()&& !rootResource.isDirectory() && !rootResource.toString().startsWith("jar:"))
122             {
123                Resource jarResource = JarResource.newJarResource(rootResource);
124                if (jarResource.exists() && jarResource.isDirectory())
125                    rootResource = jarResource;
126             }
127             
128             //Set the base resource of the ContextHandler, if not already set, can also be overridden by the context xml file
129             if (_contextHandler != null && _contextHandler.getBaseResource() == null)
130             {
131                 _contextHandler.setBaseResource(rootResource);
132             }
133 
134             //Use a classloader that knows about the common jetty parent loader, and also the bundle                  
135             OSGiClassLoader classLoader = new OSGiClassLoader(getServerInstanceWrapper().getParentClassLoaderForWebapps(), _bundle);
136 
137             //if there is a context file, find it and apply it
138             if (_contextFile == null && _contextHandler == null)
139                 throw new IllegalStateException("No context file or ContextHandler");
140 
141             if (_contextFile != null)
142             {   
143                 //apply the contextFile, creating the ContextHandler, the DeploymentManager will register it in the ContextHandlerCollection
144                 Resource res = null;
145                 
146                 String jettyHome = (String)getServerInstanceWrapper().getServer().getAttribute(OSGiServerConstants.JETTY_HOME);
147                 if (jettyHome == null)
148                     jettyHome =  System.getProperty(OSGiServerConstants.JETTY_HOME);
149                 
150                 res = findFile(_contextFile, jettyHome, bundleOverrideLocation, _bundle);
151 
152                 //apply the context xml file, either to an existing ContextHandler, or letting the
153                 //it create the ContextHandler as necessary
154                 if (res != null)
155                 { 
156                     ClassLoader cl = Thread.currentThread().getContextClassLoader();
157 
158                     LOG.debug("Context classloader = " + cl);
159                     try
160                     {
161                         Thread.currentThread().setContextClassLoader(classLoader);
162                         
163                         XmlConfiguration xmlConfiguration = new XmlConfiguration(res.getInputStream());
164                         HashMap properties = new HashMap();
165                         //put the server instance in
166                         properties.put("Server", getServerInstanceWrapper().getServer());
167                         //put in the location of the bundle root
168                         properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString());
169                         
170                         // insert the bundle's location as a property.
171                         xmlConfiguration.getProperties().putAll(properties);
172 
173                         if (_contextHandler == null)
174                             _contextHandler = (ContextHandler) xmlConfiguration.configure();
175                         else
176                             xmlConfiguration.configure(_contextHandler);
177                     }
178                     finally
179                     {
180                         Thread.currentThread().setContextClassLoader(cl);
181                     }
182                 }
183             }
184 
185             //Set up the class loader we created
186             _contextHandler.setClassLoader(classLoader);
187             
188             
189             //If a bundle/service property specifies context path, let it override the context xml
190             String contextPath = (String)_properties.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
191             if (contextPath == null)
192                 contextPath = (String)_properties.get(OSGiWebappConstants.SERVICE_PROP_CONTEXT_PATH);
193             if (contextPath != null)
194                 _contextHandler.setContextPath(contextPath);    
195             
196             //osgi Enterprise Spec r4 p.427
197             _contextHandler.setAttribute(OSGiWebappConstants.OSGI_BUNDLECONTEXT, _bundle.getBundleContext());
198             
199             //make sure we protect also the osgi dirs specified by OSGi Enterprise spec
200             String[] targets = _contextHandler.getProtectedTargets();
201             int length = (targets==null?0:targets.length);
202             
203             String[] updatedTargets = null;
204             if (targets != null)
205             {
206                 updatedTargets = new String[length+OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length];
207                 System.arraycopy(targets, 0, updatedTargets, 0, length);
208                 
209             }
210             else
211                 updatedTargets = new String[OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length];
212             System.arraycopy(OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS, 0, updatedTargets, length, OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length);
213             _contextHandler.setProtectedTargets(updatedTargets);
214            
215         }
216 
217     }
218     
219     /* ------------------------------------------------------------ */
220     public AbstractContextProvider(ServerInstanceWrapper wrapper)
221     {
222         _serverWrapper = wrapper;
223     }
224     
225     
226     /* ------------------------------------------------------------ */
227     public ServerInstanceWrapper getServerInstanceWrapper()
228     {
229         return _serverWrapper;
230     }
231     
232     /* ------------------------------------------------------------ */
233     /** 
234      * @see org.eclipse.jetty.deploy.AppProvider#createContextHandler(org.eclipse.jetty.deploy.App)
235      */
236     public ContextHandler createContextHandler(App app) throws Exception
237     {
238         if (app == null)
239             return null;
240         if (!(app instanceof OSGiApp))
241             throw new IllegalStateException(app+" is not a BundleApp");
242         
243         //Create a ContextHandler suitable to deploy in OSGi
244         ContextHandler h = ((OSGiApp)app).createContextHandler();           
245         return h;
246     }
247     
248     /* ------------------------------------------------------------ */
249     public void setDeploymentManager(DeploymentManager deploymentManager)
250     {
251         _deploymentManager = deploymentManager;
252     }
253     
254     /* ------------------------------------------------------------ */
255     public DeploymentManager getDeploymentManager()
256     {
257         return _deploymentManager;
258     }
259 }