1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.eclipse.jetty.osgi.boot.internal.webapp;
16
17 import java.io.BufferedInputStream;
18 import java.io.File;
19 import java.io.FileInputStream;
20 import java.io.FileNotFoundException;
21 import java.io.IOException;
22 import java.io.InputStream;
23 import java.net.URL;
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.Enumeration;
27 import java.util.HashMap;
28
29 import org.eclipse.jetty.deploy.ContextDeployer;
30 import org.eclipse.jetty.osgi.boot.OSGiWebappConstants;
31 import org.eclipse.jetty.osgi.boot.internal.serverfactory.ServerInstanceWrapper;
32 import org.eclipse.jetty.osgi.boot.utils.BundleClassLoaderHelper;
33 import org.eclipse.jetty.osgi.boot.utils.BundleFileLocatorHelper;
34 import org.eclipse.jetty.osgi.boot.utils.WebappRegistrationCustomizer;
35 import org.eclipse.jetty.osgi.boot.utils.internal.DefaultBundleClassLoaderHelper;
36 import org.eclipse.jetty.osgi.boot.utils.internal.DefaultFileLocatorHelper;
37 import org.eclipse.jetty.server.handler.ContextHandler;
38 import org.eclipse.jetty.util.IO;
39 import org.eclipse.jetty.util.log.Log;
40 import org.eclipse.jetty.util.log.Logger;
41 import org.eclipse.jetty.util.resource.Resource;
42 import org.eclipse.jetty.webapp.WebAppContext;
43 import org.eclipse.jetty.xml.XmlConfiguration;
44 import org.osgi.framework.Bundle;
45 import org.osgi.framework.BundleContext;
46 import org.xml.sax.SAXException;
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64 public class WebBundleDeployerHelper implements IWebBundleDeployerHelper
65 {
66
67 private static Logger __logger = Log.getLogger(WebBundleDeployerHelper.class.getName());
68
69 private static boolean INITIALIZED = false;
70
71
72
73
74
75
76 public static BundleClassLoaderHelper BUNDLE_CLASS_LOADER_HELPER = null;
77
78
79
80
81
82 public static BundleFileLocatorHelper BUNDLE_FILE_LOCATOR_HELPER = null;
83
84
85
86
87
88
89
90
91
92
93 public static Collection<WebappRegistrationCustomizer> JSP_REGISTRATION_HELPERS = new ArrayList<WebappRegistrationCustomizer>();
94
95
96
97
98
99
100
101
102 private ServerInstanceWrapper _wrapper;
103
104 public WebBundleDeployerHelper(ServerInstanceWrapper wrapper)
105 {
106 staticInit();
107 _wrapper = wrapper;
108 }
109
110
111 public static synchronized void staticInit()
112 {
113 if (!INITIALIZED)
114 {
115 INITIALIZED = true;
116
117 try
118 {
119 BUNDLE_CLASS_LOADER_HELPER = (BundleClassLoaderHelper)Class.forName(BundleClassLoaderHelper.CLASS_NAME).newInstance();
120 }
121 catch (Throwable t)
122 {
123
124 BUNDLE_CLASS_LOADER_HELPER = new DefaultBundleClassLoaderHelper();
125 }
126
127 try
128 {
129 BUNDLE_FILE_LOCATOR_HELPER = (BundleFileLocatorHelper)Class.forName(BundleFileLocatorHelper.CLASS_NAME).newInstance();
130 }
131 catch (Throwable t)
132 {
133
134 BUNDLE_FILE_LOCATOR_HELPER = new DefaultFileLocatorHelper();
135 }
136 }
137 }
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159 public WebAppContext registerWebapplication(Bundle bundle,
160 String webappFolderPath, String contextPath, String extraClasspath,
161 String overrideBundleInstallLocation,
162 String requireTldBundle, String webXmlPath,
163 String defaultWebXmlPath, WebAppContext webAppContext) throws Exception
164 {
165 File bundleInstall = overrideBundleInstallLocation == null?BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(bundle):new File(
166 overrideBundleInstallLocation);
167 File webapp = null;
168 URL baseWebappInstallURL = null;
169 if (webappFolderPath != null && webappFolderPath.length() != 0 && !webappFolderPath.equals("."))
170 {
171 if (webappFolderPath.startsWith("/") || webappFolderPath.startsWith("file:"))
172 {
173 webapp = new File(webappFolderPath);
174 }
175 else if (bundleInstall != null && bundleInstall.isDirectory())
176 {
177 webapp = new File(bundleInstall,webappFolderPath);
178 }
179 else if (bundleInstall != null)
180 {
181 Enumeration<URL> urls = BUNDLE_FILE_LOCATOR_HELPER.findEntries(bundle, webappFolderPath);
182 if (urls != null && urls.hasMoreElements())
183 {
184 baseWebappInstallURL = urls.nextElement();
185 }
186 }
187 }
188 else
189 {
190 webapp = bundleInstall;
191 }
192 if (baseWebappInstallURL == null && (webapp == null || !webapp.exists()))
193 {
194 throw new IllegalArgumentException("Unable to locate " + webappFolderPath + " inside "
195 + (bundleInstall != null?bundleInstall.getAbsolutePath():"unlocated bundle '" + bundle.getSymbolicName() + "'"));
196 }
197 if (baseWebappInstallURL == null && webapp != null)
198 {
199 baseWebappInstallURL = webapp.toURI().toURL();
200 }
201 return registerWebapplication(bundle,webappFolderPath,baseWebappInstallURL,contextPath,
202 extraClasspath,bundleInstall,requireTldBundle,webXmlPath,defaultWebXmlPath,webAppContext);
203 }
204
205
206
207
208 private WebAppContext registerWebapplication(Bundle contributor, String pathInBundleToWebApp,
209 URL baseWebappInstallURL, String contextPath, String extraClasspath, File bundleInstall,
210 String requireTldBundle, String webXmlPath, String defaultWebXmlPath, WebAppContext context)
211 throws Exception
212 {
213
214 ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
215 String[] oldServerClasses = null;
216
217 try
218 {
219
220
221 OSGiWebappClassLoader composite = createWebappClassLoader(contributor);
222
223
224 Thread.currentThread().setContextClassLoader(composite);
225
226 context.setWar(baseWebappInstallURL.toString());
227 context.setContextPath(contextPath);
228 context.setExtraClasspath(extraClasspath);
229
230 if (webXmlPath != null && webXmlPath.length() != 0)
231 {
232 File webXml = null;
233 if (webXmlPath.startsWith("/") || webXmlPath.startsWith("file:/"))
234 {
235 webXml = new File(webXmlPath);
236 }
237 else
238 {
239 webXml = new File(bundleInstall,webXmlPath);
240 }
241 if (webXml.exists())
242 {
243 context.setDescriptor(webXml.getAbsolutePath());
244 }
245 }
246
247 if (defaultWebXmlPath == null || defaultWebXmlPath.length() == 0)
248 {
249
250 defaultWebXmlPath = _wrapper.getOSGiAppProvider().getDefaultsDescriptor();
251 }
252 if (defaultWebXmlPath != null && defaultWebXmlPath.length() != 0)
253 {
254 File defaultWebXml = null;
255 if (defaultWebXmlPath.startsWith("/") || defaultWebXmlPath.startsWith("file:/"))
256 {
257 defaultWebXml = new File(webXmlPath);
258 }
259 else
260 {
261 defaultWebXml = new File(bundleInstall,defaultWebXmlPath);
262 }
263 if (defaultWebXml.exists())
264 {
265 context.setDefaultsDescriptor(defaultWebXml.getAbsolutePath());
266 }
267 }
268
269
270 context.setParentLoaderPriority(_wrapper.getOSGiAppProvider().isParentLoaderPriority());
271
272 configureWebAppContext(context,contributor,requireTldBundle);
273 configureWebappClassLoader(contributor,context,composite);
274
275
276
277
278
279
280 oldServerClasses = context.getServerClasses();
281 context.setServerClasses(null);
282
283 _wrapper.getOSGiAppProvider().addContext(contributor,pathInBundleToWebApp,context);
284
285 return context;
286 }
287 finally
288 {
289 if (context != null && oldServerClasses != null)
290 {
291 context.setServerClasses(oldServerClasses);
292 }
293 Thread.currentThread().setContextClassLoader(contextCl);
294 }
295
296 }
297
298
299
300
301 public void unregister(ContextHandler contextHandler) throws Exception
302 {
303 _wrapper.getOSGiAppProvider().removeContext(contextHandler);
304 }
305
306
307
308
309 public ContextHandler registerContext(Bundle contributor, String contextFileRelativePath, String extraClasspath,
310 String overrideBundleInstallLocation, String requireTldBundle, ContextHandler handler)
311 throws Exception
312 {
313 File contextsHome = _wrapper.getOSGiAppProvider().getContextXmlDirAsFile();
314 if (contextsHome != null)
315 {
316 File prodContextFile = new File(contextsHome,contributor.getSymbolicName() + "/" + contextFileRelativePath);
317 if (prodContextFile.exists())
318 {
319 return registerContext(contributor,contextFileRelativePath,prodContextFile,extraClasspath,
320 overrideBundleInstallLocation,requireTldBundle,handler);
321 }
322 }
323 File rootFolder = overrideBundleInstallLocation != null
324 ? Resource.newResource(overrideBundleInstallLocation).getFile()
325 : BUNDLE_FILE_LOCATOR_HELPER.getBundleInstallLocation(contributor);
326 File contextFile = rootFolder != null?new File(rootFolder,contextFileRelativePath):null;
327 if (contextFile != null && contextFile.exists())
328 {
329 return registerContext(contributor,contextFileRelativePath,contextFile,extraClasspath,overrideBundleInstallLocation,requireTldBundle,handler);
330 }
331 else
332 {
333 if (contextFileRelativePath.startsWith("./"))
334 {
335 contextFileRelativePath = contextFileRelativePath.substring(1);
336 }
337 if (!contextFileRelativePath.startsWith("/"))
338 {
339 contextFileRelativePath = "/" + contextFileRelativePath;
340 }
341
342 URL contextURL = contributor.getEntry(contextFileRelativePath);
343 if (contextURL != null)
344 {
345 return registerContext(contributor,contextFileRelativePath,contextURL.openStream(),extraClasspath,overrideBundleInstallLocation,requireTldBundle,handler);
346 }
347 throw new IllegalArgumentException("Could not find the context " + "file " + contextFileRelativePath + " for the bundle "
348 + contributor.getSymbolicName() + (overrideBundleInstallLocation != null?" using the install location " + overrideBundleInstallLocation:""));
349 }
350 }
351
352
353
354
355
356
357
358
359
360
361
362 private ContextHandler registerContext(Bundle contributor, String pathInBundle, File contextFile,
363 String extraClasspath, String overrideBundleInstallLocation,
364 String requireTldBundle, ContextHandler handler) throws Exception
365 {
366 InputStream contextFileInputStream = null;
367 try
368 {
369 contextFileInputStream = new BufferedInputStream(new FileInputStream(contextFile));
370 return registerContext(contributor, pathInBundle, contextFileInputStream,
371 extraClasspath,overrideBundleInstallLocation,requireTldBundle,handler);
372 }
373 finally
374 {
375 IO.close(contextFileInputStream);
376 }
377 }
378
379
380
381
382
383
384
385
386 private ContextHandler registerContext(Bundle contributor,
387 String pathInsideBundle, InputStream contextFileInputStream,
388 String extraClasspath, String overrideBundleInstallLocation,
389 String requireTldBundle, ContextHandler handler)
390 throws Exception
391 {
392 ClassLoader contextCl = Thread.currentThread().getContextClassLoader();
393 String[] oldServerClasses = null;
394 WebAppContext webAppContext = null;
395 try
396 {
397
398
399 OSGiWebappClassLoader composite = createWebappClassLoader(contributor);
400
401
402
403 Thread.currentThread().setContextClassLoader(composite);
404 ContextHandler context = createContextHandler(handler, contributor,
405 contextFileInputStream,extraClasspath,
406 overrideBundleInstallLocation,requireTldBundle);
407 if (context == null)
408 {
409 return null;
410 }
411
412
413
414
415
416
417
418 configureWebappClassLoader(contributor,context,composite);
419 if (context instanceof WebAppContext)
420 {
421 webAppContext = (WebAppContext)context;
422
423
424 oldServerClasses = webAppContext.getServerClasses();
425 webAppContext.setServerClasses(null);
426 }
427 _wrapper.getOSGiAppProvider().addContext(contributor, pathInsideBundle, context);
428 return context;
429 }
430 finally
431 {
432 if (webAppContext != null)
433 {
434 webAppContext.setServerClasses(oldServerClasses);
435 }
436 Thread.currentThread().setContextClassLoader(contextCl);
437 }
438
439 }
440
441
442
443
444
445
446
447 protected void configureWebAppContext(ContextHandler wah, Bundle contributor,
448 String requireTldBundle)
449 {
450
451 wah.setAttribute(OSGiWebappConstants.RFC66_OSGI_BUNDLE_CONTEXT,contributor.getBundleContext());
452
453
454
455
456
457 wah.setAttribute("org.springframework.osgi.web." + BundleContext.class.getName(),
458 contributor.getBundleContext());
459
460
461
462 wah.setAttribute(OSGiWebappConstants.JETTY_OSGI_BUNDLE, contributor);
463
464
465
466 wah.setAttribute(OSGiWebappConstants.REQUIRE_TLD_BUNDLE, requireTldBundle);
467
468
469 }
470
471
472
473
474
475
476 protected ContextHandler createContextHandler(ContextHandler handlerToConfigure,
477 Bundle bundle, File contextFile, String extraClasspath,
478 String overrideBundleInstallLocation, String requireTldBundle)
479 {
480 try
481 {
482 return createContextHandler(handlerToConfigure,bundle,
483 new BufferedInputStream(new FileInputStream(contextFile)),
484 extraClasspath,overrideBundleInstallLocation,requireTldBundle);
485 }
486 catch (FileNotFoundException e)
487 {
488 e.printStackTrace();
489 }
490 return null;
491 }
492
493
494
495
496
497
498 @SuppressWarnings("unchecked")
499 protected ContextHandler createContextHandler(ContextHandler handlerToConfigure,
500 Bundle bundle, InputStream contextInputStream, String extraClasspath,
501 String overrideBundleInstallLocation, String requireTldBundle)
502 {
503
504
505
506
507
508
509
510
511
512
513
514 try
515 {
516 XmlConfiguration xmlConfiguration = new XmlConfiguration(contextInputStream);
517 HashMap properties = new HashMap();
518 properties.put("Server",_wrapper.getServer());
519
520
521 setThisBundleHomeProperty(bundle,properties,overrideBundleInstallLocation);
522 xmlConfiguration.setProperties(properties);
523
524 ContextHandler context = null;
525 if (handlerToConfigure == null)
526 {
527 context = (ContextHandler)xmlConfiguration.configure();
528 }
529 else
530 {
531 xmlConfiguration.configure(handlerToConfigure);
532 context = handlerToConfigure;
533 }
534
535 if (context instanceof WebAppContext)
536 {
537 ((WebAppContext)context).setExtraClasspath(extraClasspath);
538 ((WebAppContext)context).setParentLoaderPriority(_wrapper.getOSGiAppProvider().isParentLoaderPriority());
539 if (_wrapper.getOSGiAppProvider().getDefaultsDescriptor() != null && _wrapper.getOSGiAppProvider().getDefaultsDescriptor().length() != 0)
540 {
541 ((WebAppContext)context).setDefaultsDescriptor(_wrapper.getOSGiAppProvider().getDefaultsDescriptor());
542 }
543 }
544
545
546 configureWebAppContext(context, bundle, requireTldBundle);
547 return context;
548 }
549 catch (FileNotFoundException e)
550 {
551 return null;
552 }
553 catch (SAXException e)
554 {
555
556 e.printStackTrace();
557 }
558 catch (IOException e)
559 {
560
561 e.printStackTrace();
562 }
563 catch (Throwable e)
564 {
565
566 e.printStackTrace();
567 }
568 finally
569 {
570 IO.close(contextInputStream);
571 }
572 return null;
573 }
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604 protected void configureWebappClassLoader(Bundle contributor, ContextHandler context, OSGiWebappClassLoader webappClassLoader) throws Exception
605 {
606 if (context instanceof WebAppContext)
607 {
608 WebAppContext webappCtxt = (WebAppContext)context;
609 context.setClassLoader(webappClassLoader);
610 webappClassLoader.setWebappContext(webappCtxt);
611 }
612 else
613 {
614 context.setClassLoader(webappClassLoader);
615 }
616 }
617
618
619
620
621 protected OSGiWebappClassLoader createWebappClassLoader(Bundle contributor) throws Exception
622 {
623
624
625
626 OSGiWebappClassLoader webappClassLoader = new OSGiWebappClassLoader(
627 _wrapper.getParentClassLoaderForWebapps(),new WebAppContext(),contributor,BUNDLE_CLASS_LOADER_HELPER);
628 return webappClassLoader;
629 }
630
631
632
633
634
635
636 private void setThisBundleHomeProperty(Bundle bundle, HashMap<String, Object> properties, String overrideBundleInstallLocation)
637 {
638 try
639 {
640 File location = overrideBundleInstallLocation != null?new File(overrideBundleInstallLocation):BUNDLE_FILE_LOCATOR_HELPER
641 .getBundleInstallLocation(bundle);
642 properties.put("this.bundle.install",location.getCanonicalPath());
643 properties.put("this.bundle.install.url",bundle.getEntry("/").toString());
644 }
645 catch (Throwable t)
646 {
647 __logger.warn("Unable to set 'this.bundle.install' " + " for the bundle " + bundle.getSymbolicName(), t);
648 }
649 }
650
651
652 }