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