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