1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.Enumeration;
25 import java.util.HashMap;
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.OSGiWebappClassLoader;
32 import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelperFactory;
33 import org.eclipse.jetty.server.handler.ContextHandler;
34 import org.eclipse.jetty.util.component.AbstractLifeCycle;
35 import org.eclipse.jetty.util.log.Log;
36 import org.eclipse.jetty.util.log.Logger;
37 import org.eclipse.jetty.util.resource.JarResource;
38 import org.eclipse.jetty.util.resource.Resource;
39 import org.eclipse.jetty.webapp.WebAppContext;
40 import org.eclipse.jetty.xml.XmlConfiguration;
41 import org.osgi.framework.Bundle;
42 import org.osgi.framework.BundleContext;
43 import org.osgi.framework.ServiceReference;
44 import org.osgi.service.packageadmin.PackageAdmin;
45
46
47
48
49
50
51
52
53
54
55
56 public abstract class AbstractWebAppProvider extends AbstractLifeCycle implements AppProvider
57 {
58 private static final Logger LOG = Log.getLogger(AbstractWebAppProvider.class);
59
60 public static String __defaultConfigurations[] = {
61 "org.eclipse.jetty.osgi.boot.OSGiWebInfConfiguration",
62 "org.eclipse.jetty.webapp.WebXmlConfiguration",
63 "org.eclipse.jetty.webapp.MetaInfConfiguration",
64 "org.eclipse.jetty.webapp.FragmentConfiguration",
65 "org.eclipse.jetty.webapp.JettyWebXmlConfiguration"
66 };
67
68 public static void setDefaultConfigurations (String[] defaultConfigs)
69 {
70 __defaultConfigurations = defaultConfigs;
71 }
72
73 public static String[] getDefaultConfigurations ()
74 {
75 return __defaultConfigurations;
76 }
77
78
79 private boolean _parentLoaderPriority;
80
81 private String _defaultsDescriptor;
82
83 private boolean _extractWars = true;
84
85 private String _tldBundles;
86
87 private DeploymentManager _deploymentManager;
88
89 private String[] _configurationClasses;
90
91 private ServerInstanceWrapper _serverWrapper;
92
93
94
95
96
97
98
99 public class OSGiApp extends AbstractOSGiApp
100 {
101 private String _contextPath;
102 private String _webAppPath;
103 private WebAppContext _webApp;
104
105 public OSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, String originId)
106 {
107 super(manager, provider, bundle, originId);
108 }
109
110 public OSGiApp(DeploymentManager manager, AppProvider provider, Bundle bundle, Dictionary properties, String originId)
111 {
112 super(manager, provider, bundle, properties, originId);
113 }
114
115 public void setWebAppContext (WebAppContext webApp)
116 {
117 _webApp = webApp;
118 }
119
120 public String getContextPath()
121 {
122 return _contextPath;
123 }
124
125 public void setContextPath(String contextPath)
126 {
127 this._contextPath = contextPath;
128 }
129
130 public String getBundlePath()
131 {
132 return _webAppPath;
133 }
134
135 public void setWebAppPath(String path)
136 {
137 this._webAppPath = path;
138 }
139
140
141 public ContextHandler createContextHandler()
142 throws Exception
143 {
144 if (_webApp != null)
145 {
146 configureWebApp();
147 return _webApp;
148 }
149
150 createWebApp();
151 return _webApp;
152 }
153
154
155
156 protected void createWebApp ()
157 throws Exception
158 {
159 _webApp = newWebApp();
160 configureWebApp();
161 }
162
163 protected WebAppContext newWebApp ()
164 {
165 WebAppContext webApp = new WebAppContext();
166 webApp.setAttribute(OSGiWebappConstants.WATERMARK, OSGiWebappConstants.WATERMARK);
167
168
169 String[] targets = webApp.getProtectedTargets();
170 String[] updatedTargets = null;
171 if (targets != null)
172 {
173 updatedTargets = new String[targets.length+OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length];
174 System.arraycopy(targets, 0, updatedTargets, 0, targets.length);
175 }
176 else
177 updatedTargets = new String[OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length];
178 System.arraycopy(OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS, 0, updatedTargets, targets.length, OSGiWebappConstants.DEFAULT_PROTECTED_OSGI_TARGETS.length);
179 webApp.setProtectedTargets(updatedTargets);
180
181 return webApp;
182 }
183
184
185 public void configureWebApp()
186 throws Exception
187 {
188
189 _webApp.setContextPath(_contextPath);
190
191
192 _webApp.setAttribute(OSGiWebappConstants.OSGI_BUNDLECONTEXT, _bundle.getBundleContext());
193
194 String overrideBundleInstallLocation = (String)_properties.get(OSGiWebappConstants.JETTY_BUNDLE_INSTALL_LOCATION_OVERRIDE);
195 File bundleInstallLocation =
196 (overrideBundleInstallLocation == null
197 ? BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(_bundle)
198 : new File(overrideBundleInstallLocation));
199 URL url = null;
200 Resource rootResource = Resource.newResource(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(bundleInstallLocation.toURI().toURL()));
201
202 if (rootResource.exists()&& !rootResource.isDirectory() && !rootResource.toString().startsWith("jar:"))
203 {
204 Resource jarResource = JarResource.newJarResource(rootResource);
205 if (jarResource.exists() && jarResource.isDirectory())
206 rootResource = jarResource;
207 }
208
209
210 if (_webAppPath == null || _webAppPath.length() == 0 || ".".equals(_webAppPath))
211 {
212 url = bundleInstallLocation.toURI().toURL();
213 }
214 else
215 {
216
217 if (_webAppPath.startsWith("/") || _webAppPath.startsWith("file:"))
218 {
219 url = new File(_webAppPath).toURI().toURL();
220 }
221 else if (bundleInstallLocation != null && bundleInstallLocation.isDirectory())
222 {
223 url = new File(bundleInstallLocation, _webAppPath).toURI().toURL();
224 }
225 else if (bundleInstallLocation != null)
226 {
227 Enumeration<URL> urls = BundleFileLocatorHelperFactory.getFactory().getHelper().findEntries(_bundle, _webAppPath);
228 if (urls != null && urls.hasMoreElements())
229 url = urls.nextElement();
230 }
231 }
232
233 if (url == null)
234 {
235 throw new IllegalArgumentException("Unable to locate " + _webAppPath
236 + " in "
237 + (bundleInstallLocation != null ? bundleInstallLocation.getAbsolutePath() : "unlocated bundle '" + _bundle.getSymbolicName()+ "'"));
238 }
239
240
241
242 _webApp.setWar(BundleFileLocatorHelperFactory.getFactory().getHelper().getLocalURL(url).toString());
243
244
245 _webApp.setParentLoaderPriority(isParentLoaderPriority());
246 _webApp.setExtractWAR(isExtract());
247 if (getConfigurationClasses() != null)
248 _webApp.setConfigurationClasses(getConfigurationClasses());
249 else
250 _webApp.setConfigurationClasses(__defaultConfigurations);
251
252 if (getDefaultsDescriptor() != null)
253 _webApp.setDefaultsDescriptor(getDefaultsDescriptor());
254
255
256
257 String tmp = (String)_properties.get(OSGiWebappConstants.JETTY_EXTRA_CLASSPATH);
258 if (tmp != null)
259 _webApp.setExtraClasspath(tmp);
260
261
262 tmp = (String)_properties.get(OSGiWebappConstants.JETTY_WEB_XML_PATH);
263 if (tmp != null && tmp.trim().length() != 0)
264 {
265 File webXml = getFile (tmp, bundleInstallLocation);
266 if (webXml != null && webXml.exists())
267 _webApp.setDescriptor(webXml.getAbsolutePath());
268 }
269
270
271 tmp = (String)_properties.get(OSGiWebappConstants.JETTY_DEFAULT_WEB_XML_PATH);
272 if (tmp != null)
273 {
274 File defaultWebXml = getFile (tmp, bundleInstallLocation);
275 if (defaultWebXml != null)
276 {
277 if (defaultWebXml.exists())
278 _webApp.setDefaultsDescriptor(defaultWebXml.getAbsolutePath());
279 else
280 LOG.warn(defaultWebXml.getAbsolutePath()+" does not exist");
281 }
282 }
283
284
285
286
287 String requireTldBundles = (String)_properties.get(OSGiWebappConstants.REQUIRE_TLD_BUNDLE);
288 String pathsToTldBundles = getPathsToRequiredBundles(requireTldBundles);
289
290
291
292
293 OSGiWebappClassLoader webAppLoader = new OSGiWebappClassLoader(_serverWrapper.getParentClassLoaderForWebapps(), _webApp, _bundle);
294
295 if (pathsToTldBundles != null)
296 webAppLoader.addClassPath(pathsToTldBundles);
297 _webApp.setClassLoader(webAppLoader);
298
299
300
301
302 applyMetaInfContextXml(rootResource);
303
304
305
306 _webApp.setAttribute(OSGiWebappConstants.REQUIRE_TLD_BUNDLE, requireTldBundles);
307
308
309
310 _webApp.setAttribute(OSGiWebappConstants.RFC66_OSGI_BUNDLE_CONTEXT, _bundle.getBundleContext());
311
312
313
314
315
316 _webApp.setAttribute("org.springframework.osgi.web." + BundleContext.class.getName(), _bundle.getBundleContext());
317
318
319
320
321
322 _webApp.setAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE, _bundle);
323 }
324
325 protected String getPathsToRequiredBundles (String requireTldBundles)
326 throws Exception
327 {
328 if (requireTldBundles == null) return null;
329
330 ServiceReference ref = _bundle.getBundleContext().getServiceReference(org.osgi.service.packageadmin.PackageAdmin.class.getName());
331 PackageAdmin packageAdmin = (ref == null) ? null : (PackageAdmin)_bundle.getBundleContext().getService(ref);
332 if (packageAdmin == null)
333 throw new IllegalStateException("Unable to get PackageAdmin reference to locate required Tld bundles");
334
335 StringBuilder paths = new StringBuilder();
336 String[] symbNames = requireTldBundles.split(", ");
337
338 for (String symbName : symbNames)
339 {
340 Bundle[] bs = packageAdmin.getBundles(symbName, null);
341 if (bs == null || bs.length == 0)
342 {
343 throw new IllegalArgumentException("Unable to locate the bundle '" + symbName
344 + "' specified by "
345 + OSGiWebappConstants.REQUIRE_TLD_BUNDLE
346 + " in manifest of "
347 + (_bundle == null ? "unknown" : _bundle.getSymbolicName()));
348 }
349
350 File f = BundleFileLocatorHelperFactory.getFactory().getHelper().getBundleInstallLocation(bs[0]);
351 if (paths.length() > 0) paths.append(", ");
352 paths.append(f.toURI().toURL().toString());
353 LOG.debug("getPathsToRequiredBundles: bundle path=" + bs[0].getLocation() + " uri=" + f.toURI());
354 }
355
356 return paths.toString();
357 }
358
359
360 protected void applyMetaInfContextXml(Resource rootResource)
361 throws Exception
362 {
363 if (_bundle == null) return;
364 if (_webApp == null) return;
365
366 ClassLoader cl = Thread.currentThread().getContextClassLoader();
367 LOG.debug("Context classloader = " + cl);
368 try
369 {
370
371 Thread.currentThread().setContextClassLoader(_webApp.getClassLoader());
372
373
374
375 URL contextXmlUrl = _bundle.getEntry("/META-INF/jetty-webapp-context.xml");
376 if (contextXmlUrl == null) return;
377
378
379 LOG.info("Applying " + contextXmlUrl + " to " + _webApp);
380
381 XmlConfiguration xmlConfiguration = new XmlConfiguration(contextXmlUrl);
382 HashMap properties = new HashMap();
383 properties.put("Server", getDeploymentManager().getServer());
384 properties.put(OSGiWebappConstants.JETTY_BUNDLE_ROOT, rootResource.toString());
385 properties.put(OSGiServerConstants.JETTY_HOME, getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME));
386 xmlConfiguration.getProperties().putAll(properties);
387 xmlConfiguration.configure(_webApp);
388 }
389 finally
390 {
391 Thread.currentThread().setContextClassLoader(cl);
392 }
393 }
394
395 private File getFile (String file, File bundleInstall)
396 {
397 if (file == null)
398 return null;
399
400 if (file.startsWith("/") || file.startsWith("file:/"))
401 return new File(file);
402 else
403 {
404
405
406 File f = new File (bundleInstall, file);
407 if (f.exists()) return f;
408 String jettyHome = (String)getDeploymentManager().getServer().getAttribute(OSGiServerConstants.JETTY_HOME);
409 if (jettyHome != null)
410 return new File(jettyHome, file);
411 }
412
413 return null;
414 }
415 }
416
417
418 public AbstractWebAppProvider (ServerInstanceWrapper wrapper)
419 {
420 _serverWrapper = wrapper;
421 }
422
423
424
425
426
427
428
429
430
431 public boolean isParentLoaderPriority()
432 {
433 return _parentLoaderPriority;
434 }
435
436
437
438
439
440
441
442 public void setParentLoaderPriority(boolean parentLoaderPriority)
443 {
444 _parentLoaderPriority = parentLoaderPriority;
445 }
446
447
448
449
450
451
452
453 public String getDefaultsDescriptor()
454 {
455 return _defaultsDescriptor;
456 }
457
458
459
460
461
462
463
464 public void setDefaultsDescriptor(String defaultsDescriptor)
465 {
466 _defaultsDescriptor = defaultsDescriptor;
467 }
468
469
470
471 public boolean isExtract()
472 {
473 return _extractWars;
474 }
475
476
477
478 public void setExtract(boolean extract)
479 {
480 _extractWars = extract;
481 }
482
483
484
485
486
487
488
489 public void setTldBundles(String tldBundles)
490 {
491 _tldBundles = tldBundles;
492 }
493
494
495
496
497
498
499
500 public String getTldBundles()
501 {
502 return _tldBundles;
503 }
504
505
506
507
508
509 public void setConfigurationClasses(String[] configurations)
510 {
511 _configurationClasses = configurations == null ? null : (String[]) configurations.clone();
512 }
513
514
515
516
517
518 public String[] getConfigurationClasses()
519 {
520 return _configurationClasses;
521 }
522
523
524 public void setServerInstanceWrapper(ServerInstanceWrapper wrapper)
525 {
526 _serverWrapper = wrapper;
527 }
528
529 public ServerInstanceWrapper getServerInstanceWrapper()
530 {
531 return _serverWrapper;
532 }
533
534
535
536
537
538 public DeploymentManager getDeploymentManager()
539 {
540 return _deploymentManager;
541 }
542
543
544
545
546
547 public void setDeploymentManager(DeploymentManager deploymentManager)
548 {
549 _deploymentManager = deploymentManager;
550 }
551
552
553
554 public ContextHandler createContextHandler(App app) throws Exception
555 {
556 if (app == null)
557 return null;
558 if (!(app instanceof OSGiApp))
559 throw new IllegalStateException(app+" is not a BundleApp");
560
561
562 ContextHandler ch = ((OSGiApp)app).createContextHandler();
563 return ch;
564 }
565
566
567
568 public static String getOriginId(Bundle contributor, String path)
569 {
570 return contributor.getSymbolicName() + "-" + contributor.getVersion().toString() + (path.startsWith("/") ? path : "/" + path);
571 }
572
573 }