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