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.util.Dictionary;
22  import java.util.HashMap;
23  import java.util.Hashtable;
24  import java.util.Map;
25  
26  import org.eclipse.jetty.deploy.App;
27  import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
28  import org.eclipse.jetty.osgi.boot.utils.EventSender;
29  import org.eclipse.jetty.util.log.Log;
30  import org.eclipse.jetty.util.log.Logger;
31  import org.osgi.framework.Bundle;
32  import org.osgi.framework.FrameworkUtil;
33  import org.osgi.framework.ServiceRegistration;
34  
35  
36  
37  /**
38   * BundleWebAppProvider
39   *
40   * A Jetty Provider that knows how to deploy a WebApp contained inside a Bundle.
41   * 
42   */
43  public class BundleWebAppProvider extends AbstractWebAppProvider implements BundleProvider
44  {     
45      private static final Logger LOG = Log.getLogger(AbstractWebAppProvider.class);
46      
47      /**
48       * Map of Bundle to App. Used when a Bundle contains a webapp.
49       */
50      private Map<Bundle, App> _bundleMap = new HashMap<Bundle, App>();
51      
52      private ServiceRegistration _serviceRegForBundles;
53      
54  
55      /* ------------------------------------------------------------ */
56      /**
57       * @param wrapper
58       */
59      public BundleWebAppProvider (ServerInstanceWrapper wrapper)
60      {
61          super(wrapper);
62      }
63      
64      
65      
66      
67      /* ------------------------------------------------------------ */
68      /** 
69       * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStart()
70       */
71      protected void doStart() throws Exception
72      {
73          //register as an osgi service for deploying bundles, advertising the name of the jetty Server instance we are related to
74          Dictionary<String,String> properties = new Hashtable<String,String>();
75          properties.put(OSGiServerConstants.MANAGED_JETTY_SERVER_NAME, getServerInstanceWrapper().getManagedServerName());
76          _serviceRegForBundles = FrameworkUtil.getBundle(this.getClass()).getBundleContext().registerService(BundleProvider.class.getName(), this, properties);
77          super.doStart();
78      }
79  
80      /* ------------------------------------------------------------ */
81      /** 
82       * @see org.eclipse.jetty.util.component.AbstractLifeCycle#doStop()
83       */
84      @Override
85      protected void doStop() throws Exception
86      {
87          //unregister ourselves
88          if (_serviceRegForBundles != null)
89          {
90              try
91              {
92                  _serviceRegForBundles.unregister();
93              }
94              catch (Exception e)
95              {
96                  LOG.warn(e);
97              }
98          }
99       
100         super.doStop();
101     }
102     
103     
104     
105 
106     
107     
108     /* ------------------------------------------------------------ */
109     /**
110      * A bundle has been added that could be a webapp 
111      * @param bundle
112      */
113     public boolean bundleAdded (Bundle bundle) throws Exception
114     {
115         if (bundle == null)
116             return false;
117 
118         ClassLoader cl = Thread.currentThread().getContextClassLoader();
119         Thread.currentThread().setContextClassLoader(getServerInstanceWrapper().getParentClassLoaderForWebapps());
120         String contextPath = null;
121         try 
122         {
123             Dictionary headers = bundle.getHeaders();
124 
125             //does the bundle have a OSGiWebappConstants.JETTY_WAR_FOLDER_PATH 
126             if (headers.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH) != null)
127             {
128                 String base = (String)headers.get(OSGiWebappConstants.JETTY_WAR_FOLDER_PATH);
129                 contextPath = getContextPath(bundle);
130                 String originId = getOriginId(bundle, base);
131  
132                 //TODO : we don't know whether an app is actually deployed, as deploymentManager swallows all
133                 //exceptions inside the impl of addApp. Need to send the Event and also register as a service
134                 //only if the deployment succeeded
135                 OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId);
136                 app.setWebAppPath(base);
137                 app.setContextPath(contextPath);
138                 _bundleMap.put(bundle, app);
139                 getDeploymentManager().addApp(app);
140                 return true;
141             }
142 
143 
144             //does the bundle have a WEB-INF/web.xml
145             if (bundle.getEntry("/WEB-INF/web.xml") != null)
146             {
147                 String base = ".";
148                 contextPath = getContextPath(bundle);
149                 String originId = getOriginId(bundle, base);
150        
151                 OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId);
152                 app.setContextPath(contextPath);
153                 app.setWebAppPath(base);
154                 _bundleMap.put(bundle, app);
155                 getDeploymentManager().addApp(app);               
156                 return true;
157             }
158 
159             //does the bundle define a OSGiWebappConstants.RFC66_WEB_CONTEXTPATH
160             if (headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH) != null)
161             {
162                 //Could be a static webapp with no web.xml
163                 String base = ".";
164                 contextPath = (String)headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
165                 String originId = getOriginId(bundle,base);
166                 
167                 OSGiApp app = new OSGiApp(getDeploymentManager(), this, bundle, originId);
168                 app.setContextPath(contextPath);
169                 app.setWebAppPath(base);
170                 _bundleMap.put(bundle, app);
171                 getDeploymentManager().addApp(app);                
172                 return true;
173             }
174 
175             return false;
176         }
177         catch (Exception e)
178         {
179             
180             throw e;
181         }
182         finally
183         {
184             Thread.currentThread().setContextClassLoader(cl);
185         }
186     }
187 
188     
189     /* ------------------------------------------------------------ */
190     /** 
191      * Bundle has been removed. If it was a webapp we deployed, undeploy it.
192      * @param bundle
193      * 
194      * @return true if this was a webapp we had deployed, false otherwise
195      */
196     public boolean bundleRemoved (Bundle bundle) throws Exception
197     {
198         App app = _bundleMap.remove(bundle);
199         if (app != null)
200         {
201             getDeploymentManager().removeApp(app); 
202             return true;
203         }
204         return false;
205     }
206     
207    
208 
209     
210     
211     /* ------------------------------------------------------------ */
212     private static String getContextPath(Bundle bundle)
213     {
214         Dictionary<?, ?> headers = bundle.getHeaders();
215         String contextPath = (String) headers.get(OSGiWebappConstants.RFC66_WEB_CONTEXTPATH);
216         if (contextPath == null)
217         {
218             // extract from the last token of the bundle's location:
219             // (really ?could consider processing the symbolic name as an alternative
220             // the location will often reflect the version.
221             // maybe this is relevant when the file is a war)
222             String location = bundle.getLocation();
223             String toks[] = location.replace('\\', '/').split("/");
224             contextPath = toks[toks.length - 1];
225             // remove .jar, .war etc:
226             int lastDot = contextPath.lastIndexOf('.');
227             if (lastDot != -1)
228                 contextPath = contextPath.substring(0, lastDot);
229         }
230         if (!contextPath.startsWith("/"))
231             contextPath = "/" + contextPath;
232  
233         return contextPath;
234     }
235     
236     
237 
238 }