]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.init/src/org/argeo/init/osgi/OsgiBoot.java
Use latest release of Argeo Maven parent
[lgpl/argeo-commons.git] / org.argeo.init / src / org / argeo / init / osgi / OsgiBoot.java
1 package org.argeo.init.osgi;
2
3 import static org.argeo.init.osgi.OsgiBootUtils.debug;
4 import static org.argeo.init.osgi.OsgiBootUtils.warn;
5
6 import java.io.File;
7 import java.nio.file.FileSystems;
8 import java.nio.file.Files;
9 import java.nio.file.Path;
10 import java.nio.file.PathMatcher;
11 import java.nio.file.Paths;
12 import java.util.ArrayList;
13 import java.util.HashMap;
14 import java.util.Iterator;
15 import java.util.List;
16 import java.util.Map;
17 import java.util.Properties;
18 import java.util.Set;
19 import java.util.SortedMap;
20 import java.util.StringTokenizer;
21 import java.util.TreeMap;
22
23 import org.argeo.init.a2.A2Source;
24 import org.argeo.init.a2.ProvisioningManager;
25 import org.osgi.framework.Bundle;
26 import org.osgi.framework.BundleContext;
27 import org.osgi.framework.BundleException;
28 import org.osgi.framework.FrameworkEvent;
29 import org.osgi.framework.Version;
30 import org.osgi.framework.startlevel.BundleStartLevel;
31 import org.osgi.framework.startlevel.FrameworkStartLevel;
32 import org.osgi.framework.wiring.FrameworkWiring;
33
34 /**
35 * Basic provisioning of an OSGi runtime via file path patterns and system
36 * properties. The approach is to generate list of URLs based on various
37 * methods, configured via properties.
38 */
39 public class OsgiBoot implements OsgiBootConstants {
40 public final static String PROP_ARGEO_OSGI_START = "argeo.osgi.start";
41 public final static String PROP_ARGEO_OSGI_SOURCES = "argeo.osgi.sources";
42
43 public final static String PROP_ARGEO_OSGI_BUNDLES = "argeo.osgi.bundles";
44 public final static String PROP_ARGEO_OSGI_BASE_URL = "argeo.osgi.baseUrl";
45 public final static String PROP_ARGEO_OSGI_LOCAL_CACHE = "argeo.osgi.localCache";
46 public final static String PROP_ARGEO_OSGI_DISTRIBUTION_URL = "argeo.osgi.distributionUrl";
47
48 // booleans
49 public final static String PROP_ARGEO_OSGI_BOOT_DEBUG = "argeo.osgi.boot.debug";
50 // public final static String PROP_ARGEO_OSGI_BOOT_EXCLUDE_SVN =
51 // "argeo.osgi.boot.excludeSvn";
52
53 public final static String PROP_ARGEO_OSGI_BOOT_SYSTEM_PROPERTIES_FILE = "argeo.osgi.boot.systemPropertiesFile";
54 public final static String PROP_ARGEO_OSGI_BOOT_APPCLASS = "argeo.osgi.boot.appclass";
55 public final static String PROP_ARGEO_OSGI_BOOT_APPARGS = "argeo.osgi.boot.appargs";
56
57 public final static String DEFAULT_BASE_URL = "reference:file:";
58 // public final static String EXCLUDES_SVN_PATTERN = "**/.svn/**";
59
60 // OSGi system properties
61 final static String PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL = "osgi.bundles.defaultStartLevel";
62 final static String PROP_OSGI_STARTLEVEL = "osgi.startLevel";
63 final static String INSTANCE_AREA_PROP = "osgi.instance.area";
64 final static String CONFIGURATION_AREA_PROP = "osgi.configuration.area";
65
66 // Symbolic names
67 public final static String SYMBOLIC_NAME_OSGI_BOOT = "org.argeo.osgi.boot";
68 public final static String SYMBOLIC_NAME_EQUINOX = "org.eclipse.osgi";
69
70 /** Exclude svn metadata implicitely(a bit costly) */
71 // private boolean excludeSvn =
72 // Boolean.valueOf(System.getProperty(PROP_ARGEO_OSGI_BOOT_EXCLUDE_SVN,
73 // "false"))
74 // .booleanValue();
75
76 /** Default is 10s */
77 @Deprecated
78 private long defaultTimeout = 10000l;
79
80 private final BundleContext bundleContext;
81 private final String localCache;
82
83 private final ProvisioningManager provisioningManager;
84
85 /*
86 * INITIALIZATION
87 */
88 /** Constructor */
89 public OsgiBoot(BundleContext bundleContext) {
90 this.bundleContext = bundleContext;
91 Path homePath = Paths.get(System.getProperty("user.home")).toAbsolutePath();
92 String homeUri = homePath.toUri().toString();
93 localCache = getProperty(PROP_ARGEO_OSGI_LOCAL_CACHE, homeUri + ".m2/repository/");
94
95 provisioningManager = new ProvisioningManager(bundleContext);
96 String sources = getProperty(PROP_ARGEO_OSGI_SOURCES);
97 if (sources == null) {
98 provisioningManager.registerDefaultSource();
99 } else {
100 for (String source : sources.split(",")) {
101 if (source.trim().equals(A2Source.DEFAULT_A2_URI)) {
102 if (Files.exists(homePath))
103 provisioningManager.registerSource(
104 A2Source.SCHEME_A2 + "://" + homePath.toString() + "/.local/share/osgi");
105 provisioningManager.registerSource(A2Source.SCHEME_A2 + ":///usr/local/share/osgi");
106 provisioningManager.registerSource(A2Source.SCHEME_A2 + ":///usr/share/osgi");
107 } else {
108 provisioningManager.registerSource(source);
109 }
110 }
111 }
112 }
113
114 ProvisioningManager getProvisioningManager() {
115 return provisioningManager;
116 }
117
118 /*
119 * HIGH-LEVEL METHODS
120 */
121 /** Bootstraps the OSGi runtime */
122 public void bootstrap() {
123 try {
124 long begin = System.currentTimeMillis();
125 System.out.println();
126 String osgiInstancePath = bundleContext.getProperty(INSTANCE_AREA_PROP);
127 OsgiBootUtils
128 .info("OSGi bootstrap starting" + (osgiInstancePath != null ? " (" + osgiInstancePath + ")" : ""));
129 installUrls(getBundlesUrls());
130 installUrls(getDistributionUrls());
131 provisioningManager.install(null);
132 startBundles();
133 long duration = System.currentTimeMillis() - begin;
134 OsgiBootUtils.info("OSGi bootstrap completed in " + Math.round(((double) duration) / 1000) + "s ("
135 + duration + "ms), " + bundleContext.getBundles().length + " bundles");
136 } catch (RuntimeException e) {
137 OsgiBootUtils.error("OSGi bootstrap FAILED", e);
138 throw e;
139 }
140
141 // diagnostics
142 if (OsgiBootUtils.debug) {
143 OsgiBootDiagnostics diagnostics = new OsgiBootDiagnostics(bundleContext);
144 diagnostics.checkUnresolved();
145 Map<String, Set<String>> duplicatePackages = diagnostics.findPackagesExportedTwice();
146 if (duplicatePackages.size() > 0) {
147 OsgiBootUtils.info("Packages exported twice:");
148 Iterator<String> it = duplicatePackages.keySet().iterator();
149 while (it.hasNext()) {
150 String pkgName = it.next();
151 OsgiBootUtils.info(pkgName);
152 Set<String> bdles = duplicatePackages.get(pkgName);
153 Iterator<String> bdlesIt = bdles.iterator();
154 while (bdlesIt.hasNext())
155 OsgiBootUtils.info(" " + bdlesIt.next());
156 }
157 }
158 }
159 System.out.println();
160 }
161
162 public void update() {
163 provisioningManager.update();
164 }
165
166 /*
167 * INSTALLATION
168 */
169 /** Install a single url. Convenience method. */
170 public Bundle installUrl(String url) {
171 List<String> urls = new ArrayList<String>();
172 urls.add(url);
173 installUrls(urls);
174 return (Bundle) getBundlesByLocation().get(url);
175 }
176
177 /** Install the bundles at this URL list. */
178 public void installUrls(List<String> urls) {
179 Map<String, Bundle> installedBundles = getBundlesByLocation();
180 for (int i = 0; i < urls.size(); i++) {
181 String url = (String) urls.get(i);
182 installUrl(url, installedBundles);
183 }
184 refreshFramework();
185 }
186
187 /** Actually install the provided URL */
188 protected void installUrl(String url, Map<String, Bundle> installedBundles) {
189 try {
190 if (installedBundles.containsKey(url)) {
191 Bundle bundle = (Bundle) installedBundles.get(url);
192 if (OsgiBootUtils.debug)
193 debug("Bundle " + bundle.getSymbolicName() + " already installed from " + url);
194 } else if (url.contains("/" + SYMBOLIC_NAME_EQUINOX + "/")
195 || url.contains("/" + SYMBOLIC_NAME_OSGI_BOOT + "/")) {
196 if (OsgiBootUtils.debug)
197 warn("Skip " + url);
198 return;
199 } else {
200 Bundle bundle = bundleContext.installBundle(url);
201 if (url.startsWith("http"))
202 OsgiBootUtils
203 .info("Installed " + bundle.getSymbolicName() + "-" + bundle.getVersion() + " from " + url);
204 else if (OsgiBootUtils.debug)
205 OsgiBootUtils.debug(
206 "Installed " + bundle.getSymbolicName() + "-" + bundle.getVersion() + " from " + url);
207 assert bundle.getSymbolicName() != null;
208 // uninstall previous versions
209 bundles: for (Bundle b : bundleContext.getBundles()) {
210 if (b.getSymbolicName() == null)
211 continue bundles;
212 if (bundle.getSymbolicName().equals(b.getSymbolicName())) {
213 Version bundleV = bundle.getVersion();
214 Version bV = b.getVersion();
215 if (bV == null)
216 continue bundles;
217 if (bundleV.getMajor() == bV.getMajor() && bundleV.getMinor() == bV.getMinor()) {
218 if (bundleV.getMicro() > bV.getMicro()) {
219 // uninstall older bundles
220 b.uninstall();
221 OsgiBootUtils.debug("Uninstalled " + b);
222 } else if (bundleV.getMicro() < bV.getMicro()) {
223 // uninstall just installed bundle if newer
224 bundle.uninstall();
225 OsgiBootUtils.debug("Uninstalled " + bundle);
226 break bundles;
227 } else {
228 // uninstall any other with same major/minor
229 if (!bundleV.getQualifier().equals(bV.getQualifier())) {
230 b.uninstall();
231 OsgiBootUtils.debug("Uninstalled " + b);
232 }
233 }
234 }
235 }
236 }
237 }
238 } catch (BundleException e) {
239 final String ALREADY_INSTALLED = "is already installed";
240 String message = e.getMessage();
241 if ((message.contains("Bundle \"" + SYMBOLIC_NAME_OSGI_BOOT + "\"")
242 || message.contains("Bundle \"" + SYMBOLIC_NAME_EQUINOX + "\""))
243 && message.contains(ALREADY_INSTALLED)) {
244 // silent, in order to avoid warnings: we know that both
245 // have already been installed...
246 } else {
247 if (message.contains(ALREADY_INSTALLED)) {
248 if (OsgiBootUtils.isDebug())
249 OsgiBootUtils.warn("Duplicate install from " + url + ": " + message);
250 } else
251 OsgiBootUtils.warn("Could not install bundle from " + url + ": " + message);
252 }
253 if (OsgiBootUtils.debug && !message.contains(ALREADY_INSTALLED))
254 e.printStackTrace();
255 }
256 }
257
258 /*
259 * START
260 */
261 public void startBundles() {
262 startBundles(System.getProperties());
263 }
264
265 public void startBundles(Properties properties) {
266 FrameworkStartLevel frameworkStartLevel = bundleContext.getBundle(0).adapt(FrameworkStartLevel.class);
267
268 // default and active start levels from System properties
269 Integer defaultStartLevel = Integer.parseInt(getProperty(PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL, "4"));
270 Integer activeStartLevel = Integer.parseInt(getProperty(PROP_OSGI_STARTLEVEL, "6"));
271
272 SortedMap<Integer, List<String>> startLevels = new TreeMap<Integer, List<String>>();
273 computeStartLevels(startLevels, properties, defaultStartLevel);
274 // inverts the map for the time being, TODO optimise
275 Map<String, Integer> bundleStartLevels = new HashMap<>();
276 for (Integer level : startLevels.keySet()) {
277 for (String bsn : startLevels.get(level))
278 bundleStartLevels.put(bsn, level);
279 }
280 for (Bundle bundle : bundleContext.getBundles()) {
281 String bsn = bundle.getSymbolicName();
282 if (bundleStartLevels.containsKey(bsn)) {
283 BundleStartLevel bundleStartLevel = bundle.adapt(BundleStartLevel.class);
284 Integer level = bundleStartLevels.get(bsn);
285 if (bundleStartLevel.getStartLevel() != level || !bundleStartLevel.isPersistentlyStarted()) {
286 bundleStartLevel.setStartLevel(level);
287 try {
288 bundle.start();
289 } catch (BundleException e) {
290 OsgiBootUtils.error("Cannot mark " + bsn + " as started", e);
291 }
292 if (getDebug())
293 OsgiBootUtils.debug(bsn + " starts at level " + level);
294 }
295 }
296 }
297 frameworkStartLevel.setStartLevel(activeStartLevel, (FrameworkEvent event) -> {
298 if (getDebug())
299 OsgiBootUtils.debug("Framework event: " + event);
300 int initialStartLevel = frameworkStartLevel.getInitialBundleStartLevel();
301 int startLevel = frameworkStartLevel.getStartLevel();
302 OsgiBootUtils.debug("Framework start level: " + startLevel + " (initial: " + initialStartLevel + ")");
303 });
304 }
305
306 private static void computeStartLevels(SortedMap<Integer, List<String>> startLevels, Properties properties,
307 Integer defaultStartLevel) {
308
309 // default (and previously, only behaviour)
310 appendToStartLevels(startLevels, defaultStartLevel, properties.getProperty(PROP_ARGEO_OSGI_START, ""));
311
312 // list argeo.osgi.start.* system properties
313 Iterator<Object> keys = properties.keySet().iterator();
314 final String prefix = PROP_ARGEO_OSGI_START + ".";
315 while (keys.hasNext()) {
316 String key = keys.next().toString();
317 if (key.startsWith(prefix)) {
318 Integer startLevel;
319 String suffix = key.substring(prefix.length());
320 String[] tokens = suffix.split("\\.");
321 if (tokens.length > 0 && !tokens[0].trim().equals(""))
322 try {
323 // first token is start level
324 startLevel = Integer.parseInt(tokens[0]);
325 } catch (NumberFormatException e) {
326 startLevel = defaultStartLevel;
327 }
328 else
329 startLevel = defaultStartLevel;
330
331 // append bundle names
332 String bundleNames = properties.getProperty(key);
333 appendToStartLevels(startLevels, startLevel, bundleNames);
334 }
335 }
336 }
337
338 /** Append a comma-separated list of bundles to the start levels. */
339 private static void appendToStartLevels(SortedMap<Integer, List<String>> startLevels, Integer startLevel,
340 String str) {
341 if (str == null || str.trim().equals(""))
342 return;
343
344 if (!startLevels.containsKey(startLevel))
345 startLevels.put(startLevel, new ArrayList<String>());
346 String[] bundleNames = str.split(",");
347 for (int i = 0; i < bundleNames.length; i++) {
348 if (bundleNames[i] != null && !bundleNames[i].trim().equals(""))
349 (startLevels.get(startLevel)).add(bundleNames[i]);
350 }
351 }
352
353 /**
354 * Start the provided list of bundles
355 *
356 * @return whether all bundles are now in active state
357 * @deprecated
358 */
359 @Deprecated
360 public boolean startBundles(List<String> bundlesToStart) {
361 if (bundlesToStart.size() == 0)
362 return true;
363
364 // used to monitor ACTIVE states
365 List<Bundle> startedBundles = new ArrayList<Bundle>();
366 // used to log the bundles not found
367 List<String> notFoundBundles = new ArrayList<String>(bundlesToStart);
368
369 Bundle[] bundles = bundleContext.getBundles();
370 long startBegin = System.currentTimeMillis();
371 for (int i = 0; i < bundles.length; i++) {
372 Bundle bundle = bundles[i];
373 String symbolicName = bundle.getSymbolicName();
374 if (bundlesToStart.contains(symbolicName))
375 try {
376 try {
377 bundle.start();
378 if (OsgiBootUtils.debug)
379 debug("Bundle " + symbolicName + " started");
380 } catch (Exception e) {
381 OsgiBootUtils.warn("Start of bundle " + symbolicName + " failed because of " + e
382 + ", maybe bundle is not yet resolved," + " waiting and trying again.");
383 waitForBundleResolvedOrActive(startBegin, bundle);
384 bundle.start();
385 startedBundles.add(bundle);
386 }
387 notFoundBundles.remove(symbolicName);
388 } catch (Exception e) {
389 OsgiBootUtils.warn("Bundle " + symbolicName + " cannot be started: " + e.getMessage());
390 if (OsgiBootUtils.debug)
391 e.printStackTrace();
392 // was found even if start failed
393 notFoundBundles.remove(symbolicName);
394 }
395 }
396
397 for (int i = 0; i < notFoundBundles.size(); i++)
398 OsgiBootUtils.warn("Bundle '" + notFoundBundles.get(i) + "' not started because it was not found.");
399
400 // monitors that all bundles are started
401 long beginMonitor = System.currentTimeMillis();
402 boolean allStarted = !(startedBundles.size() > 0);
403 List<String> notStarted = new ArrayList<String>();
404 while (!allStarted && (System.currentTimeMillis() - beginMonitor) < defaultTimeout) {
405 notStarted = new ArrayList<String>();
406 allStarted = true;
407 for (int i = 0; i < startedBundles.size(); i++) {
408 Bundle bundle = (Bundle) startedBundles.get(i);
409 // TODO check behaviour of lazs bundles
410 if (bundle.getState() != Bundle.ACTIVE) {
411 allStarted = false;
412 notStarted.add(bundle.getSymbolicName());
413 }
414 }
415 try {
416 Thread.sleep(100);
417 } catch (InterruptedException e) {
418 // silent
419 }
420 }
421 long duration = System.currentTimeMillis() - beginMonitor;
422
423 if (!allStarted)
424 for (int i = 0; i < notStarted.size(); i++)
425 OsgiBootUtils.warn("Bundle '" + notStarted.get(i) + "' not ACTIVE after " + (duration / 1000) + "s");
426
427 return allStarted;
428 }
429
430 /** Waits for a bundle to become active or resolved */
431 @Deprecated
432 private void waitForBundleResolvedOrActive(long startBegin, Bundle bundle) throws Exception {
433 int originalState = bundle.getState();
434 if ((originalState == Bundle.RESOLVED) || (originalState == Bundle.ACTIVE))
435 return;
436
437 String originalStateStr = OsgiBootUtils.stateAsString(originalState);
438
439 int currentState = bundle.getState();
440 while (!(currentState == Bundle.RESOLVED || currentState == Bundle.ACTIVE)) {
441 long now = System.currentTimeMillis();
442 if ((now - startBegin) > defaultTimeout * 10)
443 throw new Exception("Bundle " + bundle.getSymbolicName() + " was not RESOLVED or ACTIVE after "
444 + (now - startBegin) + "ms (originalState=" + originalStateStr + ", currentState="
445 + OsgiBootUtils.stateAsString(currentState) + ")");
446
447 try {
448 Thread.sleep(100l);
449 } catch (InterruptedException e) {
450 // silent
451 }
452 currentState = bundle.getState();
453 }
454 }
455
456 /*
457 * BUNDLE PATTERNS INSTALLATION
458 */
459 /**
460 * Computes a list of URLs based on Ant-like include/exclude patterns defined by
461 * ${argeo.osgi.bundles} with the following format:<br>
462 * <code>/base/directory;in=*.jar;in=**;ex=org.eclipse.osgi_*;jar</code><br>
463 * WARNING: <code>/base/directory;in=*.jar,\</code> at the end of a file,
464 * without a new line causes a '.' to be appended with unexpected side effects.
465 */
466 public List<String> getBundlesUrls() {
467 String bundlePatterns = getProperty(PROP_ARGEO_OSGI_BUNDLES);
468 return getBundlesUrls(bundlePatterns);
469 }
470
471 /**
472 * Compute a list of URLs to install based on the provided patterns, with
473 * default base url
474 */
475 public List<String> getBundlesUrls(String bundlePatterns) {
476 String baseUrl = getProperty(PROP_ARGEO_OSGI_BASE_URL, DEFAULT_BASE_URL);
477 return getBundlesUrls(baseUrl, bundlePatterns);
478 }
479
480 /** Implements the path matching logic */
481 public List<String> getBundlesUrls(String baseUrl, String bundlePatterns) {
482 List<String> urls = new ArrayList<String>();
483 if (bundlePatterns == null)
484 return urls;
485
486 // bundlePatterns = SystemPropertyUtils.resolvePlaceholders(bundlePatterns);
487 if (OsgiBootUtils.debug)
488 debug(PROP_ARGEO_OSGI_BUNDLES + "=" + bundlePatterns);
489
490 StringTokenizer st = new StringTokenizer(bundlePatterns, ",");
491 List<BundlesSet> bundlesSets = new ArrayList<BundlesSet>();
492 while (st.hasMoreTokens()) {
493 String token = st.nextToken();
494 if (new File(token).exists()) {
495 String url = locationToUrl(baseUrl, token);
496 urls.add(url);
497 } else
498 bundlesSets.add(new BundlesSet(token));
499 }
500
501 // find included
502 List<String> included = new ArrayList<String>();
503 // PathMatcher matcher = new AntPathMatcher();
504 for (int i = 0; i < bundlesSets.size(); i++) {
505 BundlesSet bundlesSet = (BundlesSet) bundlesSets.get(i);
506 for (int j = 0; j < bundlesSet.getIncludes().size(); j++) {
507 String pattern = (String) bundlesSet.getIncludes().get(j);
508 match(included, bundlesSet.getDir(), null, pattern);
509 }
510 }
511
512 // find excluded
513 List<String> excluded = new ArrayList<String>();
514 for (int i = 0; i < bundlesSets.size(); i++) {
515 BundlesSet bundlesSet = (BundlesSet) bundlesSets.get(i);
516 for (int j = 0; j < bundlesSet.getExcludes().size(); j++) {
517 String pattern = (String) bundlesSet.getExcludes().get(j);
518 match(excluded, bundlesSet.getDir(), null, pattern);
519 }
520 }
521
522 // construct list
523 for (int i = 0; i < included.size(); i++) {
524 String fullPath = (String) included.get(i);
525 if (!excluded.contains(fullPath))
526 urls.add(locationToUrl(baseUrl, fullPath));
527 }
528
529 return urls;
530 }
531
532 /*
533 * DISTRIBUTION JAR INSTALLATION
534 */
535 public List<String> getDistributionUrls() {
536 String distributionUrl = getProperty(PROP_ARGEO_OSGI_DISTRIBUTION_URL);
537 String baseUrl = getProperty(PROP_ARGEO_OSGI_BASE_URL);
538 return getDistributionUrls(distributionUrl, baseUrl);
539 }
540
541 public List<String> getDistributionUrls(String distributionUrl, String baseUrl) {
542 List<String> urls = new ArrayList<String>();
543 if (distributionUrl == null)
544 return urls;
545
546 DistributionBundle distributionBundle;
547 if (distributionUrl.startsWith("http") || distributionUrl.startsWith("file")) {
548 distributionBundle = new DistributionBundle(distributionUrl);
549 if (baseUrl != null)
550 distributionBundle.setBaseUrl(baseUrl);
551 } else {
552 // relative url
553 if (baseUrl == null) {
554 baseUrl = localCache;
555 }
556
557 if (distributionUrl.contains(":")) {
558 // TODO make it safer
559 String[] parts = distributionUrl.trim().split(":");
560 String[] categoryParts = parts[0].split("\\.");
561 String artifactId = parts[1];
562 String version = parts[2];
563 StringBuilder sb = new StringBuilder();
564 for (String categoryPart : categoryParts) {
565 sb.append(categoryPart).append('/');
566 }
567 sb.append(artifactId).append('/');
568 sb.append(version).append('/');
569 sb.append(artifactId).append('-').append(version).append(".jar");
570 distributionUrl = sb.toString();
571 }
572
573 distributionBundle = new DistributionBundle(baseUrl, distributionUrl, localCache);
574 }
575 // if (baseUrl != null && !(distributionUrl.startsWith("http") ||
576 // distributionUrl.startsWith("file"))) {
577 // // relative url
578 // distributionBundle = new DistributionBundle(baseUrl, distributionUrl,
579 // localCache);
580 // } else {
581 // distributionBundle = new DistributionBundle(distributionUrl);
582 // if (baseUrl != null)
583 // distributionBundle.setBaseUrl(baseUrl);
584 // }
585 distributionBundle.processUrl();
586 return distributionBundle.listUrls();
587 }
588
589 /*
590 * HIGH LEVEL UTILITIES
591 */
592 /** Actually performs the matching logic. */
593 protected void match(List<String> matched, String base, String currentPath, String pattern) {
594 if (currentPath == null) {
595 // Init
596 File baseDir = new File(base.replace('/', File.separatorChar));
597 File[] files = baseDir.listFiles();
598
599 if (files == null) {
600 if (OsgiBootUtils.debug)
601 OsgiBootUtils.warn("Base dir " + baseDir + " has no children, exists=" + baseDir.exists()
602 + ", isDirectory=" + baseDir.isDirectory());
603 return;
604 }
605
606 for (int i = 0; i < files.length; i++)
607 match(matched, base, files[i].getName(), pattern);
608 } else {
609 PathMatcher matcher = FileSystems.getDefault().getPathMatcher(pattern);
610 String fullPath = base + '/' + currentPath;
611 if (matched.contains(fullPath))
612 return;// don't try deeper if already matched
613
614 boolean ok = matcher.matches(Paths.get(currentPath));
615 // if (debug)
616 // debug(currentPath + " " + (ok ? "" : " not ")
617 // + " matched with " + pattern);
618 if (ok) {
619 matched.add(fullPath);
620 return;
621 } else {
622 String newFullPath = relativeToFullPath(base, currentPath);
623 File newFile = new File(newFullPath);
624 File[] files = newFile.listFiles();
625 if (files != null) {
626 for (int i = 0; i < files.length; i++) {
627 String newCurrentPath = currentPath + '/' + files[i].getName();
628 if (files[i].isDirectory()) {
629 // if (matcher.matchStart(pattern, newCurrentPath)) {
630 // FIXME recurse only if start matches ?
631 match(matched, base, newCurrentPath, pattern);
632 // } else {
633 // if (OsgiBootUtils.debug)
634 // debug(newCurrentPath + " does not start match with " + pattern);
635 //
636 // }
637 } else {
638 boolean nonDirectoryOk = matcher.matches(Paths.get(newCurrentPath));
639 if (OsgiBootUtils.debug)
640 debug(currentPath + " " + (ok ? "" : " not ") + " matched with " + pattern);
641 if (nonDirectoryOk)
642 matched.add(relativeToFullPath(base, newCurrentPath));
643 }
644 }
645 }
646 }
647 }
648 }
649
650 protected void matchFile() {
651
652 }
653
654 /*
655 * LOW LEVEL UTILITIES
656 */
657 /**
658 * The bundles already installed. Key is location (String) , value is a
659 * {@link Bundle}
660 */
661 public Map<String, Bundle> getBundlesByLocation() {
662 Map<String, Bundle> installedBundles = new HashMap<String, Bundle>();
663 Bundle[] bundles = bundleContext.getBundles();
664 for (int i = 0; i < bundles.length; i++) {
665 installedBundles.put(bundles[i].getLocation(), bundles[i]);
666 }
667 return installedBundles;
668 }
669
670 /**
671 * The bundles already installed. Key is symbolic name (String) , value is a
672 * {@link Bundle}
673 */
674 public Map<String, Bundle> getBundlesBySymbolicName() {
675 Map<String, Bundle> namedBundles = new HashMap<String, Bundle>();
676 Bundle[] bundles = bundleContext.getBundles();
677 for (int i = 0; i < bundles.length; i++) {
678 namedBundles.put(bundles[i].getSymbolicName(), bundles[i]);
679 }
680 return namedBundles;
681 }
682
683 /** Creates an URL from a location */
684 protected String locationToUrl(String baseUrl, String location) {
685 return baseUrl + location;
686 }
687
688 /** Transforms a relative path in a full system path. */
689 protected String relativeToFullPath(String basePath, String relativePath) {
690 return (basePath + '/' + relativePath).replace('/', File.separatorChar);
691 }
692
693 private void refreshFramework() {
694 Bundle systemBundle = bundleContext.getBundle(0);
695 FrameworkWiring frameworkWiring = systemBundle.adapt(FrameworkWiring.class);
696 frameworkWiring.refreshBundles(null);
697 }
698
699 /**
700 * Gets a property value
701 *
702 * @return null when defaultValue is ""
703 */
704 public String getProperty(String name, String defaultValue) {
705 String value = bundleContext.getProperty(name);
706 if (value == null)
707 return defaultValue; // may be null
708 else
709 return value;
710 }
711
712 public String getProperty(String name) {
713 return getProperty(name, null);
714 }
715
716 /*
717 * BEAN METHODS
718 */
719
720 public boolean getDebug() {
721 return OsgiBootUtils.debug;
722 }
723
724 // public void setDebug(boolean debug) {
725 // this.debug = debug;
726 // }
727
728 public BundleContext getBundleContext() {
729 return bundleContext;
730 }
731
732 public String getLocalCache() {
733 return localCache;
734 }
735
736 // public void setDefaultTimeout(long defaultTimeout) {
737 // this.defaultTimeout = defaultTimeout;
738 // }
739
740 // public boolean isExcludeSvn() {
741 // return excludeSvn;
742 // }
743 //
744 // public void setExcludeSvn(boolean excludeSvn) {
745 // this.excludeSvn = excludeSvn;
746 // }
747
748 /*
749 * INTERNAL CLASSES
750 */
751
752 }