1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.eclipse.jetty.osgi.boot;
16
17 import java.io.File;
18 import java.io.FilenameFilter;
19 import java.io.IOException;
20 import java.util.HashSet;
21 import java.util.Iterator;
22 import java.util.Map.Entry;
23 import java.util.Set;
24
25 import org.eclipse.jetty.deploy.App;
26 import org.eclipse.jetty.deploy.AppProvider;
27 import org.eclipse.jetty.deploy.DeploymentManager;
28 import org.eclipse.jetty.deploy.providers.ContextProvider;
29 import org.eclipse.jetty.deploy.providers.ScanningAppProvider;
30 import org.eclipse.jetty.osgi.boot.utils.internal.PackageAdminServiceTracker;
31 import org.eclipse.jetty.server.handler.ContextHandler;
32 import org.eclipse.jetty.util.Scanner;
33 import org.eclipse.jetty.util.log.Log;
34 import org.eclipse.jetty.util.log.Logger;
35 import org.eclipse.jetty.util.resource.Resource;
36 import org.eclipse.jetty.webapp.WebAppContext;
37 import org.osgi.framework.Bundle;
38 import org.osgi.framework.BundleContext;
39 import org.osgi.framework.BundleException;
40 import org.osgi.framework.Constants;
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 public class OSGiAppProvider extends ScanningAppProvider implements AppProvider
63 {
64 private static final Logger LOG = Log.getLogger(OSGiAppProvider.class);
65
66 private boolean _extractWars = true;
67
68 private boolean _parentLoaderPriority = false;
69
70 private String _defaultsDescriptor;
71
72 private String _tldBundles;
73
74 private String[] _configurationClasses;
75
76 private boolean _autoInstallOSGiBundles = true;
77
78
79
80
81 Set<Bundle> _pendingBundlesToStart = null;
82
83
84
85
86
87 private static class Filter implements FilenameFilter
88 {
89 OSGiAppProvider _enclosedInstance;
90
91 public boolean accept(File dir, String name)
92 {
93 File file = new File(dir, name);
94 if (fileMightBeAnOSGiBundle(file)) { return true; }
95 if (!file.isDirectory())
96 {
97 String contextName = getDeployedAppName(name);
98 if (contextName != null)
99 {
100 App app = _enclosedInstance.getDeployedApps().get(contextName);
101 return app != null;
102 }
103 }
104 return false;
105 }
106 }
107
108
109
110
111
112
113 private static String getDeployedAppName(String contextFileName)
114 {
115 String lowername = contextFileName.toLowerCase();
116 if (lowername.endsWith(".xml"))
117 {
118 String contextName = contextFileName.substring(0, lowername.length() - ".xml".length());
119 return contextName;
120 }
121 return null;
122 }
123
124
125
126
127
128
129
130
131 private String getContextHandlerAppName(ContextHandler context)
132 {
133 String appName = context.getDisplayName();
134 if (appName == null || appName.length() == 0 || getDeployedApps().containsKey(appName))
135 {
136 if (context instanceof WebAppContext)
137 {
138 appName = ((WebAppContext) context).getContextPath();
139 if (getDeployedApps().containsKey(appName))
140 {
141 appName = "noDisplayName" + context.getClass().getSimpleName() + context.hashCode();
142 }
143 }
144 else
145 {
146 appName = "noDisplayName" + context.getClass().getSimpleName() + context.hashCode();
147 }
148 }
149 return appName;
150 }
151
152
153
154
155
156 public OSGiAppProvider()
157 {
158 super(new Filter());
159 ((Filter) super._filenameFilter)._enclosedInstance = this;
160 }
161
162
163
164
165
166
167
168 public OSGiAppProvider(File contextsDir) throws IOException
169 {
170 this();
171 setMonitoredDirResource(Resource.newResource(contextsDir.toURI()));
172 }
173
174
175
176
177
178
179 public ContextHandler createContextHandler(App app) throws Exception
180 {
181
182 ContextHandler wah = app.getContextHandler();
183 if (wah == null)
184 {
185
186
187
188
189 throw new IllegalStateException("The App must be passed the " + "instance of the ContextHandler when it is constructed");
190 }
191 if (_configurationClasses != null && wah instanceof WebAppContext)
192 {
193 ((WebAppContext) wah).setConfigurationClasses(_configurationClasses);
194 }
195
196 if (_defaultsDescriptor != null)
197 ((WebAppContext) wah).setDefaultsDescriptor(_defaultsDescriptor);
198 return app.getContextHandler();
199 }
200
201
202
203
204 @Override
205 public void setDeploymentManager(DeploymentManager deploymentManager)
206 {
207 super.setDeploymentManager(deploymentManager);
208 }
209
210 private static String getOriginId(Bundle contributor, String pathInBundle)
211 {
212 return contributor.getSymbolicName() + "-" + contributor.getVersion().toString() + (pathInBundle.startsWith("/") ? pathInBundle : "/" + pathInBundle);
213 }
214
215
216
217
218
219 public void addContext(Bundle contributor, String pathInBundle, ContextHandler context) throws Exception
220 {
221 addContext(getOriginId(contributor, pathInBundle), context);
222 }
223
224
225
226
227
228 public void addContext(String originId, ContextHandler context) throws Exception
229 {
230
231 if (context instanceof WebAppContext)
232 {
233 ((WebAppContext) context).setExtractWAR(isExtract());
234 }
235
236
237 App app = new App(getDeploymentManager(), this, originId, context);
238 String appName = getContextHandlerAppName(context);
239 getDeployedApps().put(appName, app);
240 getDeploymentManager().addApp(app);
241 }
242
243
244
245
246
247
248
249
250
251
252 @Override
253 protected App createApp(String filename)
254 {
255
256
257
258 String name = getDeployedAppName(filename);
259 if (name != null) { return getDeployedApps().get(name); }
260 return null;
261 }
262
263 public void removeContext(ContextHandler context) throws Exception
264 {
265 String appName = getContextHandlerAppName(context);
266 App app = getDeployedApps().remove(context.getDisplayName());
267 if (app == null)
268 {
269
270
271 appName = null;
272 for (Entry<String, App> deployedApp : getDeployedApps().entrySet())
273 {
274 if (deployedApp.getValue().getContextHandler() == context)
275 {
276 app = deployedApp.getValue();
277 appName = deployedApp.getKey();
278 break;
279 }
280 }
281 if (appName != null)
282 {
283 getDeployedApps().remove(appName);
284 }
285 }
286 if (app != null)
287 {
288 getDeploymentManager().removeApp(app);
289 }
290 }
291
292
293
294
295
296
297
298
299 public boolean isParentLoaderPriority()
300 {
301 return _parentLoaderPriority;
302 }
303
304
305
306
307
308
309
310 public void setParentLoaderPriority(boolean parentLoaderPriority)
311 {
312 _parentLoaderPriority = parentLoaderPriority;
313 }
314
315
316
317
318
319
320
321 public String getDefaultsDescriptor()
322 {
323 return _defaultsDescriptor;
324 }
325
326
327
328
329
330
331
332 public void setDefaultsDescriptor(String defaultsDescriptor)
333 {
334 _defaultsDescriptor = defaultsDescriptor;
335 }
336
337
338
339
340
341 public File getContextXmlDirAsFile()
342 {
343 try
344 {
345 Resource monitoredDir = getMonitoredDirResource();
346 if (monitoredDir == null) return null;
347 return monitoredDir.getFile();
348 }
349 catch (IOException e)
350 {
351 LOG.warn(e);
352 return null;
353 }
354 }
355
356
357
358
359
360
361 public String getContextXmlDir()
362 {
363 try
364 {
365 Resource monitoredDir = getMonitoredDirResource();
366 if (monitoredDir == null) return null;
367 return monitoredDir.getFile().toURI().toString();
368 }
369 catch (IOException e)
370 {
371 LOG.warn(e);
372 return null;
373 }
374 }
375
376 public boolean isExtract()
377 {
378 return _extractWars;
379 }
380
381 public void setExtract(boolean extract)
382 {
383 _extractWars = extract;
384 }
385
386
387
388
389
390
391 public boolean isAutoInstallOSGiBundles()
392 {
393 return _autoInstallOSGiBundles;
394 }
395
396
397
398
399
400
401 public void setAutoInstallOSGiBundles(boolean installingOSGiBundles)
402 {
403 _autoInstallOSGiBundles = installingOSGiBundles;
404 }
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422 public void setContextXmlDir(String contextsDir)
423 {
424 setMonitoredDirName(contextsDir);
425 }
426
427
428
429
430
431 public void setTldBundles(String tldBundles)
432 {
433 _tldBundles = tldBundles;
434 }
435
436
437
438
439
440 public String getTldBundles()
441 {
442 return _tldBundles;
443 }
444
445
446
447
448 public void setConfigurationClasses(String[] configurations)
449 {
450 _configurationClasses = configurations == null ? null : (String[]) configurations.clone();
451 }
452
453
454
455
456
457 public String[] getConfigurationClasses()
458 {
459 return _configurationClasses;
460 }
461
462
463
464
465 @Override
466 protected void doStart() throws Exception
467 {
468 if (isAutoInstallOSGiBundles())
469 {
470 if (getMonitoredDirResource() == null)
471 {
472 setAutoInstallOSGiBundles(false);
473 LOG.info("Disable autoInstallOSGiBundles as there is not contexts folder to monitor.");
474 }
475 else
476 {
477 File scandir = null;
478 try
479 {
480 scandir = getMonitoredDirResource().getFile();
481 if (!scandir.exists() || !scandir.isDirectory())
482 {
483 setAutoInstallOSGiBundles(false);
484 LOG.warn("Disable autoInstallOSGiBundles as the contexts folder '" + scandir.getAbsolutePath() + " does not exist.");
485 scandir = null;
486 }
487 }
488 catch (IOException ioe)
489 {
490 setAutoInstallOSGiBundles(false);
491 LOG.warn("Disable autoInstallOSGiBundles as the contexts folder '" + getMonitoredDirResource().getURI() + " does not exist.");
492 scandir = null;
493 }
494 if (scandir != null)
495 {
496 for (File file : scandir.listFiles())
497 {
498 if (fileMightBeAnOSGiBundle(file))
499 {
500 installBundle(file, false);
501 }
502 }
503 }
504 }
505 }
506 super.doStart();
507 if (isAutoInstallOSGiBundles())
508 {
509 Scanner.ScanCycleListener scanCycleListner = new AutoStartWhenFrameworkHasCompleted(this);
510 super.addScannerListener(scanCycleListner);
511 }
512 }
513
514
515
516
517
518
519
520
521 @Override
522 protected void fileAdded(String filename) throws Exception
523 {
524 File file = new File(filename);
525 if (isAutoInstallOSGiBundles() && file.exists() && fileMightBeAnOSGiBundle(file))
526 {
527 installBundle(file, true);
528 }
529 else
530 {
531 super.fileAdded(filename);
532 }
533 }
534
535
536
537
538
539 private static boolean fileMightBeAnOSGiBundle(File file)
540 {
541 if (file.isDirectory())
542 {
543 if (new File(file, "META-INF/MANIFEST.MF").exists()) { return true; }
544 }
545 else if (file.getName().endsWith(".jar")) { return true; }
546 return false;
547 }
548
549 @Override
550 protected void fileChanged(String filename) throws Exception
551 {
552 File file = new File(filename);
553 if (isAutoInstallOSGiBundles() && fileMightBeAnOSGiBundle(file))
554 {
555 updateBundle(file);
556 }
557 else
558 {
559 super.fileChanged(filename);
560 }
561 }
562
563 @Override
564 protected void fileRemoved(String filename) throws Exception
565 {
566 File file = new File(filename);
567 if (isAutoInstallOSGiBundles() && fileMightBeAnOSGiBundle(file))
568 {
569 uninstallBundle(file);
570 }
571 else
572 {
573 super.fileRemoved(filename);
574 }
575 }
576
577
578
579
580
581
582
583
584
585
586 protected Bundle getBundle(BundleContext bc, String location)
587 {
588
589
590 for (Bundle b : bc.getBundles())
591 {
592 if (b.getLocation().equals(location)) { return b; }
593 }
594 return null;
595 }
596
597 protected synchronized Bundle installBundle(File file, boolean start)
598 {
599
600 try
601 {
602 BundleContext bc = JettyBootstrapActivator.getBundleContext();
603 String location = file.toURI().toString();
604 Bundle b = getBundle(bc, location);
605 if (b == null)
606 {
607 b = bc.installBundle(location);
608 }
609 if (b == null)
610 {
611
612
613 LOG.warn("The file " + location + " is not an OSGi bundle.");
614 return null;
615 }
616 if (start && b.getHeaders().get(Constants.FRAGMENT_HOST) == null)
617 {
618
619
620 if (!PackageAdminServiceTracker.INSTANCE.frameworkHasCompletedAutostarts())
621 {
622 if (_pendingBundlesToStart == null)
623 {
624 _pendingBundlesToStart = new HashSet<Bundle>();
625 }
626 _pendingBundlesToStart.add(b);
627 return null;
628 }
629 else
630 {
631 b.start();
632 }
633 }
634 return b;
635 }
636 catch (BundleException e)
637 {
638 LOG.warn("Unable to " + (start ? "start" : "install") + " the bundle " + file.getAbsolutePath(), e);
639 }
640 return null;
641 }
642
643 protected void uninstallBundle(File file)
644 {
645 try
646 {
647 Bundle b = getBundle(JettyBootstrapActivator.getBundleContext(), file.toURI().toString());
648 b.stop();
649 b.uninstall();
650 }
651 catch (BundleException e)
652 {
653 LOG.warn("Unable to uninstall the bundle " + file.getAbsolutePath(), e);
654 }
655 }
656
657 protected void updateBundle(File file)
658 {
659 try
660 {
661 Bundle b = getBundle(JettyBootstrapActivator.getBundleContext(), file.toURI().toString());
662 if (b == null)
663 {
664 installBundle(file, true);
665 }
666 else if (b.getState() == Bundle.ACTIVE)
667 {
668 b.update();
669 }
670 else
671 {
672 b.start();
673 }
674 }
675 catch (BundleException e)
676 {
677 LOG.warn("Unable to update the bundle " + file.getAbsolutePath(), e);
678 }
679 }
680
681 }
682
683
684
685
686
687 class AutoStartWhenFrameworkHasCompleted implements Scanner.ScanCycleListener
688 {
689 private static final Logger LOG = Log.getLogger(AutoStartWhenFrameworkHasCompleted.class);
690
691 private final OSGiAppProvider _appProvider;
692
693 AutoStartWhenFrameworkHasCompleted(OSGiAppProvider appProvider)
694 {
695 _appProvider = appProvider;
696 }
697
698 public void scanStarted(int cycle) throws Exception
699 {
700 }
701
702 public void scanEnded(int cycle) throws Exception
703 {
704 if (_appProvider._pendingBundlesToStart != null && PackageAdminServiceTracker.INSTANCE.frameworkHasCompletedAutostarts())
705 {
706 Iterator<Bundle> it = _appProvider._pendingBundlesToStart.iterator();
707 while (it.hasNext())
708 {
709 Bundle b = it.next();
710 if (b.getHeaders().get(Constants.FRAGMENT_HOST) != null)
711 {
712 continue;
713 }
714 try
715 {
716 b.start();
717 }
718 catch (BundleException e)
719 {
720 LOG.warn("Unable to start the bundle " + b.getLocation(), e);
721 }
722
723 }
724 _appProvider._pendingBundlesToStart = null;
725 }
726 }
727
728 }