]> git.argeo.org Git - lgpl/argeo-commons.git/blob - osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/OsgiBoot.java
Improve OSGi boot
[lgpl/argeo-commons.git] / osgi / runtime / org.argeo.osgi.boot / src / main / java / org / argeo / slc / osgiboot / OsgiBoot.java
1 package org.argeo.slc.osgiboot;
2
3 import java.io.BufferedReader;
4 import java.io.File;
5 import java.io.IOException;
6 import java.io.InputStream;
7 import java.io.InputStreamReader;
8 import java.net.URL;
9 import java.util.ArrayList;
10 import java.util.HashMap;
11 import java.util.Iterator;
12 import java.util.List;
13 import java.util.Map;
14 import java.util.StringTokenizer;
15
16 import org.argeo.slc.osgiboot.internal.springutil.AntPathMatcher;
17 import org.argeo.slc.osgiboot.internal.springutil.PathMatcher;
18 import org.argeo.slc.osgiboot.internal.springutil.SystemPropertyUtils;
19 import org.osgi.framework.Bundle;
20 import org.osgi.framework.BundleContext;
21 import org.osgi.framework.BundleException;
22 import org.osgi.framework.Constants;
23 import org.osgi.framework.ServiceReference;
24 import org.osgi.service.packageadmin.PackageAdmin;
25
26 public class OsgiBoot {
27 public final static String SYMBOLIC_NAME_OSGI_BOOT = "org.argeo.osgi.boot";
28 public final static String SYMBOLIC_NAME_EQUINOX = "org.eclipse.osgi";
29
30 public final static String PROP_ARGEO_OSGI_DATA_DIR = "argeo.osgi.data.dir";
31
32 public final static String PROP_ARGEO_OSGI_START = "argeo.osgi.start";
33 public final static String PROP_ARGEO_OSGI_BUNDLES = "argeo.osgi.bundles";
34 public final static String PROP_ARGEO_OSGI_LOCATIONS = "argeo.osgi.locations";
35 public final static String PROP_ARGEO_OSGI_BASE_URL = "argeo.osgi.baseUrl";
36 public final static String PROP_ARGEO_OSGI_MODULES_URL = "argeo.osgi.modulesUrl";
37
38 public final static String PROP_ARGEO_OSGI_BOOT_DEBUG = "argeo.osgi.boot.debug";
39 public final static String PROP_ARGEO_OSGI_BOOT_DEFAULT_TIMEOUT = "argeo.osgi.boot.defaultTimeout";
40 public final static String PROP_ARGEO_OSGI_BOOT_MODULES_URL_SEPARATOR = "argeo.osgi.boot.modulesUrlSeparator";
41 public final static String PROP_ARGEO_OSGI_BOOT_SYSTEM_PROPERTIES_FILE = "argeo.osgi.boot.systemPropertiesFile";
42
43 /** @deprecated */
44 public final static String PROP_SLC_OSGI_START = "slc.osgi.start";
45 /** @deprecated */
46 public final static String PROP_SLC_OSGI_BUNDLES = "slc.osgi.bundles";
47 /** @deprecated */
48 public final static String PROP_SLC_OSGI_LOCATIONS = "slc.osgi.locations";
49 /** @deprecated */
50 public final static String PROP_SLC_OSGI_BASE_URL = "slc.osgi.baseUrl";
51 /** @deprecated */
52 public final static String PROP_SLC_OSGI_MODULES_URL = "slc.osgi.modulesUrl";
53
54 /** @deprecated */
55 public final static String PROP_SLC_OSGIBOOT_DEBUG = "slc.osgiboot.debug";
56 /** @deprecated */
57 public final static String PROP_SLC_OSGIBOOT_DEFAULT_TIMEOUT = "slc.osgiboot.defaultTimeout";
58 /** @deprecated */
59 public final static String PROP_SLC_OSGIBOOT_MODULES_URL_SEPARATOR = "slc.osgiboot.modulesUrlSeparator";
60 /** @deprecated */
61 public final static String PROP_SLC_OSGIBOOT_SYSTEM_PROPERTIES_FILE = "slc.osgiboot.systemPropertiesFile";
62
63 public final static String DEFAULT_BASE_URL = "reference:file:";
64 public final static String EXCLUDES_SVN_PATTERN = "**/.svn/**";
65
66 private boolean debug = Boolean.valueOf(
67 System.getProperty(PROP_ARGEO_OSGI_BOOT_DEBUG, System.getProperty(
68 PROP_SLC_OSGIBOOT_DEBUG, "false"))).booleanValue();
69 /** Default is 10s (set in constructor) */
70 private long defaultTimeout;
71
72 private boolean excludeSvn = true;
73 /** Default is ',' (set in constructor) */
74 private String modulesUrlSeparator = ",";
75
76 private final BundleContext bundleContext;
77
78 public OsgiBoot(BundleContext bundleContext) {
79 this.bundleContext = bundleContext;
80 defaultTimeout = Long.parseLong(getPropertyCompat(
81 PROP_ARGEO_OSGI_BOOT_DEFAULT_TIMEOUT,
82 PROP_SLC_OSGIBOOT_DEFAULT_TIMEOUT, "10000"));
83 modulesUrlSeparator = getPropertyCompat(
84 PROP_ARGEO_OSGI_BOOT_MODULES_URL_SEPARATOR,
85 PROP_SLC_OSGIBOOT_MODULES_URL_SEPARATOR, ",");
86 initSystemProperties();
87 }
88
89 protected void initSystemProperties() {
90 String osgiInstanceArea = System.getProperty("osgi.instance.area");
91 String osgiInstanceAreaDefault = System
92 .getProperty("osgi.instance.area.default");
93 String tempDir = System.getProperty("java.io.tmpdir");
94
95 File dataDir = null;
96 if (osgiInstanceArea != null) {
97 // within OSGi with -data specified
98 osgiInstanceArea = removeFilePrefix(osgiInstanceArea);
99 dataDir = new File(osgiInstanceArea);
100 } else if (osgiInstanceAreaDefault != null) {
101 // within OSGi without -data specified
102 osgiInstanceAreaDefault = removeFilePrefix(osgiInstanceAreaDefault);
103 dataDir = new File(osgiInstanceAreaDefault);
104 } else {// outside OSGi
105 dataDir = new File(tempDir + File.separator + "argeoOsgiData");
106 }
107
108 System.setProperty(PROP_ARGEO_OSGI_DATA_DIR, dataDir.getAbsolutePath());
109 }
110
111 public static String removeFilePrefix(String url) {
112 if (url.startsWith("file:"))
113 return url.substring("file:".length());
114 else if (url.startsWith("reference:file:"))
115 return url.substring("reference:file:".length());
116 else
117 return url;
118 }
119
120 public void bootstrap() {
121 System.out.println();
122 info("OSGi bootstrap starting...");
123 info("Writable data directory : "
124 + System.getProperty(PROP_ARGEO_OSGI_DATA_DIR)
125 + " (set as system property " + PROP_ARGEO_OSGI_DATA_DIR + ")");
126 installUrls(getBundlesUrls());
127 installUrls(getLocationsUrls());
128 installUrls(getModulesUrls());
129 checkUnresolved();
130 startBundles();
131 info("OSGi bootstrap completed");
132 System.out.println();
133 }
134
135 public void installUrls(List urls) {
136 Map installedBundles = getInstalledBundles();
137 for (int i = 0; i < urls.size(); i++) {
138 String url = (String) urls.get(i);
139 try {
140 if (installedBundles.containsKey(url)) {
141 Bundle bundle = (Bundle) installedBundles.get(url);
142 // bundle.update();
143 if (debug)
144 debug("Bundle " + bundle.getSymbolicName()
145 + " already installed from " + url);
146 } else {
147 Bundle bundle = bundleContext.installBundle(url);
148 if (debug)
149 debug("Installed bundle " + bundle.getSymbolicName()
150 + " from " + url);
151 }
152 } catch (BundleException e) {
153 String message = e.getMessage();
154 if ((message.contains("Bundle \"" + SYMBOLIC_NAME_OSGI_BOOT
155 + "\"") || message.contains("Bundle \""
156 + SYMBOLIC_NAME_EQUINOX + "\""))
157 && message.contains("has already been installed")) {
158 // silent, in order to avoid warnings: we know that both
159 // have already been installed...
160 } else {
161 warn("Could not install bundle from " + url + ": "
162 + message);
163 }
164 if (debug)
165 e.printStackTrace();
166 }
167 }
168
169 }
170
171 public void installOrUpdateUrls(Map urls) {
172 Map installedBundles = getBundles();
173
174 for (Iterator modules = urls.keySet().iterator(); modules.hasNext();) {
175 String moduleName = (String) modules.next();
176 String urlStr = (String) urls.get(moduleName);
177 if (installedBundles.containsKey(moduleName)) {
178 Bundle bundle = (Bundle) installedBundles.get(moduleName);
179 InputStream in;
180 try {
181 URL url = new URL(urlStr);
182 in = url.openStream();
183 bundle.update(in);
184 info("Updated bundle " + moduleName + " from " + urlStr);
185 } catch (Exception e) {
186 throw new RuntimeException("Cannot update " + moduleName
187 + " from " + urlStr);
188 }
189 if (in != null)
190 try {
191 in.close();
192 } catch (IOException e) {
193 e.printStackTrace();
194 }
195 } else {
196 try {
197 Bundle bundle = bundleContext.installBundle(urlStr);
198 if (debug)
199 debug("Installed bundle " + bundle.getSymbolicName()
200 + " from " + urlStr);
201 } catch (BundleException e) {
202 warn("Could not install bundle from " + urlStr + ": "
203 + e.getMessage());
204 }
205 }
206 }
207
208 }
209
210 public void startBundles() {
211 String bundlesToStart = getPropertyCompat(PROP_ARGEO_OSGI_START,
212 PROP_SLC_OSGI_START);
213 startBundles(bundlesToStart);
214 }
215
216 public void startBundles(String bundlesToStartStr) {
217 if (bundlesToStartStr == null)
218 return;
219
220 StringTokenizer st = new StringTokenizer(bundlesToStartStr, ",");
221 List bundlesToStart = new ArrayList();
222 while (st.hasMoreTokens()) {
223 String name = st.nextToken().trim();
224 bundlesToStart.add(name);
225 }
226 startBundles(bundlesToStart);
227 }
228
229 public void startBundles(List bundlesToStart) {
230 if (bundlesToStart.size() == 0)
231 return;
232
233 // used to log the bundles not found
234 List notFoundBundles = new ArrayList(bundlesToStart);
235
236 Bundle[] bundles = bundleContext.getBundles();
237 long startBegin = System.currentTimeMillis();
238 for (int i = 0; i < bundles.length; i++) {
239 Bundle bundle = bundles[i];
240 String symbolicName = bundle.getSymbolicName();
241 if (bundlesToStart.contains(symbolicName))
242 try {
243 try {
244 bundle.start();
245 } catch (Exception e) {
246 warn("Start of bundle " + symbolicName
247 + " failed because of " + e
248 + ", maybe bundle is not yet resolved,"
249 + " waiting and trying again.");
250 waitForBundleResolvedOrActive(startBegin, bundle);
251 bundle.start();
252 }
253 notFoundBundles.remove(symbolicName);
254 } catch (Exception e) {
255 warn("Bundle " + symbolicName + " cannot be started: "
256 + e.getMessage());
257 if (debug)
258 e.printStackTrace();
259 // was found even if start failed
260 notFoundBundles.remove(symbolicName);
261 }
262 }
263
264 for (int i = 0; i < notFoundBundles.size(); i++)
265 warn("Bundle " + notFoundBundles.get(i)
266 + " not started because it was not found.");
267 }
268
269 protected void checkUnresolved() {
270 // Refresh
271 ServiceReference packageAdminRef = bundleContext
272 .getServiceReference(PackageAdmin.class.getName());
273 PackageAdmin packageAdmin = (PackageAdmin) bundleContext
274 .getService(packageAdminRef);
275 packageAdmin.resolveBundles(null);
276
277 Bundle[] bundles = bundleContext.getBundles();
278 List /* Bundle */unresolvedBundles = new ArrayList();
279 for (int i = 0; i < bundles.length; i++) {
280 int bundleState = bundles[i].getState();
281 if (!(bundleState == Bundle.ACTIVE
282 || bundleState == Bundle.RESOLVED || bundleState == Bundle.STARTING))
283 unresolvedBundles.add(bundles[i]);
284 }
285
286 if (unresolvedBundles.size() != 0) {
287 warn("Unresolved bundles " + unresolvedBundles);
288 }
289 }
290
291 protected void waitForBundleResolvedOrActive(long startBegin, Bundle bundle)
292 throws Exception {
293 int originalState = bundle.getState();
294 if ((originalState == Bundle.RESOLVED)
295 || (originalState == Bundle.ACTIVE))
296 return;
297
298 String originalStateStr = stateAsString(originalState);
299
300 int currentState = bundle.getState();
301 while (!(currentState == Bundle.RESOLVED || currentState == Bundle.ACTIVE)) {
302 long now = System.currentTimeMillis();
303 if ((now - startBegin) > defaultTimeout)
304 throw new Exception("Bundle " + bundle.getSymbolicName()
305 + " was not RESOLVED or ACTIVE after "
306 + (now - startBegin) + "ms (originalState="
307 + originalStateStr + ", currentState="
308 + stateAsString(currentState) + ")");
309
310 try {
311 Thread.sleep(100l);
312 } catch (InterruptedException e) {
313 // silent
314 }
315 currentState = bundle.getState();
316 }
317 }
318
319 public static String stateAsString(int state) {
320 switch (state) {
321 case Bundle.UNINSTALLED:
322 return "UNINSTALLED";
323 case Bundle.INSTALLED:
324 return "INSTALLED";
325 case Bundle.RESOLVED:
326 return "RESOLVED";
327 case Bundle.STARTING:
328 return "STARTING";
329 case Bundle.ACTIVE:
330 return "ACTIVE";
331 case Bundle.STOPPING:
332 return "STOPPING";
333 default:
334 return Integer.toString(state);
335 }
336 }
337
338 /** Key is location */
339 public Map getInstalledBundles() {
340 Map installedBundles = new HashMap();
341
342 Bundle[] bundles = bundleContext.getBundles();
343 for (int i = 0; i < bundles.length; i++) {
344 installedBundles.put(bundles[i].getLocation(), bundles[i]);
345 }
346 return installedBundles;
347 }
348
349 /** Key is symbolic name */
350 public Map getBundles() {
351 Map namedBundles = new HashMap();
352 Bundle[] bundles = bundleContext.getBundles();
353 for (int i = 0; i < bundles.length; i++) {
354 namedBundles.put(bundles[i].getSymbolicName(), bundles[i]);
355 }
356 return namedBundles;
357 }
358
359 public List getLocationsUrls() {
360 String baseUrl = getPropertyCompat(PROP_ARGEO_OSGI_BASE_URL,
361 PROP_SLC_OSGI_BASE_URL, DEFAULT_BASE_URL);
362 String bundleLocations = getPropertyCompat(PROP_ARGEO_OSGI_LOCATIONS,
363 PROP_SLC_OSGI_LOCATIONS);
364 return getLocationsUrls(baseUrl, bundleLocations);
365 }
366
367 public List getModulesUrls() {
368 List urls = new ArrayList();
369 String modulesUrlStr = getPropertyCompat(PROP_ARGEO_OSGI_MODULES_URL,
370 PROP_SLC_OSGI_MODULES_URL);
371 if (modulesUrlStr == null)
372 return urls;
373
374 String baseUrl = getPropertyCompat(PROP_ARGEO_OSGI_BASE_URL,
375 PROP_SLC_OSGI_BASE_URL);
376
377 Map installedBundles = getBundles();
378
379 BufferedReader reader = null;
380 try {
381 URL modulesUrl = new URL(modulesUrlStr);
382 reader = new BufferedReader(new InputStreamReader(modulesUrl
383 .openStream()));
384 String line = null;
385 while ((line = reader.readLine()) != null) {
386 StringTokenizer st = new StringTokenizer(line,
387 modulesUrlSeparator);
388 String moduleName = st.nextToken();
389 String moduleVersion = st.nextToken();
390 String url = st.nextToken();
391 if (baseUrl != null)
392 url = baseUrl + url;
393
394 if (installedBundles.containsKey(moduleName)) {
395 Bundle bundle = (Bundle) installedBundles.get(moduleName);
396 String bundleVersion = bundle.getHeaders().get(
397 Constants.BUNDLE_VERSION).toString();
398 int comp = compareVersions(bundleVersion, moduleVersion);
399 if (comp > 0) {
400 warn("Installed version " + bundleVersion
401 + " of bundle " + moduleName
402 + " is newer than provided version "
403 + moduleVersion);
404 } else if (comp < 0) {
405 urls.add(url);
406 info("Updated bundle " + moduleName + " with version "
407 + moduleVersion + " (old version was "
408 + bundleVersion + ")");
409 } else {
410 // do nothing
411 }
412 } else {
413 urls.add(url);
414 }
415 }
416 } catch (Exception e1) {
417 throw new RuntimeException("Cannot read url " + modulesUrlStr, e1);
418 } finally {
419 if (reader != null)
420 try {
421 reader.close();
422 } catch (IOException e) {
423 e.printStackTrace();
424 }
425 }
426 return urls;
427 }
428
429 /**
430 * @return ==0: versions are identical, <0: tested version is newer, >0:
431 * currentVersion is newer.
432 */
433 protected int compareVersions(String currentVersion, String testedVersion) {
434 List cToks = new ArrayList();
435 StringTokenizer cSt = new StringTokenizer(currentVersion, ".");
436 while (cSt.hasMoreTokens())
437 cToks.add(cSt.nextToken());
438 List tToks = new ArrayList();
439 StringTokenizer tSt = new StringTokenizer(currentVersion, ".");
440 while (tSt.hasMoreTokens())
441 tToks.add(tSt.nextToken());
442
443 int comp = 0;
444 comp: for (int i = 0; i < cToks.size(); i++) {
445 if (tToks.size() <= i) {
446 // equals until then, tested shorter
447 comp = 1;
448 break comp;
449 }
450
451 String c = (String) cToks.get(i);
452 String t = (String) tToks.get(i);
453
454 try {
455 int cInt = Integer.parseInt(c);
456 int tInt = Integer.parseInt(t);
457 if (cInt == tInt)
458 continue comp;
459 else {
460 comp = (cInt - tInt);
461 break comp;
462 }
463 } catch (NumberFormatException e) {
464 if (c.equals(t))
465 continue comp;
466 else {
467 comp = c.compareTo(t);
468 break comp;
469 }
470 }
471 }
472
473 if (comp == 0 && tToks.size() > cToks.size()) {
474 // equals until then, current shorter
475 comp = -1;
476 }
477
478 return comp;
479 }
480
481 public List getLocationsUrls(String baseUrl, String bundleLocations) {
482 List urls = new ArrayList();
483
484 if (bundleLocations == null)
485 return urls;
486 bundleLocations = SystemPropertyUtils
487 .resolvePlaceholders(bundleLocations);
488 if (debug)
489 debug(PROP_ARGEO_OSGI_LOCATIONS + "=" + bundleLocations);
490
491 StringTokenizer st = new StringTokenizer(bundleLocations,
492 File.pathSeparator);
493 while (st.hasMoreTokens()) {
494 urls.add(locationToUrl(baseUrl, st.nextToken().trim()));
495 }
496 return urls;
497 }
498
499 public List getBundlesUrls() {
500 String baseUrl = getPropertyCompat(PROP_ARGEO_OSGI_BASE_URL,
501 PROP_SLC_OSGI_BASE_URL, DEFAULT_BASE_URL);
502 String bundlePatterns = getPropertyCompat(PROP_ARGEO_OSGI_BUNDLES,
503 PROP_SLC_OSGI_BUNDLES);
504 return getBundlesUrls(baseUrl, bundlePatterns);
505 }
506
507 public List getBundlesUrls(String baseUrl, String bundlePatterns) {
508 List urls = new ArrayList();
509
510 List bundlesSets = new ArrayList();
511 if (bundlePatterns == null)
512 return urls;
513 bundlePatterns = SystemPropertyUtils
514 .resolvePlaceholders(bundlePatterns);
515 if (debug)
516 debug(PROP_ARGEO_OSGI_BUNDLES + "=" + bundlePatterns
517 + " (excludeSvn=" + excludeSvn + ")");
518
519 StringTokenizer st = new StringTokenizer(bundlePatterns, ",");
520 while (st.hasMoreTokens()) {
521 bundlesSets.add(new BundlesSet(st.nextToken()));
522 }
523
524 List included = new ArrayList();
525 PathMatcher matcher = new AntPathMatcher();
526 for (int i = 0; i < bundlesSets.size(); i++) {
527 BundlesSet bundlesSet = (BundlesSet) bundlesSets.get(i);
528 for (int j = 0; j < bundlesSet.getIncludes().size(); j++) {
529 String pattern = (String) bundlesSet.getIncludes().get(j);
530 match(matcher, included, bundlesSet.getDir(), null, pattern);
531 }
532 }
533
534 List excluded = new ArrayList();
535 for (int i = 0; i < bundlesSets.size(); i++) {
536 BundlesSet bundlesSet = (BundlesSet) bundlesSets.get(i);
537 for (int j = 0; j < bundlesSet.getExcludes().size(); j++) {
538 String pattern = (String) bundlesSet.getExcludes().get(j);
539 match(matcher, excluded, bundlesSet.getDir(), null, pattern);
540 }
541 }
542
543 for (int i = 0; i < included.size(); i++) {
544 String fullPath = (String) included.get(i);
545 if (!excluded.contains(fullPath))
546 urls.add(locationToUrl(baseUrl, fullPath));
547 }
548
549 return urls;
550 }
551
552 protected void match(PathMatcher matcher, List matched, String base,
553 String currentPath, String pattern) {
554 if (currentPath == null) {
555 // Init
556 File baseDir = new File(base.replace('/', File.separatorChar));
557 File[] files = baseDir.listFiles();
558
559 if (files == null) {
560 warn("Base dir " + baseDir + " has no children, exists="
561 + baseDir.exists() + ", isDirectory="
562 + baseDir.isDirectory());
563 return;
564 }
565
566 for (int i = 0; i < files.length; i++)
567 match(matcher, matched, base, files[i].getName(), pattern);
568 } else {
569 String fullPath = base + '/' + currentPath;
570 if (matched.contains(fullPath))
571 return;// don't try deeper if already matched
572
573 boolean ok = matcher.match(pattern, currentPath);
574 if (debug)
575 debug(currentPath + " " + (ok ? "" : " not ")
576 + " matched with " + pattern);
577 if (ok) {
578 matched.add(fullPath);
579 return;
580 } else {
581 String newFullPath = relativeToFullPath(base, currentPath);
582 File newFile = new File(newFullPath);
583 File[] files = newFile.listFiles();
584 if (files != null) {
585 for (int i = 0; i < files.length; i++) {
586 String newCurrentPath = currentPath + '/'
587 + files[i].getName();
588 if (files[i].isDirectory()) {
589 if (matcher.matchStart(pattern, newCurrentPath)) {
590 // recurse only if start matches
591 match(matcher, matched, base, newCurrentPath,
592 pattern);
593 } else {
594 if (debug)
595 debug(newCurrentPath
596 + " does not start match with "
597 + pattern);
598
599 }
600 } else {
601 boolean nonDirectoryOk = matcher.match(pattern,
602 newCurrentPath);
603 if (debug)
604 debug(currentPath + " " + (ok ? "" : " not ")
605 + " matched with " + pattern);
606 if (nonDirectoryOk)
607 matched.add(relativeToFullPath(base,
608 newCurrentPath));
609 }
610 }
611 }
612 }
613 }
614 }
615
616 protected String locationToUrl(String baseUrl, String location) {
617 int extInd = location.lastIndexOf('.');
618 String ext = null;
619 if (extInd > 0)
620 ext = location.substring(extInd);
621
622 if (baseUrl.startsWith("reference:") && ".jar".equals(ext))
623 return "file:" + location;
624 else
625 return baseUrl + location;
626 }
627
628 /** Transforms a relative path in a full system path. */
629 protected String relativeToFullPath(String basePath, String relativePath) {
630 return (basePath + '/' + relativePath).replace('/', File.separatorChar);
631 }
632
633 protected static void info(Object obj) {
634 System.out.println("# OSGiBOOT # " + obj);
635 }
636
637 protected void debug(Object obj) {
638 if (debug)
639 System.out.println("# OSGiBOOT DBG # " + obj);
640 }
641
642 protected void warn(Object obj) {
643 System.out.println("# OSGiBOOT WARN # " + obj);
644 // Because of a weird bug under Windows when starting it in a forked VM
645 // if (System.getProperty("os.name").contains("Windows"))
646 // System.out.println("# WARN " + obj);
647 // else
648 // System.err.println("# WARN " + obj);
649 }
650
651 protected String getProperty(String name, String defaultValue) {
652 final String value;
653 if (defaultValue != null)
654 value = System.getProperty(name, defaultValue);
655 else
656 value = System.getProperty(name);
657
658 if (value == null || value.equals(""))
659 return null;
660 else
661 return value;
662 }
663
664 protected String getProperty(String name) {
665 return getProperty(name, null);
666 }
667
668 protected String getPropertyCompat(String name, String oldName) {
669 return getPropertyCompat(name, oldName, null);
670 }
671
672 protected String getPropertyCompat(String name, String oldName,
673 String defaultValue) {
674 String res = null;
675
676 if (defaultValue != null) {
677 res = getProperty(name, defaultValue);
678 if (res.equals(defaultValue)) {
679 res = getProperty(oldName, defaultValue);
680 if (!res.equals(defaultValue))
681 warnDeprecated(name, oldName);
682 }
683 } else {
684 res = getProperty(name, null);
685 if (res == null) {
686 res = getProperty(oldName, null);
687 if (res != null)
688 warnDeprecated(name, oldName);
689 }
690 }
691 return res;
692 }
693
694 protected void warnDeprecated(String name, String oldName) {
695 warn("Property '" + oldName
696 + "' is deprecated and will be removed soon, use '" + name
697 + "' instead.");
698 }
699
700 public boolean getDebug() {
701 return debug;
702 }
703
704 public void setDebug(boolean debug) {
705 this.debug = debug;
706 }
707
708 public BundleContext getBundleContext() {
709 return bundleContext;
710 }
711
712 /** Whether to exclude Subversion directories (true by default) */
713 public boolean isExcludeSvn() {
714 return excludeSvn;
715 }
716
717 public void setExcludeSvn(boolean excludeSvn) {
718 this.excludeSvn = excludeSvn;
719 }
720
721 protected class BundlesSet {
722 private String baseUrl = "reference:file";// not used yet
723 private final String dir;
724 private List includes = new ArrayList();
725 private List excludes = new ArrayList();
726
727 public BundlesSet(String def) {
728 StringTokenizer st = new StringTokenizer(def, ";");
729
730 if (!st.hasMoreTokens())
731 throw new RuntimeException("Base dir not defined.");
732 try {
733 String dirPath = st.nextToken();
734
735 if (dirPath.startsWith("file:"))
736 dirPath = dirPath.substring("file:".length());
737
738 dir = new File(dirPath.replace('/', File.separatorChar))
739 .getCanonicalPath();
740 if (debug)
741 debug("Base dir: " + dir);
742 } catch (IOException e) {
743 throw new RuntimeException("Cannot convert to absolute path", e);
744 }
745
746 while (st.hasMoreTokens()) {
747 String tk = st.nextToken();
748 StringTokenizer stEq = new StringTokenizer(tk, "=");
749 String type = stEq.nextToken();
750 String pattern = stEq.nextToken();
751 if ("in".equals(type) || "include".equals(type)) {
752 includes.add(pattern);
753 } else if ("ex".equals(type) || "exclude".equals(type)) {
754 excludes.add(pattern);
755 } else if ("baseUrl".equals(type)) {
756 baseUrl = pattern;
757 } else {
758 System.err.println("Unkown bundles pattern type " + type);
759 }
760 }
761
762 if (excludeSvn && !excludes.contains(EXCLUDES_SVN_PATTERN)) {
763 excludes.add(EXCLUDES_SVN_PATTERN);
764 }
765 }
766
767 public String getDir() {
768 return dir;
769 }
770
771 public List getIncludes() {
772 return includes;
773 }
774
775 public List getExcludes() {
776 return excludes;
777 }
778
779 public String getBaseUrl() {
780 return baseUrl;
781 }
782
783 }
784
785 public void setDefaultTimeout(long defaultTimeout) {
786 this.defaultTimeout = defaultTimeout;
787 }
788
789 public void setModulesUrlSeparator(String modulesUrlSeparator) {
790 this.modulesUrlSeparator = modulesUrlSeparator;
791 }
792
793 }