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