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