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