2 * Copyright (C) 2007-2012 Mathieu Baudier
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
16 package org
.argeo
.osgi
.boot
;
18 import java
.io
.BufferedReader
;
20 import java
.io
.IOException
;
21 import java
.io
.InputStreamReader
;
23 import java
.util
.ArrayList
;
24 import java
.util
.HashMap
;
25 import java
.util
.Iterator
;
26 import java
.util
.List
;
29 import java
.util
.SortedMap
;
30 import java
.util
.StringTokenizer
;
31 import java
.util
.TreeMap
;
32 import java
.util
.TreeSet
;
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
.Constants
;
41 import org
.osgi
.framework
.ServiceReference
;
42 import org
.osgi
.service
.packageadmin
.ExportedPackage
;
43 import org
.osgi
.service
.packageadmin
.PackageAdmin
;
46 * Basic provisioning of an OSGi runtime via file path patterns and system
47 * properties. Java 1.4 compatible.<br>
48 * The approach is to generate list of URLs based on various methods, configured
49 * via system properties.
51 public class OsgiBoot
{
52 public final static String SYMBOLIC_NAME_OSGI_BOOT
= "org.argeo.osgi.boot";
53 public final static String SYMBOLIC_NAME_EQUINOX
= "org.eclipse.osgi";
55 public final static String PROP_ARGEO_OSGI_DATA_DIR
= "argeo.osgi.data.dir";
57 public final static String PROP_ARGEO_OSGI_START
= "argeo.osgi.start";
58 public final static String PROP_ARGEO_OSGI_BUNDLES
= "argeo.osgi.bundles";
59 public final static String PROP_ARGEO_OSGI_LOCATIONS
= "argeo.osgi.locations";
60 public final static String PROP_ARGEO_OSGI_BASE_URL
= "argeo.osgi.baseUrl";
62 public final static String PROP_ARGEO_OSGI_MODULES_URL
= "argeo.osgi.modulesUrl";
63 public final static String PROP_ARGEO_OSGI_DISTRIBUTION_URL
= "argeo.osgi.distributionUrl";
66 public final static String PROP_ARGEO_OSGI_BOOT_DEBUG
= "argeo.osgi.boot.debug";
67 public final static String PROP_ARGEO_OSGI_BOOT_EXCLUDE_SVN
= "argeo.osgi.boot.excludeSvn";
68 public final static String PROP_ARGEO_OSGI_BOOT_INSTALL_IN_LEXICOGRAPHIC_ORDER
= "argeo.osgi.boot.installInLexicographicOrder";
70 public final static String PROP_ARGEO_OSGI_BOOT_DEFAULT_TIMEOUT
= "argeo.osgi.boot.defaultTimeout";
71 public final static String PROP_ARGEO_OSGI_BOOT_MODULES_URL_SEPARATOR
= "argeo.osgi.boot.modulesUrlSeparator";
72 public final static String PROP_ARGEO_OSGI_BOOT_SYSTEM_PROPERTIES_FILE
= "argeo.osgi.boot.systemPropertiesFile";
73 public final static String PROP_ARGEO_OSGI_BOOT_APPCLASS
= "argeo.osgi.boot.appclass";
74 public final static String PROP_ARGEO_OSGI_BOOT_APPARGS
= "argeo.osgi.boot.appargs";
76 public final static String DEFAULT_BASE_URL
= "reference:file:";
77 public final static String EXCLUDES_SVN_PATTERN
= "**/.svn/**";
79 // OSGi system properties
80 public final static String INSTANCE_AREA_PROP
= "osgi.instance.area";
81 public final static String INSTANCE_AREA_DEFAULT_PROP
= "osgi.instance.area.default";
83 private boolean debug
= Boolean
.valueOf(
84 System
.getProperty(PROP_ARGEO_OSGI_BOOT_DEBUG
, "true"))
86 /** Exclude svn metadata implicitely(a bit costly) */
87 private boolean excludeSvn
= Boolean
.valueOf(
88 System
.getProperty(PROP_ARGEO_OSGI_BOOT_EXCLUDE_SVN
, "false"))
92 * The {@link #installUrls(List)} methods won't follow the list order but
93 * order the urls according to the alphabetical order of the file names
94 * (last part of the URL). The goal is to stay closer from Eclipse PDE way
95 * of installing target platform bundles.
97 private boolean installInLexicographicOrder
= Boolean
100 PROP_ARGEO_OSGI_BOOT_INSTALL_IN_LEXICOGRAPHIC_ORDER
,
101 "true")).booleanValue();;
103 /** Default is 10s (set in constructor) */
104 private long defaultTimeout
;
106 /** Default is ',' (set in constructor) */
107 private String modulesUrlSeparator
= ",";
109 private final BundleContext bundleContext
;
115 public OsgiBoot(BundleContext bundleContext
) {
116 this.bundleContext
= bundleContext
;
117 defaultTimeout
= Long
.parseLong(OsgiBootUtils
.getProperty(
118 PROP_ARGEO_OSGI_BOOT_DEFAULT_TIMEOUT
, "10000"));
119 modulesUrlSeparator
= OsgiBootUtils
.getProperty(
120 PROP_ARGEO_OSGI_BOOT_MODULES_URL_SEPARATOR
, ",");
121 initSystemProperties();
125 * Set additional system properties, especially ${argeo.osgi.data.dir} as an
126 * OS file path (and not a file:// URL)
128 protected void initSystemProperties() {
129 String osgiInstanceArea
= System
.getProperty(INSTANCE_AREA_PROP
);
130 String osgiInstanceAreaDefault
= System
131 .getProperty(INSTANCE_AREA_DEFAULT_PROP
);
132 String tempDir
= System
.getProperty("java.io.tmpdir");
135 if (osgiInstanceArea
!= null) {
136 // within OSGi with -data specified
137 osgiInstanceArea
= removeFilePrefix(osgiInstanceArea
);
138 dataDir
= new File(osgiInstanceArea
);
139 } else if (osgiInstanceAreaDefault
!= null) {
140 // within OSGi without -data specified
141 osgiInstanceAreaDefault
= removeFilePrefix(osgiInstanceAreaDefault
);
142 dataDir
= new File(osgiInstanceAreaDefault
);
143 } else {// outside OSGi
144 dataDir
= new File(tempDir
+ File
.separator
+ "argeoOsgiData");
146 System
.setProperty(PROP_ARGEO_OSGI_DATA_DIR
, dataDir
.getAbsolutePath());
152 /** Bootstraps the OSGi runtime */
153 public void bootstrap() {
154 long begin
= System
.currentTimeMillis();
155 System
.out
.println();
156 OsgiBootUtils
.info("OSGi bootstrap starting...");
157 OsgiBootUtils
.info("Writable data directory : "
158 + System
.getProperty(PROP_ARGEO_OSGI_DATA_DIR
)
159 + " (set as system property " + PROP_ARGEO_OSGI_DATA_DIR
+ ")");
160 installUrls(getBundlesUrls());
161 installUrls(getLocationsUrls());
162 installUrls(getModulesUrls());
163 installUrls(getDistributionUrls());
166 long duration
= System
.currentTimeMillis() - begin
;
167 OsgiBootUtils
.info("OSGi bootstrap completed in "
168 + Math
.round(((double) duration
) / 1000) + "s (" + duration
169 + "ms), " + bundleContext
.getBundles().length
+ " bundles");
171 // display packages exported twice
173 Map
/* <String,Set<String>> */duplicatePackages
= findPackagesExportedTwice();
174 if (duplicatePackages
.size() > 0) {
175 OsgiBootUtils
.info("Packages exported twice:");
176 Iterator it
= duplicatePackages
.keySet().iterator();
177 while (it
.hasNext()) {
178 String pkgName
= it
.next().toString();
179 OsgiBootUtils
.info(pkgName
);
180 Set bdles
= (Set
) duplicatePackages
.get(pkgName
);
181 Iterator bdlesIt
= bdles
.iterator();
182 while (bdlesIt
.hasNext())
183 OsgiBootUtils
.info(" " + bdlesIt
.next());
188 System
.out
.println();
194 /** Install a single url. Convenience method. */
195 public Bundle
installUrl(String url
) {
196 List urls
= new ArrayList();
199 return (Bundle
) getBundlesByLocation().get(url
);
202 /** Install the bundles at this URL list. */
203 public void installUrls(List urls
) {
204 Map installedBundles
= getBundlesByLocation();
206 if (installInLexicographicOrder
) {
207 SortedMap map
= new TreeMap();
209 for (int i
= 0; i
< urls
.size(); i
++) {
210 String url
= (String
) urls
.get(i
);
211 int index
= url
.lastIndexOf('/');
214 fileName
= url
.substring(index
+ 1);
217 map
.put(fileName
, url
);
221 Iterator keys
= map
.keySet().iterator();
222 while (keys
.hasNext()) {
223 Object key
= keys
.next();
224 String url
= map
.get(key
).toString();
225 installUrl(url
, installedBundles
);
228 for (int i
= 0; i
< urls
.size(); i
++) {
229 String url
= (String
) urls
.get(i
);
230 installUrl(url
, installedBundles
);
236 /** Actually install the provided URL */
237 protected void installUrl(String url
, Map installedBundles
) {
239 if (installedBundles
.containsKey(url
)) {
240 Bundle bundle
= (Bundle
) installedBundles
.get(url
);
243 debug("Bundle " + bundle
.getSymbolicName()
244 + " already installed from " + url
);
246 Bundle bundle
= bundleContext
.installBundle(url
);
248 debug("Installed bundle " + bundle
.getSymbolicName()
251 } catch (BundleException e
) {
252 String message
= e
.getMessage();
253 if ((message
.contains("Bundle \"" + SYMBOLIC_NAME_OSGI_BOOT
+ "\"") || message
254 .contains("Bundle \"" + SYMBOLIC_NAME_EQUINOX
+ "\""))
255 && message
.contains("has already been installed")) {
256 // silent, in order to avoid warnings: we know that both
257 // have already been installed...
259 OsgiBootUtils
.warn("Could not install bundle from " + url
267 /* @deprecated Doesn't seem to be used anymore. */
268 // public void installOrUpdateUrls(Map urls) {
269 // Map installedBundles = getBundles();
271 // for (Iterator modules = urls.keySet().iterator(); modules.hasNext();) {
272 // String moduleName = (String) modules.next();
273 // String urlStr = (String) urls.get(moduleName);
274 // if (installedBundles.containsKey(moduleName)) {
275 // Bundle bundle = (Bundle) installedBundles.get(moduleName);
278 // URL url = new URL(urlStr);
279 // in = url.openStream();
280 // bundle.update(in);
281 // OsgiBootUtils.info("Updated bundle " + moduleName
282 // + " from " + urlStr);
283 // } catch (Exception e) {
284 // throw new RuntimeException("Cannot update " + moduleName
285 // + " from " + urlStr);
290 // } catch (IOException e) {
291 // e.printStackTrace();
295 // Bundle bundle = bundleContext.installBundle(urlStr);
297 // debug("Installed bundle " + bundle.getSymbolicName()
298 // + " from " + urlStr);
299 // } catch (BundleException e) {
300 // OsgiBootUtils.warn("Could not install bundle from "
301 // + urlStr + ": " + e.getMessage());
311 public void startBundles() {
312 String bundlesToStart
= OsgiBootUtils
313 .getProperty(PROP_ARGEO_OSGI_START
);
314 startBundles(bundlesToStart
);
317 /** Convenience method accepting a comma-separated list of bundle to start */
318 public void startBundles(String bundlesToStartStr
) {
319 if (bundlesToStartStr
== null)
322 StringTokenizer st
= new StringTokenizer(bundlesToStartStr
, ",");
323 List bundlesToStart
= new ArrayList();
324 while (st
.hasMoreTokens()) {
325 String name
= st
.nextToken().trim();
326 bundlesToStart
.add(name
);
328 startBundles(bundlesToStart
);
331 /** Start the provided list of bundles */
332 public void startBundles(List bundlesToStart
) {
333 if (bundlesToStart
.size() == 0)
336 // used to log the bundles not found
337 List notFoundBundles
= new ArrayList(bundlesToStart
);
339 Bundle
[] bundles
= bundleContext
.getBundles();
340 long startBegin
= System
.currentTimeMillis();
341 for (int i
= 0; i
< bundles
.length
; i
++) {
342 Bundle bundle
= bundles
[i
];
343 String symbolicName
= bundle
.getSymbolicName();
344 if (bundlesToStart
.contains(symbolicName
))
349 debug("Bundle " + symbolicName
+ " started");
350 } catch (Exception e
) {
351 OsgiBootUtils
.warn("Start of bundle " + symbolicName
352 + " failed because of " + e
353 + ", maybe bundle is not yet resolved,"
354 + " waiting and trying again.");
355 waitForBundleResolvedOrActive(startBegin
, bundle
);
358 notFoundBundles
.remove(symbolicName
);
359 } catch (Exception e
) {
360 OsgiBootUtils
.warn("Bundle " + symbolicName
361 + " cannot be started: " + e
.getMessage());
364 // was found even if start failed
365 notFoundBundles
.remove(symbolicName
);
369 for (int i
= 0; i
< notFoundBundles
.size(); i
++)
370 OsgiBootUtils
.warn("Bundle " + notFoundBundles
.get(i
)
371 + " not started because it was not found.");
377 /** Check unresolved bundles */
378 protected void checkUnresolved() {
380 ServiceReference packageAdminRef
= bundleContext
381 .getServiceReference(PackageAdmin
.class.getName());
382 PackageAdmin packageAdmin
= (PackageAdmin
) bundleContext
383 .getService(packageAdminRef
);
384 packageAdmin
.resolveBundles(null);
386 Bundle
[] bundles
= bundleContext
.getBundles();
387 List
/* Bundle */unresolvedBundles
= new ArrayList();
388 for (int i
= 0; i
< bundles
.length
; i
++) {
389 int bundleState
= bundles
[i
].getState();
390 if (!(bundleState
== Bundle
.ACTIVE
391 || bundleState
== Bundle
.RESOLVED
|| bundleState
== Bundle
.STARTING
))
392 unresolvedBundles
.add(bundles
[i
]);
395 if (unresolvedBundles
.size() != 0) {
396 OsgiBootUtils
.warn("Unresolved bundles " + unresolvedBundles
);
400 /** List packages exported twice. */
401 public Map
findPackagesExportedTwice() {
402 ServiceReference paSr
= bundleContext
403 .getServiceReference(PackageAdmin
.class.getName());
404 PackageAdmin packageAdmin
= (PackageAdmin
) bundleContext
407 // find packages exported twice
408 Bundle
[] bundles
= bundleContext
.getBundles();
409 Map
/* <String,Set<String>> */exportedPackages
= new TreeMap();
410 for (int i
= 0; i
< bundles
.length
; i
++) {
411 Bundle bundle
= bundles
[i
];
412 ExportedPackage
[] pkgs
= packageAdmin
.getExportedPackages(bundle
);
414 for (int j
= 0; j
< pkgs
.length
; j
++) {
415 String pkgName
= pkgs
[j
].getName();
416 if (!exportedPackages
.containsKey(pkgName
)) {
417 exportedPackages
.put(pkgName
, new TreeSet());
419 ((Set
) exportedPackages
.get(pkgName
)).add(bundle
420 .getSymbolicName() + "_" + bundle
.getVersion());
423 Map
/* <String,Set<String>> */duplicatePackages
= new TreeMap();
424 Iterator it
= exportedPackages
.keySet().iterator();
425 while (it
.hasNext()) {
426 String pkgName
= it
.next().toString();
427 Set bdles
= (Set
) exportedPackages
.get(pkgName
);
428 if (bdles
.size() > 1)
429 duplicatePackages
.put(pkgName
, bdles
);
431 return duplicatePackages
;
434 /** Waits for a bundle to become active or resolved */
435 protected void waitForBundleResolvedOrActive(long startBegin
, Bundle bundle
)
437 int originalState
= bundle
.getState();
438 if ((originalState
== Bundle
.RESOLVED
)
439 || (originalState
== Bundle
.ACTIVE
))
442 String originalStateStr
= OsgiBootUtils
.stateAsString(originalState
);
444 int currentState
= bundle
.getState();
445 while (!(currentState
== Bundle
.RESOLVED
|| currentState
== Bundle
.ACTIVE
)) {
446 long now
= System
.currentTimeMillis();
447 if ((now
- startBegin
) > defaultTimeout
)
448 throw new Exception("Bundle " + bundle
.getSymbolicName()
449 + " was not RESOLVED or ACTIVE after "
450 + (now
- startBegin
) + "ms (originalState="
451 + originalStateStr
+ ", currentState="
452 + OsgiBootUtils
.stateAsString(currentState
) + ")");
456 } catch (InterruptedException e
) {
459 currentState
= bundle
.getState();
464 * EXPLICIT LOCATIONS INSTALLATION
466 /** Gets the list of resolved explicit URL locations. */
467 public List
getLocationsUrls() {
468 String baseUrl
= OsgiBootUtils
.getProperty(PROP_ARGEO_OSGI_BASE_URL
,
470 String bundleLocations
= OsgiBootUtils
471 .getProperty(PROP_ARGEO_OSGI_LOCATIONS
);
472 return getLocationsUrls(baseUrl
, bundleLocations
);
476 * Gets a list of URLs based on explicit locations, resolving placeholder
477 * ${...} containing system properties, e.g. ${user.home}.
479 public List
getLocationsUrls(String baseUrl
, String bundleLocations
) {
480 List urls
= new ArrayList();
482 if (bundleLocations
== null)
484 bundleLocations
= SystemPropertyUtils
485 .resolvePlaceholders(bundleLocations
);
487 debug(PROP_ARGEO_OSGI_LOCATIONS
+ "=" + bundleLocations
);
489 StringTokenizer st
= new StringTokenizer(bundleLocations
,
491 while (st
.hasMoreTokens()) {
492 urls
.add(locationToUrl(baseUrl
, st
.nextToken().trim()));
498 * BUNDLE PATTERNS INSTALLATION
501 * Computes a list of URLs based on Ant-like incluide/exclude patterns
502 * defined by ${argeo.osgi.bundles} with the following format:<br>
503 * <code>/base/directory;in=*.jar;in=**;ex=org.eclipse.osgi_*;jar</code><br>
504 * WARNING: <code>/base/directory;in=*.jar,\</code> at the end of a file,
505 * without a new line causes a '.' to be appended with unexpected side
508 public List
getBundlesUrls() {
509 String bundlePatterns
= OsgiBootUtils
510 .getProperty(PROP_ARGEO_OSGI_BUNDLES
);
511 return getBundlesUrls(bundlePatterns
);
515 * Compute alist of URLs to install based on the provided patterns, with
518 public List
getBundlesUrls(String bundlePatterns
) {
519 String baseUrl
= OsgiBootUtils
.getProperty(PROP_ARGEO_OSGI_BASE_URL
,
521 return getBundlesUrls(baseUrl
, bundlePatterns
);
524 /** Implements the path matching logic */
525 List
getBundlesUrls(String baseUrl
, String bundlePatterns
) {
526 List urls
= new ArrayList();
527 if (bundlePatterns
== null)
530 bundlePatterns
= SystemPropertyUtils
531 .resolvePlaceholders(bundlePatterns
);
533 debug(PROP_ARGEO_OSGI_BUNDLES
+ "=" + bundlePatterns
534 + " (excludeSvn=" + excludeSvn
+ ")");
536 StringTokenizer st
= new StringTokenizer(bundlePatterns
, ",");
537 List bundlesSets
= new ArrayList();
538 while (st
.hasMoreTokens()) {
539 bundlesSets
.add(new BundlesSet(st
.nextToken()));
543 List included
= new ArrayList();
544 PathMatcher matcher
= new AntPathMatcher();
545 for (int i
= 0; i
< bundlesSets
.size(); i
++) {
546 BundlesSet bundlesSet
= (BundlesSet
) bundlesSets
.get(i
);
547 for (int j
= 0; j
< bundlesSet
.getIncludes().size(); j
++) {
548 String pattern
= (String
) bundlesSet
.getIncludes().get(j
);
549 match(matcher
, included
, bundlesSet
.getDir(), null, pattern
);
554 List excluded
= new ArrayList();
555 for (int i
= 0; i
< bundlesSets
.size(); i
++) {
556 BundlesSet bundlesSet
= (BundlesSet
) bundlesSets
.get(i
);
557 for (int j
= 0; j
< bundlesSet
.getExcludes().size(); j
++) {
558 String pattern
= (String
) bundlesSet
.getExcludes().get(j
);
559 match(matcher
, excluded
, bundlesSet
.getDir(), null, pattern
);
564 for (int i
= 0; i
< included
.size(); i
++) {
565 String fullPath
= (String
) included
.get(i
);
566 if (!excluded
.contains(fullPath
))
567 urls
.add(locationToUrl(baseUrl
, fullPath
));
574 * DISTRIBUTION JAR INSTALLATION
576 public List
getDistributionUrls() {
577 List urls
= new ArrayList();
578 String distributionUrl
= OsgiBootUtils
579 .getProperty(PROP_ARGEO_OSGI_DISTRIBUTION_URL
);
580 if (distributionUrl
== null)
582 String baseUrl
= OsgiBootUtils
.getProperty(PROP_ARGEO_OSGI_BASE_URL
);
584 DistributionBundle distributionBundle
;
586 && !(distributionUrl
.startsWith("http") || distributionUrl
587 .startsWith("file"))) {
589 distributionBundle
= new DistributionBundle(baseUrl
,
592 distributionBundle
= new DistributionBundle(distributionUrl
);
594 distributionBundle
.setBaseUrl(baseUrl
);
597 distributionBundle
.processUrl();
598 return distributionBundle
.listUrls();
602 * MODULES LIST INSTALLATION (${argeo.osgi.modulesUrl})
605 * Downloads a list of URLs in CSV format from ${argeo.osgi.modulesUrl}:<br>
606 * <code>Bundle-SymbolicName,Bundle-Version,url</code>)<br>
607 * If ${argeo.osgi.baseUrl} is set, URLs will be considered relative paths
608 * and be concatenated with the base URL, typically the root of a Maven
613 public List
getModulesUrls() {
614 List urls
= new ArrayList();
615 String modulesUrlStr
= OsgiBootUtils
616 .getProperty(PROP_ARGEO_OSGI_MODULES_URL
);
617 if (modulesUrlStr
== null)
620 String baseUrl
= OsgiBootUtils
.getProperty(PROP_ARGEO_OSGI_BASE_URL
);
622 Map installedBundles
= getBundlesBySymbolicName();
624 BufferedReader reader
= null;
626 URL modulesUrl
= new URL(modulesUrlStr
);
627 reader
= new BufferedReader(new InputStreamReader(
628 modulesUrl
.openStream()));
630 while ((line
= reader
.readLine()) != null) {
631 StringTokenizer st
= new StringTokenizer(line
,
632 modulesUrlSeparator
);
633 String moduleName
= st
.nextToken();
634 String moduleVersion
= st
.nextToken();
635 String url
= st
.nextToken();
639 if (installedBundles
.containsKey(moduleName
)) {
640 Bundle bundle
= (Bundle
) installedBundles
.get(moduleName
);
641 String bundleVersion
= bundle
.getHeaders()
642 .get(Constants
.BUNDLE_VERSION
).toString();
643 int comp
= OsgiBootUtils
.compareVersions(bundleVersion
,
646 OsgiBootUtils
.warn("Installed version " + bundleVersion
647 + " of bundle " + moduleName
648 + " is newer than provided version "
650 } else if (comp
< 0) {
652 OsgiBootUtils
.info("Updated bundle " + moduleName
653 + " with version " + moduleVersion
654 + " (old version was " + bundleVersion
+ ")");
662 } catch (Exception e1
) {
663 throw new RuntimeException("Cannot read url " + modulesUrlStr
, e1
);
668 } catch (IOException e
) {
676 * HIGH LEVEL UTILITIES
678 /** Actually performs the matching logic. */
679 protected void match(PathMatcher matcher
, List matched
, String base
,
680 String currentPath
, String pattern
) {
681 if (currentPath
== null) {
683 File baseDir
= new File(base
.replace('/', File
.separatorChar
));
684 File
[] files
= baseDir
.listFiles();
688 OsgiBootUtils
.warn("Base dir " + baseDir
689 + " has no children, exists=" + baseDir
.exists()
690 + ", isDirectory=" + baseDir
.isDirectory());
694 for (int i
= 0; i
< files
.length
; i
++)
695 match(matcher
, matched
, base
, files
[i
].getName(), pattern
);
697 String fullPath
= base
+ '/' + currentPath
;
698 if (matched
.contains(fullPath
))
699 return;// don't try deeper if already matched
701 boolean ok
= matcher
.match(pattern
, currentPath
);
703 // debug(currentPath + " " + (ok ? "" : " not ")
704 // + " matched with " + pattern);
706 matched
.add(fullPath
);
709 String newFullPath
= relativeToFullPath(base
, currentPath
);
710 File newFile
= new File(newFullPath
);
711 File
[] files
= newFile
.listFiles();
713 for (int i
= 0; i
< files
.length
; i
++) {
714 String newCurrentPath
= currentPath
+ '/'
715 + files
[i
].getName();
716 if (files
[i
].isDirectory()) {
717 if (matcher
.matchStart(pattern
, newCurrentPath
)) {
718 // recurse only if start matches
719 match(matcher
, matched
, base
, newCurrentPath
,
724 + " does not start match with "
729 boolean nonDirectoryOk
= matcher
.match(pattern
,
732 debug(currentPath
+ " " + (ok ?
"" : " not ")
733 + " matched with " + pattern
);
735 matched
.add(relativeToFullPath(base
,
744 protected void matchFile() {
749 * LOW LEVEL UTILITIES
752 * The bundles already installed. Key is location (String) , value is a
755 public Map
getBundlesByLocation() {
756 Map installedBundles
= new HashMap();
757 Bundle
[] bundles
= bundleContext
.getBundles();
758 for (int i
= 0; i
< bundles
.length
; i
++) {
759 installedBundles
.put(bundles
[i
].getLocation(), bundles
[i
]);
761 return installedBundles
;
765 * The bundles already installed. Key is symbolic name (String) , value is a
768 public Map
getBundlesBySymbolicName() {
769 Map namedBundles
= new HashMap();
770 Bundle
[] bundles
= bundleContext
.getBundles();
771 for (int i
= 0; i
< bundles
.length
; i
++) {
772 namedBundles
.put(bundles
[i
].getSymbolicName(), bundles
[i
]);
777 /** Creates an URL from a location */
778 protected String
locationToUrl(String baseUrl
, String location
) {
779 int extInd
= location
.lastIndexOf('.');
782 ext
= location
.substring(extInd
);
784 if (baseUrl
.startsWith("reference:") && ".jar".equals(ext
))
785 return "file:" + location
;
787 return baseUrl
+ location
;
790 /** Transforms a relative path in a full system path. */
791 protected String
relativeToFullPath(String basePath
, String relativePath
) {
792 return (basePath
+ '/' + relativePath
).replace('/', File
.separatorChar
);
795 private String
removeFilePrefix(String url
) {
796 if (url
.startsWith("file:"))
797 return url
.substring("file:".length());
798 else if (url
.startsWith("reference:file:"))
799 return url
.substring("reference:file:".length());
805 * Convenience method to avoid cluttering the code with
806 * OsgiBootUtils.debug()
808 protected void debug(Object obj
) {
809 OsgiBootUtils
.debug(obj
);
816 public boolean getDebug() {
820 public void setDebug(boolean debug
) {
824 public BundleContext
getBundleContext() {
825 return bundleContext
;
828 public void setInstallInLexicographicOrder(
829 boolean installInAlphabeticalOrder
) {
830 this.installInLexicographicOrder
= installInAlphabeticalOrder
;
833 public boolean isInstallInLexicographicOrder() {
834 return installInLexicographicOrder
;
837 public void setDefaultTimeout(long defaultTimeout
) {
838 this.defaultTimeout
= defaultTimeout
;
841 public void setModulesUrlSeparator(String modulesUrlSeparator
) {
842 this.modulesUrlSeparator
= modulesUrlSeparator
;
845 public boolean isExcludeSvn() {
849 public void setExcludeSvn(boolean excludeSvn
) {
850 this.excludeSvn
= excludeSvn
;
857 /** Intermediary structure used by path matching */
858 protected class BundlesSet
{
859 private String baseUrl
= "reference:file";// not used yet
860 private final String dir
;
861 private List includes
= new ArrayList();
862 private List excludes
= new ArrayList();
864 public BundlesSet(String def
) {
865 StringTokenizer st
= new StringTokenizer(def
, ";");
867 if (!st
.hasMoreTokens())
868 throw new RuntimeException("Base dir not defined.");
870 String dirPath
= st
.nextToken();
872 if (dirPath
.startsWith("file:"))
873 dirPath
= dirPath
.substring("file:".length());
875 dir
= new File(dirPath
.replace('/', File
.separatorChar
))
878 debug("Base dir: " + dir
);
879 } catch (IOException e
) {
880 throw new RuntimeException("Cannot convert to absolute path", e
);
883 while (st
.hasMoreTokens()) {
884 String tk
= st
.nextToken();
885 StringTokenizer stEq
= new StringTokenizer(tk
, "=");
886 String type
= stEq
.nextToken();
887 String pattern
= stEq
.nextToken();
888 if ("in".equals(type
) || "include".equals(type
)) {
889 includes
.add(pattern
);
890 } else if ("ex".equals(type
) || "exclude".equals(type
)) {
891 excludes
.add(pattern
);
892 } else if ("baseUrl".equals(type
)) {
895 System
.err
.println("Unkown bundles pattern type " + type
);
899 if (excludeSvn
&& !excludes
.contains(EXCLUDES_SVN_PATTERN
)) {
900 excludes
.add(EXCLUDES_SVN_PATTERN
);
904 public String
getDir() {
908 public List
getIncludes() {
912 public List
getExcludes() {
916 public String
getBaseUrl() {