1 package org
.argeo
.init
.osgi
;
3 import static org
.argeo
.init
.osgi
.OsgiBootUtils
.debug
;
4 import static org
.argeo
.init
.osgi
.OsgiBootUtils
.warn
;
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
;
17 import java
.util
.Properties
;
19 import java
.util
.SortedMap
;
20 import java
.util
.StringTokenizer
;
21 import java
.util
.TreeMap
;
22 import java
.util
.concurrent
.ForkJoinPool
;
24 import org
.argeo
.init
.a2
.A2Source
;
25 import org
.argeo
.init
.a2
.ProvisioningManager
;
26 import org
.osgi
.framework
.Bundle
;
27 import org
.osgi
.framework
.BundleContext
;
28 import org
.osgi
.framework
.BundleException
;
29 import org
.osgi
.framework
.FrameworkEvent
;
30 import org
.osgi
.framework
.Version
;
31 import org
.osgi
.framework
.startlevel
.BundleStartLevel
;
32 import org
.osgi
.framework
.startlevel
.FrameworkStartLevel
;
33 import org
.osgi
.framework
.wiring
.FrameworkWiring
;
36 * Basic provisioning of an OSGi runtime via file path patterns and system
37 * properties. The approach is to generate list of URLs based on various
38 * methods, configured via properties.
40 public class OsgiBoot
implements OsgiBootConstants
{
41 public final static String PROP_ARGEO_OSGI_START
= "argeo.osgi.start";
42 public final static String PROP_ARGEO_OSGI_MAX_START_LEVEL
= "argeo.osgi.maxStartLevel";
43 public final static String PROP_ARGEO_OSGI_SOURCES
= "argeo.osgi.sources";
46 final static String PROP_ARGEO_OSGI_BUNDLES
= "argeo.osgi.bundles";
47 final static String PROP_ARGEO_OSGI_BASE_URL
= "argeo.osgi.baseUrl";
48 final static String PROP_ARGEO_OSGI_LOCAL_CACHE
= "argeo.osgi.localCache";
49 final static String PROP_ARGEO_OSGI_DISTRIBUTION_URL
= "argeo.osgi.distributionUrl";
53 final static String PROP_ARGEO_OSGI_BOOT_DEBUG
= "argeo.osgi.boot.debug";
55 final static String PROP_ARGEO_OSGI_BOOT_SYSTEM_PROPERTIES_FILE
= "argeo.osgi.boot.systemPropertiesFile";
56 final static String PROP_ARGEO_OSGI_BOOT_APPCLASS
= "argeo.osgi.boot.appclass";
57 final static String PROP_ARGEO_OSGI_BOOT_APPARGS
= "argeo.osgi.boot.appargs";
60 public final static String DEFAULT_BASE_URL
= "reference:file:";
61 final static String DEFAULT_MAX_START_LEVEL
= "32";
63 // OSGi standard properties
64 final static String PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL
= "osgi.bundles.defaultStartLevel";
65 final static String PROP_OSGI_STARTLEVEL
= "osgi.startLevel";
66 public final static String PROP_OSGI_INSTANCE_AREA
= "osgi.instance.area";
67 public final static String PROP_OSGI_CONFIGURATION_AREA
= "osgi.configuration.area";
68 public final static String PROP_OSGI_SHARED_CONFIGURATION_AREA
= "osgi.sharedConfiguration.area";
69 public final static String PROP_OSGI_USE_SYSTEM_PROPERTIES
= "osgi.framework.useSystemProperties";
72 final static String SYMBOLIC_NAME_OSGI_BOOT
= "org.argeo.init";
73 final static String SYMBOLIC_NAME_EQUINOX
= "org.eclipse.osgi";
75 private final BundleContext bundleContext
;
76 private final String localCache
;
77 private final ProvisioningManager provisioningManager
;
83 public OsgiBoot(BundleContext bundleContext
) {
84 this.bundleContext
= bundleContext
;
85 Path homePath
= Paths
.get(System
.getProperty("user.home")).toAbsolutePath();
86 String homeUri
= homePath
.toUri().toString();
87 localCache
= getProperty(PROP_ARGEO_OSGI_LOCAL_CACHE
, homeUri
+ ".m2/repository/");
89 provisioningManager
= new ProvisioningManager(bundleContext
);
90 String sources
= getProperty(PROP_ARGEO_OSGI_SOURCES
);
91 if (sources
== null) {
92 provisioningManager
.registerDefaultSource();
94 // OsgiBootUtils.debug("Found sources " + sources);
95 for (String source
: sources
.split(",")) {
96 int qmIndex
= source
.lastIndexOf('?');
97 String queryPart
= "";
99 queryPart
= source
.substring(qmIndex
);
100 source
= source
.substring(0, qmIndex
);
102 if (source
.trim().equals(A2Source
.DEFAULT_A2_URI
)) {
103 if (Files
.exists(homePath
))
104 provisioningManager
.registerSource(
105 A2Source
.SCHEME_A2
+ "://" + homePath
.toString() + "/.local/share/a2" + queryPart
);
106 provisioningManager
.registerSource(A2Source
.SCHEME_A2
+ ":///usr/local/share/a2" + queryPart
);
107 provisioningManager
.registerSource(A2Source
.SCHEME_A2
+ ":///usr/share/a2" + queryPart
);
108 } else if (source
.trim().equals(A2Source
.DEFAULT_A2_REFERENCE_URI
)) {
109 if (Files
.exists(homePath
))
110 provisioningManager
.registerSource(A2Source
.SCHEME_A2_REFERENCE
+ "://" + homePath
.toString()
111 + "/.local/share/a2" + queryPart
);
113 .registerSource(A2Source
.SCHEME_A2_REFERENCE
+ ":///usr/local/share/a2" + queryPart
);
114 provisioningManager
.registerSource(A2Source
.SCHEME_A2_REFERENCE
+ ":///usr/share/a2" + queryPart
);
116 provisioningManager
.registerSource(source
+ queryPart
);
122 ProvisioningManager
getProvisioningManager() {
123 return provisioningManager
;
130 * Bootstraps the OSGi runtime using these properties, which MUST be consistent
131 * with {@link BundleContext#getProperty(String)}. If these properties are
132 * <code>null</code>, system properties are used instead.
134 public void bootstrap(Map
<String
, String
> properties
) {
136 long begin
= System
.currentTimeMillis();
139 String osgiInstancePath
= getProperty(PROP_OSGI_INSTANCE_AREA
);
140 String osgiConfigurationPath
= getProperty(PROP_OSGI_CONFIGURATION_AREA
);
141 String osgiSharedConfigurationPath
= getProperty(PROP_OSGI_CONFIGURATION_AREA
);
142 OsgiBootUtils
.info("OSGi bootstrap starting" //
143 + (osgiInstancePath
!= null ?
" data: " + osgiInstancePath
+ "" : "") //
144 + (osgiConfigurationPath
!= null ?
" state: " + osgiConfigurationPath
+ "" : "") //
145 + (osgiSharedConfigurationPath
!= null ?
" config: " + osgiSharedConfigurationPath
+ "" : "") //
148 // legacy install bundles
149 installUrls(getBundlesUrls());
150 installUrls(getDistributionUrls());
152 // A2 install bundles
153 provisioningManager
.install(null);
155 // Make sure fragments are properly considered by refreshing
159 // if (properties != null && !Boolean.parseBoolean(properties.get(PROP_OSGI_USE_SYSTEM_PROPERTIES)))
160 startBundles(properties
);
165 long duration
= System
.currentTimeMillis() - begin
;
166 OsgiBootUtils
.info("OSGi bootstrap completed in " + Math
.round(((double) duration
) / 1000) + "s ("
167 + duration
+ "ms), " + bundleContext
.getBundles().length
+ " bundles");
168 } catch (RuntimeException e
) {
169 OsgiBootUtils
.error("OSGi bootstrap FAILED", e
);
174 if (OsgiBootUtils
.isDebug()) {
175 OsgiBootDiagnostics diagnostics
= new OsgiBootDiagnostics(bundleContext
);
176 diagnostics
.checkUnresolved();
177 Map
<String
, Set
<String
>> duplicatePackages
= diagnostics
.findPackagesExportedTwice();
178 if (duplicatePackages
.size() > 0) {
179 OsgiBootUtils
.info("Packages exported twice:");
180 Iterator
<String
> it
= duplicatePackages
.keySet().iterator();
181 while (it
.hasNext()) {
182 String pkgName
= it
.next();
183 OsgiBootUtils
.info(pkgName
);
184 Set
<String
> bdles
= duplicatePackages
.get(pkgName
);
185 Iterator
<String
> bdlesIt
= bdles
.iterator();
186 while (bdlesIt
.hasNext())
187 OsgiBootUtils
.info(" " + bdlesIt
.next());
191 System
.out
.println();
195 * Calls {@link #bootstrap(Map)} with <code>null</code>.
197 * @see #bootstrap(Map)
200 public void bootstrap() {
204 public void update() {
205 provisioningManager
.update();
211 /** Install a single url. Convenience method. */
212 public Bundle
installUrl(String url
) {
213 List
<String
> urls
= new ArrayList
<String
>();
216 return (Bundle
) getBundlesByLocation().get(url
);
219 /** Install the bundles at this URL list. */
220 public void installUrls(List
<String
> urls
) {
221 Map
<String
, Bundle
> installedBundles
= getBundlesByLocation();
222 for (int i
= 0; i
< urls
.size(); i
++) {
223 String url
= (String
) urls
.get(i
);
224 installUrl(url
, installedBundles
);
226 // refreshFramework();
229 /** Actually install the provided URL */
230 protected void installUrl(String url
, Map
<String
, Bundle
> installedBundles
) {
232 if (installedBundles
.containsKey(url
)) {
233 Bundle bundle
= (Bundle
) installedBundles
.get(url
);
234 if (OsgiBootUtils
.isDebug())
235 debug("Bundle " + bundle
.getSymbolicName() + " already installed from " + url
);
236 } else if (url
.contains("/" + SYMBOLIC_NAME_EQUINOX
+ "/")
237 || url
.contains("/" + SYMBOLIC_NAME_OSGI_BOOT
+ "/")) {
238 if (OsgiBootUtils
.isDebug())
242 Bundle bundle
= bundleContext
.installBundle(url
);
243 if (url
.startsWith("http"))
245 .info("Installed " + bundle
.getSymbolicName() + "-" + bundle
.getVersion() + " from " + url
);
246 else if (OsgiBootUtils
.isDebug())
248 "Installed " + bundle
.getSymbolicName() + "-" + bundle
.getVersion() + " from " + url
);
249 assert bundle
.getSymbolicName() != null;
250 // uninstall previous versions
251 bundles
: for (Bundle b
: bundleContext
.getBundles()) {
252 if (b
.getSymbolicName() == null)
254 if (bundle
.getSymbolicName().equals(b
.getSymbolicName())) {
255 Version bundleV
= bundle
.getVersion();
256 Version bV
= b
.getVersion();
259 if (bundleV
.getMajor() == bV
.getMajor() && bundleV
.getMinor() == bV
.getMinor()) {
260 if (bundleV
.getMicro() > bV
.getMicro()) {
261 // uninstall older bundles
263 OsgiBootUtils
.debug("Uninstalled " + b
);
264 } else if (bundleV
.getMicro() < bV
.getMicro()) {
265 // uninstall just installed bundle if newer
267 OsgiBootUtils
.debug("Uninstalled " + bundle
);
270 // uninstall any other with same major/minor
271 if (!bundleV
.getQualifier().equals(bV
.getQualifier())) {
273 OsgiBootUtils
.debug("Uninstalled " + b
);
280 } catch (BundleException e
) {
281 final String ALREADY_INSTALLED
= "is already installed";
282 String message
= e
.getMessage();
283 if ((message
.contains("Bundle \"" + SYMBOLIC_NAME_OSGI_BOOT
+ "\"")
284 || message
.contains("Bundle \"" + SYMBOLIC_NAME_EQUINOX
+ "\""))
285 && message
.contains(ALREADY_INSTALLED
)) {
286 // silent, in order to avoid warnings: we know that both
287 // have already been installed...
289 if (message
.contains(ALREADY_INSTALLED
)) {
290 if (OsgiBootUtils
.isDebug())
291 OsgiBootUtils
.warn("Duplicate install from " + url
+ ": " + message
);
293 OsgiBootUtils
.warn("Could not install bundle from " + url
+ ": " + message
);
295 if (OsgiBootUtils
.isDebug() && !message
.contains(ALREADY_INSTALLED
))
305 * Start bundles based on these properties.
307 * @see OsgiBoot#doStartBundles(Map)
309 public void startBundles(Map
<String
, String
> properties
) {
310 Map
<String
, String
> map
= new TreeMap
<>();
311 // first use properties
312 if (properties
!= null) {
313 for (String key
: properties
.keySet()) {
314 String property
= key
;
315 if (property
.startsWith(PROP_ARGEO_OSGI_START
)) {
316 map
.put(property
, properties
.get(property
));
320 // then try all start level until a maximum
321 int maxStartLevel
= Integer
.parseInt(getProperty(PROP_ARGEO_OSGI_MAX_START_LEVEL
, DEFAULT_MAX_START_LEVEL
));
322 for (int i
= 1; i
<= maxStartLevel
; i
++) {
323 String key
= PROP_ARGEO_OSGI_START
+ "." + i
;
324 String value
= getProperty(key
);
329 // finally, override with system properties
330 for (Object key
: System
.getProperties().keySet()) {
331 if (key
.toString().startsWith(PROP_ARGEO_OSGI_START
)) {
332 map
.put(key
.toString(), System
.getProperty(key
.toString()));
340 public void startBundles(Properties properties
) {
341 Map
<String
, String
> map
= new TreeMap
<>();
342 // first use properties
343 if (properties
!= null) {
344 for (Object key
: properties
.keySet()) {
345 String property
= key
.toString();
346 if (property
.startsWith(PROP_ARGEO_OSGI_START
)) {
347 map
.put(property
, properties
.get(property
).toString());
354 /** Start bundle based on keys starting with {@link #PROP_ARGEO_OSGI_START}. */
355 protected void doStartBundles(Map
<String
, String
> properties
) {
356 FrameworkStartLevel frameworkStartLevel
= bundleContext
.getBundle(0).adapt(FrameworkStartLevel
.class);
358 // default and active start levels from System properties
359 Integer defaultStartLevel
= Integer
.parseInt(getProperty(PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL
, "4"));
360 Integer activeStartLevel
= Integer
.parseInt(getProperty(PROP_OSGI_STARTLEVEL
, "6"));
361 if (OsgiBootUtils
.isDebug()) {
362 OsgiBootUtils
.debug("OSGi default start level: "
363 + getProperty(PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL
, "<not set>") + ", using " + defaultStartLevel
);
364 OsgiBootUtils
.debug("OSGi active start level: " + getProperty(PROP_OSGI_STARTLEVEL
, "<not set>")
365 + ", using " + activeStartLevel
);
366 OsgiBootUtils
.debug("Framework start level: " + frameworkStartLevel
.getStartLevel() + " (initial: "
367 + frameworkStartLevel
.getInitialBundleStartLevel() + ")");
370 SortedMap
<Integer
, List
<String
>> startLevels
= new TreeMap
<Integer
, List
<String
>>();
371 computeStartLevels(startLevels
, properties
, defaultStartLevel
);
372 // inverts the map for the time being, TODO optimise
373 Map
<String
, Integer
> bundleStartLevels
= new HashMap
<>();
374 for (Integer level
: startLevels
.keySet()) {
375 for (String bsn
: startLevels
.get(level
))
376 bundleStartLevels
.put(bsn
, level
);
378 for (Bundle bundle
: bundleContext
.getBundles()) {
379 String bsn
= bundle
.getSymbolicName();
380 if (bundleStartLevels
.containsKey(bsn
)) {
381 BundleStartLevel bundleStartLevel
= bundle
.adapt(BundleStartLevel
.class);
382 Integer level
= bundleStartLevels
.get(bsn
);
383 if (bundleStartLevel
.getStartLevel() != level
|| !bundleStartLevel
.isPersistentlyStarted()) {
384 bundleStartLevel
.setStartLevel(level
);
387 } catch (BundleException e
) {
388 OsgiBootUtils
.error("Cannot mark " + bsn
+ " as started", e
);
390 if (OsgiBootUtils
.isDebug())
391 OsgiBootUtils
.debug(bsn
+ " starts at level " + level
);
396 if (OsgiBootUtils
.isDebug())
397 OsgiBootUtils
.debug("About to set framework start level to " + activeStartLevel
+ " ...");
399 // Start the framework asynchronously
400 ForkJoinPool
.commonPool().execute(() -> {
401 frameworkStartLevel
.setStartLevel(activeStartLevel
, (FrameworkEvent event
) -> {
402 if (OsgiBootUtils
.isDebug())
403 OsgiBootUtils
.debug("Framework event: " + event
);
404 int initialStartLevel
= frameworkStartLevel
.getInitialBundleStartLevel();
405 int startLevel
= frameworkStartLevel
.getStartLevel();
406 if (OsgiBootUtils
.isDebug())
408 .debug("Framework start level: " + startLevel
+ " (initial: " + initialStartLevel
+ ")");
413 private static void computeStartLevels(SortedMap
<Integer
, List
<String
>> startLevels
, Map
<String
, String
> properties
,
414 Integer defaultStartLevel
) {
416 // default (and previously, only behaviour)
417 appendToStartLevels(startLevels
, defaultStartLevel
, properties
.getOrDefault(PROP_ARGEO_OSGI_START
, ""));
419 // list argeo.osgi.start.* system properties
420 Iterator
<String
> keys
= properties
.keySet().iterator();
421 final String prefix
= PROP_ARGEO_OSGI_START
+ ".";
422 while (keys
.hasNext()) {
423 String key
= keys
.next();
424 if (key
.startsWith(prefix
)) {
426 String suffix
= key
.substring(prefix
.length());
427 String
[] tokens
= suffix
.split("\\.");
428 if (tokens
.length
> 0 && !tokens
[0].trim().equals(""))
430 // first token is start level
431 startLevel
= Integer
.parseInt(tokens
[0]);
432 } catch (NumberFormatException e
) {
433 startLevel
= defaultStartLevel
;
436 startLevel
= defaultStartLevel
;
438 // append bundle names
439 String bundleNames
= properties
.get(key
);
440 appendToStartLevels(startLevels
, startLevel
, bundleNames
);
445 /** Append a comma-separated list of bundles to the start levels. */
446 private static void appendToStartLevels(SortedMap
<Integer
, List
<String
>> startLevels
, Integer startLevel
,
448 if (str
== null || str
.trim().equals(""))
451 if (!startLevels
.containsKey(startLevel
))
452 startLevels
.put(startLevel
, new ArrayList
<String
>());
453 String
[] bundleNames
= str
.split(",");
454 for (int i
= 0; i
< bundleNames
.length
; i
++) {
455 if (bundleNames
[i
] != null && !bundleNames
[i
].trim().equals(""))
456 (startLevels
.get(startLevel
)).add(bundleNames
[i
]);
461 * BUNDLE PATTERNS INSTALLATION
464 * Computes a list of URLs based on Ant-like include/exclude patterns defined by
465 * ${argeo.osgi.bundles} with the following format:<br>
466 * <code>/base/directory;in=*.jar;in=**;ex=org.eclipse.osgi_*;jar</code><br>
467 * WARNING: <code>/base/directory;in=*.jar,\</code> at the end of a file,
468 * without a new line causes a '.' to be appended with unexpected side effects.
470 public List
<String
> getBundlesUrls() {
471 String bundlePatterns
= getProperty(PROP_ARGEO_OSGI_BUNDLES
);
472 return getBundlesUrls(bundlePatterns
);
476 * Compute a list of URLs to install based on the provided patterns, with
479 public List
<String
> getBundlesUrls(String bundlePatterns
) {
480 String baseUrl
= getProperty(PROP_ARGEO_OSGI_BASE_URL
, DEFAULT_BASE_URL
);
481 return getBundlesUrls(baseUrl
, bundlePatterns
);
484 /** Implements the path matching logic */
486 public List
<String
> getBundlesUrls(String baseUrl
, String bundlePatterns
) {
487 List
<String
> urls
= new ArrayList
<String
>();
488 if (bundlePatterns
== null)
491 // bundlePatterns = SystemPropertyUtils.resolvePlaceholders(bundlePatterns);
492 if (OsgiBootUtils
.isDebug())
493 debug(PROP_ARGEO_OSGI_BUNDLES
+ "=" + bundlePatterns
);
495 StringTokenizer st
= new StringTokenizer(bundlePatterns
, ",");
496 List
<BundlesSet
> bundlesSets
= new ArrayList
<BundlesSet
>();
497 while (st
.hasMoreTokens()) {
498 String token
= st
.nextToken();
499 if (new File(token
).exists()) {
500 String url
= locationToUrl(baseUrl
, token
);
503 bundlesSets
.add(new BundlesSet(token
));
507 List
<String
> included
= new ArrayList
<String
>();
508 // PathMatcher matcher = new AntPathMatcher();
509 for (int i
= 0; i
< bundlesSets
.size(); i
++) {
510 BundlesSet bundlesSet
= (BundlesSet
) bundlesSets
.get(i
);
511 for (int j
= 0; j
< bundlesSet
.getIncludes().size(); j
++) {
512 String pattern
= (String
) bundlesSet
.getIncludes().get(j
);
513 match(included
, bundlesSet
.getDir(), null, pattern
);
518 List
<String
> excluded
= new ArrayList
<String
>();
519 for (int i
= 0; i
< bundlesSets
.size(); i
++) {
520 BundlesSet bundlesSet
= (BundlesSet
) bundlesSets
.get(i
);
521 for (int j
= 0; j
< bundlesSet
.getExcludes().size(); j
++) {
522 String pattern
= (String
) bundlesSet
.getExcludes().get(j
);
523 match(excluded
, bundlesSet
.getDir(), null, pattern
);
528 for (int i
= 0; i
< included
.size(); i
++) {
529 String fullPath
= (String
) included
.get(i
);
530 if (!excluded
.contains(fullPath
))
531 urls
.add(locationToUrl(baseUrl
, fullPath
));
538 * DISTRIBUTION JAR INSTALLATION
540 public List
<String
> getDistributionUrls() {
541 String distributionUrl
= getProperty(PROP_ARGEO_OSGI_DISTRIBUTION_URL
);
542 String baseUrl
= getProperty(PROP_ARGEO_OSGI_BASE_URL
);
543 return getDistributionUrls(distributionUrl
, baseUrl
);
546 public List
<String
> getDistributionUrls(String distributionUrl
, String baseUrl
) {
547 List
<String
> urls
= new ArrayList
<String
>();
548 if (distributionUrl
== null)
551 DistributionBundle distributionBundle
;
552 if (distributionUrl
.startsWith("http") || distributionUrl
.startsWith("file")) {
553 distributionBundle
= new DistributionBundle(distributionUrl
);
555 distributionBundle
.setBaseUrl(baseUrl
);
558 if (baseUrl
== null) {
559 baseUrl
= localCache
;
562 if (distributionUrl
.contains(":")) {
563 // TODO make it safer
564 String
[] parts
= distributionUrl
.trim().split(":");
565 String
[] categoryParts
= parts
[0].split("\\.");
566 String artifactId
= parts
[1];
567 String version
= parts
[2];
568 StringBuilder sb
= new StringBuilder();
569 for (String categoryPart
: categoryParts
) {
570 sb
.append(categoryPart
).append('/');
572 sb
.append(artifactId
).append('/');
573 sb
.append(version
).append('/');
574 sb
.append(artifactId
).append('-').append(version
).append(".jar");
575 distributionUrl
= sb
.toString();
578 distributionBundle
= new DistributionBundle(baseUrl
, distributionUrl
, localCache
);
580 distributionBundle
.processUrl();
581 return distributionBundle
.listUrls();
585 * HIGH LEVEL UTILITIES
587 /** Actually performs the matching logic. */
588 protected void match(List
<String
> matched
, String base
, String currentPath
, String pattern
) {
589 if (currentPath
== null) {
591 File baseDir
= new File(base
.replace('/', File
.separatorChar
));
592 File
[] files
= baseDir
.listFiles();
595 if (OsgiBootUtils
.isDebug())
596 OsgiBootUtils
.warn("Base dir " + baseDir
+ " has no children, exists=" + baseDir
.exists()
597 + ", isDirectory=" + baseDir
.isDirectory());
601 for (int i
= 0; i
< files
.length
; i
++)
602 match(matched
, base
, files
[i
].getName(), pattern
);
604 PathMatcher matcher
= FileSystems
.getDefault().getPathMatcher(pattern
);
605 String fullPath
= base
+ '/' + currentPath
;
606 if (matched
.contains(fullPath
))
607 return;// don't try deeper if already matched
609 boolean ok
= matcher
.matches(Paths
.get(currentPath
));
611 // debug(currentPath + " " + (ok ? "" : " not ")
612 // + " matched with " + pattern);
614 matched
.add(fullPath
);
617 String newFullPath
= relativeToFullPath(base
, currentPath
);
618 File newFile
= new File(newFullPath
);
619 File
[] files
= newFile
.listFiles();
621 for (int i
= 0; i
< files
.length
; i
++) {
622 String newCurrentPath
= currentPath
+ '/' + files
[i
].getName();
623 if (files
[i
].isDirectory()) {
624 // if (matcher.matchStart(pattern, newCurrentPath)) {
625 // FIXME recurse only if start matches ?
626 match(matched
, base
, newCurrentPath
, pattern
);
628 // if (OsgiBootUtils.isDebug())
629 // debug(newCurrentPath + " does not start match with " + pattern);
633 boolean nonDirectoryOk
= matcher
.matches(Paths
.get(newCurrentPath
));
634 if (OsgiBootUtils
.isDebug())
635 debug(currentPath
+ " " + (ok ?
"" : " not ") + " matched with " + pattern
);
637 matched
.add(relativeToFullPath(base
, newCurrentPath
));
646 * LOW LEVEL UTILITIES
649 * The bundles already installed. Key is location (String) , value is a
652 public Map
<String
, Bundle
> getBundlesByLocation() {
653 Map
<String
, Bundle
> installedBundles
= new HashMap
<String
, Bundle
>();
654 Bundle
[] bundles
= bundleContext
.getBundles();
655 for (int i
= 0; i
< bundles
.length
; i
++) {
656 installedBundles
.put(bundles
[i
].getLocation(), bundles
[i
]);
658 return installedBundles
;
662 * The bundles already installed. Key is symbolic name (String) , value is a
665 public Map
<String
, Bundle
> getBundlesBySymbolicName() {
666 Map
<String
, Bundle
> namedBundles
= new HashMap
<String
, Bundle
>();
667 Bundle
[] bundles
= bundleContext
.getBundles();
668 for (int i
= 0; i
< bundles
.length
; i
++) {
669 namedBundles
.put(bundles
[i
].getSymbolicName(), bundles
[i
]);
674 /** Creates an URL from a location */
675 protected String
locationToUrl(String baseUrl
, String location
) {
676 return baseUrl
+ location
;
679 /** Transforms a relative path in a full system path. */
680 protected String
relativeToFullPath(String basePath
, String relativePath
) {
681 return (basePath
+ '/' + relativePath
).replace('/', File
.separatorChar
);
684 private void refreshFramework() {
685 Bundle systemBundle
= bundleContext
.getBundle(0);
686 FrameworkWiring frameworkWiring
= systemBundle
.adapt(FrameworkWiring
.class);
687 // TODO deal with refresh breaking native loading (e.g SWT)
688 frameworkWiring
.refreshBundles(null);
692 * Gets a property value
694 * @return null when defaultValue is ""
696 public String
getProperty(String name
, String defaultValue
) {
697 String value
= bundleContext
.getProperty(name
);
699 return defaultValue
; // may be null
704 public String
getProperty(String name
) {
705 return getProperty(name
, null);
712 public BundleContext
getBundleContext() {
713 return bundleContext
;