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