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