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