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