2 * Copyright (C) 2010 Mathieu Baudier <mbaudier@argeo.org>
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.
17 package org
.argeo
.osgi
.boot
;
19 import java
.io
.BufferedReader
;
21 import java
.io
.IOException
;
22 import java
.io
.InputStream
;
23 import java
.io
.InputStreamReader
;
25 import java
.util
.ArrayList
;
26 import java
.util
.HashMap
;
27 import java
.util
.Iterator
;
28 import java
.util
.List
;
31 import java
.util
.StringTokenizer
;
32 import java
.util
.TreeMap
;
33 import java
.util
.TreeSet
;
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
.Constants
;
42 import org
.osgi
.framework
.ServiceReference
;
43 import org
.osgi
.service
.packageadmin
.ExportedPackage
;
44 import org
.osgi
.service
.packageadmin
.PackageAdmin
;
46 public class OsgiBoot
{
47 public final static String SYMBOLIC_NAME_OSGI_BOOT
= "org.argeo.osgi.boot";
48 public final static String SYMBOLIC_NAME_EQUINOX
= "org.eclipse.osgi";
50 public final static String PROP_ARGEO_OSGI_DATA_DIR
= "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_LOCATIONS
= "argeo.osgi.locations";
55 public final static String PROP_ARGEO_OSGI_BASE_URL
= "argeo.osgi.baseUrl";
56 public final static String PROP_ARGEO_OSGI_MODULES_URL
= "argeo.osgi.modulesUrl";
58 public final static String PROP_ARGEO_OSGI_BOOT_DEBUG
= "argeo.osgi.boot.debug";
59 public final static String PROP_ARGEO_OSGI_BOOT_DEFAULT_TIMEOUT
= "argeo.osgi.boot.defaultTimeout";
60 public final static String PROP_ARGEO_OSGI_BOOT_MODULES_URL_SEPARATOR
= "argeo.osgi.boot.modulesUrlSeparator";
61 public final static String PROP_ARGEO_OSGI_BOOT_SYSTEM_PROPERTIES_FILE
= "argeo.osgi.boot.systemPropertiesFile";
62 public final static String PROP_ARGEO_OSGI_BOOT_APPCLASS
= "argeo.osgi.boot.appclass";
63 public final static String PROP_ARGEO_OSGI_BOOT_APPARGS
= "argeo.osgi.boot.appargs";
66 public final static String PROP_SLC_OSGI_START
= "slc.osgi.start";
68 public final static String PROP_SLC_OSGI_BUNDLES
= "slc.osgi.bundles";
70 public final static String PROP_SLC_OSGI_LOCATIONS
= "slc.osgi.locations";
72 public final static String PROP_SLC_OSGI_BASE_URL
= "slc.osgi.baseUrl";
74 public final static String PROP_SLC_OSGI_MODULES_URL
= "slc.osgi.modulesUrl";
77 public final static String PROP_SLC_OSGIBOOT_DEBUG
= "slc.osgiboot.debug";
79 public final static String PROP_SLC_OSGIBOOT_DEFAULT_TIMEOUT
= "slc.osgiboot.defaultTimeout";
81 public final static String PROP_SLC_OSGIBOOT_MODULES_URL_SEPARATOR
= "slc.osgiboot.modulesUrlSeparator";
83 public final static String PROP_SLC_OSGIBOOT_SYSTEM_PROPERTIES_FILE
= "slc.osgiboot.systemPropertiesFile";
85 public final static String PROP_SLC_OSGIBOOT_APPCLASS
= "slc.osgiboot.appclass";
87 public final static String PROP_SLC_OSGIBOOT_APPARGS
= "slc.osgiboot.appargs";
89 public final static String DEFAULT_BASE_URL
= "reference:file:";
90 public final static String EXCLUDES_SVN_PATTERN
= "**/.svn/**";
92 private boolean debug
= Boolean
.valueOf(
93 System
.getProperty(PROP_ARGEO_OSGI_BOOT_DEBUG
,
94 System
.getProperty(PROP_SLC_OSGIBOOT_DEBUG
, "false")))
96 /** Default is 10s (set in constructor) */
97 private long defaultTimeout
;
99 private boolean excludeSvn
= true;
100 /** Default is ',' (set in constructor) */
101 private String modulesUrlSeparator
= ",";
103 private final BundleContext bundleContext
;
105 public OsgiBoot(BundleContext bundleContext
) {
106 this.bundleContext
= bundleContext
;
107 defaultTimeout
= Long
.parseLong(OsgiBootUtils
.getPropertyCompat(
108 PROP_ARGEO_OSGI_BOOT_DEFAULT_TIMEOUT
,
109 PROP_SLC_OSGIBOOT_DEFAULT_TIMEOUT
, "10000"));
110 modulesUrlSeparator
= OsgiBootUtils
.getPropertyCompat(
111 PROP_ARGEO_OSGI_BOOT_MODULES_URL_SEPARATOR
,
112 PROP_SLC_OSGIBOOT_MODULES_URL_SEPARATOR
, ",");
113 initSystemProperties();
116 protected void initSystemProperties() {
117 String osgiInstanceArea
= System
.getProperty("osgi.instance.area");
118 String osgiInstanceAreaDefault
= System
119 .getProperty("osgi.instance.area.default");
120 String tempDir
= System
.getProperty("java.io.tmpdir");
123 if (osgiInstanceArea
!= null) {
124 // within OSGi with -data specified
125 osgiInstanceArea
= removeFilePrefix(osgiInstanceArea
);
126 dataDir
= new File(osgiInstanceArea
);
127 } else if (osgiInstanceAreaDefault
!= null) {
128 // within OSGi without -data specified
129 osgiInstanceAreaDefault
= removeFilePrefix(osgiInstanceAreaDefault
);
130 dataDir
= new File(osgiInstanceAreaDefault
);
131 } else {// outside OSGi
132 dataDir
= new File(tempDir
+ File
.separator
+ "argeoOsgiData");
135 System
.setProperty(PROP_ARGEO_OSGI_DATA_DIR
, dataDir
.getAbsolutePath());
137 // TODO: Load additional system properties from file
138 // Properties additionalSystemProperties = new Properties();
142 public static String
removeFilePrefix(String url
) {
143 if (url
.startsWith("file:"))
144 return url
.substring("file:".length());
145 else if (url
.startsWith("reference:file:"))
146 return url
.substring("reference:file:".length());
151 public void bootstrap() {
152 long begin
= System
.currentTimeMillis();
153 System
.out
.println();
154 OsgiBootUtils
.info("OSGi bootstrap starting...");
155 OsgiBootUtils
.info("Writable data directory : "
156 + System
.getProperty(PROP_ARGEO_OSGI_DATA_DIR
)
157 + " (set as system property " + PROP_ARGEO_OSGI_DATA_DIR
+ ")");
158 installUrls(getBundlesUrls());
159 installUrls(getLocationsUrls());
160 installUrls(getModulesUrls());
163 long duration
= System
.currentTimeMillis() - begin
;
164 OsgiBootUtils
.info("OSGi bootstrap completed in "
165 + Math
.round(((double) duration
) / 1000) + "s (" + duration
166 + "ms), " + bundleContext
.getBundles().length
+ " bundles");
168 // display packages exported twice
170 Map
/* <String,Set<String>> */duplicatePackages
= findPackagesExportedTwice();
171 if (duplicatePackages
.size() > 0) {
172 OsgiBootUtils
.info("Packages exported twice:");
173 Iterator it
= duplicatePackages
.keySet().iterator();
174 while (it
.hasNext()) {
175 String pkgName
= it
.next().toString();
176 OsgiBootUtils
.info(pkgName
);
177 Set bdles
= (Set
) duplicatePackages
.get(pkgName
);
178 Iterator bdlesIt
= bdles
.iterator();
179 while (bdlesIt
.hasNext())
180 OsgiBootUtils
.info(" " + bdlesIt
.next());
185 System
.out
.println();
188 public void installUrls(List urls
) {
189 Map installedBundles
= getInstalledBundles();
190 for (int i
= 0; i
< urls
.size(); i
++) {
191 String url
= (String
) urls
.get(i
);
193 if (installedBundles
.containsKey(url
)) {
194 Bundle bundle
= (Bundle
) installedBundles
.get(url
);
197 debug("Bundle " + bundle
.getSymbolicName()
198 + " already installed from " + url
);
200 Bundle bundle
= bundleContext
.installBundle(url
);
202 debug("Installed bundle " + bundle
.getSymbolicName()
205 } catch (BundleException e
) {
206 String message
= e
.getMessage();
207 if ((message
.contains("Bundle \"" + SYMBOLIC_NAME_OSGI_BOOT
208 + "\"") || message
.contains("Bundle \""
209 + SYMBOLIC_NAME_EQUINOX
+ "\""))
210 && message
.contains("has already been installed")) {
211 // silent, in order to avoid warnings: we know that both
212 // have already been installed...
214 OsgiBootUtils
.warn("Could not install bundle from " + url
224 public void installOrUpdateUrls(Map urls
) {
225 Map installedBundles
= getBundles();
227 for (Iterator modules
= urls
.keySet().iterator(); modules
.hasNext();) {
228 String moduleName
= (String
) modules
.next();
229 String urlStr
= (String
) urls
.get(moduleName
);
230 if (installedBundles
.containsKey(moduleName
)) {
231 Bundle bundle
= (Bundle
) installedBundles
.get(moduleName
);
234 URL url
= new URL(urlStr
);
235 in
= url
.openStream();
237 OsgiBootUtils
.info("Updated bundle " + moduleName
238 + " from " + urlStr
);
239 } catch (Exception e
) {
240 throw new RuntimeException("Cannot update " + moduleName
241 + " from " + urlStr
);
246 } catch (IOException e
) {
251 Bundle bundle
= bundleContext
.installBundle(urlStr
);
253 debug("Installed bundle " + bundle
.getSymbolicName()
254 + " from " + urlStr
);
255 } catch (BundleException e
) {
256 OsgiBootUtils
.warn("Could not install bundle from "
257 + urlStr
+ ": " + e
.getMessage());
264 public void startBundles() {
265 String bundlesToStart
= OsgiBootUtils
.getPropertyCompat(
266 PROP_ARGEO_OSGI_START
, PROP_SLC_OSGI_START
);
267 startBundles(bundlesToStart
);
270 public void startBundles(String bundlesToStartStr
) {
271 if (bundlesToStartStr
== null)
274 StringTokenizer st
= new StringTokenizer(bundlesToStartStr
, ",");
275 List bundlesToStart
= new ArrayList();
276 while (st
.hasMoreTokens()) {
277 String name
= st
.nextToken().trim();
278 bundlesToStart
.add(name
);
280 startBundles(bundlesToStart
);
283 public void startBundles(List bundlesToStart
) {
284 if (bundlesToStart
.size() == 0)
287 // used to log the bundles not found
288 List notFoundBundles
= new ArrayList(bundlesToStart
);
290 Bundle
[] bundles
= bundleContext
.getBundles();
291 long startBegin
= System
.currentTimeMillis();
292 for (int i
= 0; i
< bundles
.length
; i
++) {
293 Bundle bundle
= bundles
[i
];
294 String symbolicName
= bundle
.getSymbolicName();
295 if (bundlesToStart
.contains(symbolicName
))
299 } catch (Exception e
) {
300 OsgiBootUtils
.warn("Start of bundle " + symbolicName
301 + " failed because of " + e
302 + ", maybe bundle is not yet resolved,"
303 + " waiting and trying again.");
304 waitForBundleResolvedOrActive(startBegin
, bundle
);
307 notFoundBundles
.remove(symbolicName
);
308 } catch (Exception e
) {
309 OsgiBootUtils
.warn("Bundle " + symbolicName
310 + " cannot be started: " + e
.getMessage());
313 // was found even if start failed
314 notFoundBundles
.remove(symbolicName
);
318 for (int i
= 0; i
< notFoundBundles
.size(); i
++)
319 OsgiBootUtils
.warn("Bundle " + notFoundBundles
.get(i
)
320 + " not started because it was not found.");
323 protected void checkUnresolved() {
325 ServiceReference packageAdminRef
= bundleContext
326 .getServiceReference(PackageAdmin
.class.getName());
327 PackageAdmin packageAdmin
= (PackageAdmin
) bundleContext
328 .getService(packageAdminRef
);
329 packageAdmin
.resolveBundles(null);
331 Bundle
[] bundles
= bundleContext
.getBundles();
332 List
/* Bundle */unresolvedBundles
= new ArrayList();
333 for (int i
= 0; i
< bundles
.length
; i
++) {
334 int bundleState
= bundles
[i
].getState();
335 if (!(bundleState
== Bundle
.ACTIVE
336 || bundleState
== Bundle
.RESOLVED
|| bundleState
== Bundle
.STARTING
))
337 unresolvedBundles
.add(bundles
[i
]);
340 if (unresolvedBundles
.size() != 0) {
341 OsgiBootUtils
.warn("Unresolved bundles " + unresolvedBundles
);
345 public Map
findPackagesExportedTwice() {
346 ServiceReference paSr
= bundleContext
347 .getServiceReference(PackageAdmin
.class.getName());
348 // TODO: make a cleaner referencing
349 PackageAdmin packageAdmin
= (PackageAdmin
) bundleContext
352 // find packages exported twice
353 Bundle
[] bundles
= bundleContext
.getBundles();
354 Map
/* <String,Set<String>> */exportedPackages
= new TreeMap();
355 for (int i
= 0; i
< bundles
.length
; i
++) {
356 Bundle bundle
= bundles
[i
];
357 ExportedPackage
[] pkgs
= packageAdmin
.getExportedPackages(bundle
);
359 for (int j
= 0; j
< pkgs
.length
; j
++) {
360 String pkgName
= pkgs
[j
].getName();
361 if (!exportedPackages
.containsKey(pkgName
)) {
362 exportedPackages
.put(pkgName
, new TreeSet());
364 ((Set
) exportedPackages
.get(pkgName
)).add(bundle
365 .getSymbolicName() + "_" + bundle
.getVersion());
368 Map
/* <String,Set<String>> */duplicatePackages
= new TreeMap();
369 Iterator it
= exportedPackages
.keySet().iterator();
370 while (it
.hasNext()) {
371 String pkgName
= it
.next().toString();
372 Set bdles
= (Set
) exportedPackages
.get(pkgName
);
373 if (bdles
.size() > 1)
374 duplicatePackages
.put(pkgName
, bdles
);
376 return duplicatePackages
;
379 protected void waitForBundleResolvedOrActive(long startBegin
, Bundle bundle
)
381 int originalState
= bundle
.getState();
382 if ((originalState
== Bundle
.RESOLVED
)
383 || (originalState
== Bundle
.ACTIVE
))
386 String originalStateStr
= stateAsString(originalState
);
388 int currentState
= bundle
.getState();
389 while (!(currentState
== Bundle
.RESOLVED
|| currentState
== Bundle
.ACTIVE
)) {
390 long now
= System
.currentTimeMillis();
391 if ((now
- startBegin
) > defaultTimeout
)
392 throw new Exception("Bundle " + bundle
.getSymbolicName()
393 + " was not RESOLVED or ACTIVE after "
394 + (now
- startBegin
) + "ms (originalState="
395 + originalStateStr
+ ", currentState="
396 + stateAsString(currentState
) + ")");
400 } catch (InterruptedException e
) {
403 currentState
= bundle
.getState();
407 public static String
stateAsString(int state
) {
409 case Bundle
.UNINSTALLED
:
410 return "UNINSTALLED";
411 case Bundle
.INSTALLED
:
413 case Bundle
.RESOLVED
:
415 case Bundle
.STARTING
:
419 case Bundle
.STOPPING
:
422 return Integer
.toString(state
);
426 /** Key is location */
427 public Map
getInstalledBundles() {
428 Map installedBundles
= new HashMap();
430 Bundle
[] bundles
= bundleContext
.getBundles();
431 for (int i
= 0; i
< bundles
.length
; i
++) {
432 installedBundles
.put(bundles
[i
].getLocation(), bundles
[i
]);
434 return installedBundles
;
437 /** Key is symbolic name */
438 public Map
getBundles() {
439 Map namedBundles
= new HashMap();
440 Bundle
[] bundles
= bundleContext
.getBundles();
441 for (int i
= 0; i
< bundles
.length
; i
++) {
442 namedBundles
.put(bundles
[i
].getSymbolicName(), bundles
[i
]);
447 public List
getLocationsUrls() {
448 String baseUrl
= OsgiBootUtils
.getPropertyCompat(
449 PROP_ARGEO_OSGI_BASE_URL
, PROP_SLC_OSGI_BASE_URL
,
451 String bundleLocations
= OsgiBootUtils
.getPropertyCompat(
452 PROP_ARGEO_OSGI_LOCATIONS
, PROP_SLC_OSGI_LOCATIONS
);
453 return getLocationsUrls(baseUrl
, bundleLocations
);
456 public List
getModulesUrls() {
457 List urls
= new ArrayList();
458 String modulesUrlStr
= OsgiBootUtils
.getPropertyCompat(
459 PROP_ARGEO_OSGI_MODULES_URL
, PROP_SLC_OSGI_MODULES_URL
);
460 if (modulesUrlStr
== null)
463 String baseUrl
= OsgiBootUtils
.getPropertyCompat(
464 PROP_ARGEO_OSGI_BASE_URL
, PROP_SLC_OSGI_BASE_URL
);
466 Map installedBundles
= getBundles();
468 BufferedReader reader
= null;
470 URL modulesUrl
= new URL(modulesUrlStr
);
471 reader
= new BufferedReader(new InputStreamReader(
472 modulesUrl
.openStream()));
474 while ((line
= reader
.readLine()) != null) {
475 StringTokenizer st
= new StringTokenizer(line
,
476 modulesUrlSeparator
);
477 String moduleName
= st
.nextToken();
478 String moduleVersion
= st
.nextToken();
479 String url
= st
.nextToken();
483 if (installedBundles
.containsKey(moduleName
)) {
484 Bundle bundle
= (Bundle
) installedBundles
.get(moduleName
);
485 String bundleVersion
= bundle
.getHeaders()
486 .get(Constants
.BUNDLE_VERSION
).toString();
487 int comp
= compareVersions(bundleVersion
, moduleVersion
);
489 OsgiBootUtils
.warn("Installed version " + bundleVersion
490 + " of bundle " + moduleName
491 + " is newer than provided version "
493 } else if (comp
< 0) {
495 OsgiBootUtils
.info("Updated bundle " + moduleName
496 + " with version " + moduleVersion
497 + " (old version was " + bundleVersion
+ ")");
505 } catch (Exception e1
) {
506 throw new RuntimeException("Cannot read url " + modulesUrlStr
, e1
);
511 } catch (IOException e
) {
519 * @return ==0: versions are identical, <0: tested version is newer, >0:
520 * currentVersion is newer.
522 protected int compareVersions(String currentVersion
, String testedVersion
) {
523 List cToks
= new ArrayList();
524 StringTokenizer cSt
= new StringTokenizer(currentVersion
, ".");
525 while (cSt
.hasMoreTokens())
526 cToks
.add(cSt
.nextToken());
527 List tToks
= new ArrayList();
528 StringTokenizer tSt
= new StringTokenizer(currentVersion
, ".");
529 while (tSt
.hasMoreTokens())
530 tToks
.add(tSt
.nextToken());
533 comp
: for (int i
= 0; i
< cToks
.size(); i
++) {
534 if (tToks
.size() <= i
) {
535 // equals until then, tested shorter
540 String c
= (String
) cToks
.get(i
);
541 String t
= (String
) tToks
.get(i
);
544 int cInt
= Integer
.parseInt(c
);
545 int tInt
= Integer
.parseInt(t
);
549 comp
= (cInt
- tInt
);
552 } catch (NumberFormatException e
) {
556 comp
= c
.compareTo(t
);
562 if (comp
== 0 && tToks
.size() > cToks
.size()) {
563 // equals until then, current shorter
570 public List
getLocationsUrls(String baseUrl
, String bundleLocations
) {
571 List urls
= new ArrayList();
573 if (bundleLocations
== null)
575 bundleLocations
= SystemPropertyUtils
576 .resolvePlaceholders(bundleLocations
);
578 debug(PROP_ARGEO_OSGI_LOCATIONS
+ "=" + bundleLocations
);
580 StringTokenizer st
= new StringTokenizer(bundleLocations
,
582 while (st
.hasMoreTokens()) {
583 urls
.add(locationToUrl(baseUrl
, st
.nextToken().trim()));
588 public List
getBundlesUrls() {
589 String baseUrl
= OsgiBootUtils
.getPropertyCompat(
590 PROP_ARGEO_OSGI_BASE_URL
, PROP_SLC_OSGI_BASE_URL
,
592 String bundlePatterns
= OsgiBootUtils
.getPropertyCompat(
593 PROP_ARGEO_OSGI_BUNDLES
, PROP_SLC_OSGI_BUNDLES
);
594 return getBundlesUrls(baseUrl
, bundlePatterns
);
597 public List
getBundlesUrls(String baseUrl
, String bundlePatterns
) {
598 List urls
= new ArrayList();
600 List bundlesSets
= new ArrayList();
601 if (bundlePatterns
== null)
603 bundlePatterns
= SystemPropertyUtils
604 .resolvePlaceholders(bundlePatterns
);
606 debug(PROP_ARGEO_OSGI_BUNDLES
+ "=" + bundlePatterns
607 + " (excludeSvn=" + excludeSvn
+ ")");
609 StringTokenizer st
= new StringTokenizer(bundlePatterns
, ",");
610 while (st
.hasMoreTokens()) {
611 bundlesSets
.add(new BundlesSet(st
.nextToken()));
614 List included
= new ArrayList();
615 PathMatcher matcher
= new AntPathMatcher();
616 for (int i
= 0; i
< bundlesSets
.size(); i
++) {
617 BundlesSet bundlesSet
= (BundlesSet
) bundlesSets
.get(i
);
618 for (int j
= 0; j
< bundlesSet
.getIncludes().size(); j
++) {
619 String pattern
= (String
) bundlesSet
.getIncludes().get(j
);
620 match(matcher
, included
, bundlesSet
.getDir(), null, pattern
);
624 List excluded
= new ArrayList();
625 for (int i
= 0; i
< bundlesSets
.size(); i
++) {
626 BundlesSet bundlesSet
= (BundlesSet
) bundlesSets
.get(i
);
627 for (int j
= 0; j
< bundlesSet
.getExcludes().size(); j
++) {
628 String pattern
= (String
) bundlesSet
.getExcludes().get(j
);
629 match(matcher
, excluded
, bundlesSet
.getDir(), null, pattern
);
633 for (int i
= 0; i
< included
.size(); i
++) {
634 String fullPath
= (String
) included
.get(i
);
635 if (!excluded
.contains(fullPath
))
636 urls
.add(locationToUrl(baseUrl
, fullPath
));
642 protected void match(PathMatcher matcher
, List matched
, String base
,
643 String currentPath
, String pattern
) {
644 if (currentPath
== null) {
646 File baseDir
= new File(base
.replace('/', File
.separatorChar
));
647 File
[] files
= baseDir
.listFiles();
650 OsgiBootUtils
.warn("Base dir " + baseDir
651 + " has no children, exists=" + baseDir
.exists()
652 + ", isDirectory=" + baseDir
.isDirectory());
656 for (int i
= 0; i
< files
.length
; i
++)
657 match(matcher
, matched
, base
, files
[i
].getName(), pattern
);
659 String fullPath
= base
+ '/' + currentPath
;
660 if (matched
.contains(fullPath
))
661 return;// don't try deeper if already matched
663 boolean ok
= matcher
.match(pattern
, currentPath
);
665 debug(currentPath
+ " " + (ok ?
"" : " not ")
666 + " matched with " + pattern
);
668 matched
.add(fullPath
);
671 String newFullPath
= relativeToFullPath(base
, currentPath
);
672 File newFile
= new File(newFullPath
);
673 File
[] files
= newFile
.listFiles();
675 for (int i
= 0; i
< files
.length
; i
++) {
676 String newCurrentPath
= currentPath
+ '/'
677 + files
[i
].getName();
678 if (files
[i
].isDirectory()) {
679 if (matcher
.matchStart(pattern
, newCurrentPath
)) {
680 // recurse only if start matches
681 match(matcher
, matched
, base
, newCurrentPath
,
686 + " does not start match with "
691 boolean nonDirectoryOk
= matcher
.match(pattern
,
694 debug(currentPath
+ " " + (ok ?
"" : " not ")
695 + " matched with " + pattern
);
697 matched
.add(relativeToFullPath(base
,
706 protected String
locationToUrl(String baseUrl
, String location
) {
707 int extInd
= location
.lastIndexOf('.');
710 ext
= location
.substring(extInd
);
712 if (baseUrl
.startsWith("reference:") && ".jar".equals(ext
))
713 return "file:" + location
;
715 return baseUrl
+ location
;
718 /** Transforms a relative path in a full system path. */
719 protected String
relativeToFullPath(String basePath
, String relativePath
) {
720 return (basePath
+ '/' + relativePath
).replace('/', File
.separatorChar
);
723 protected void debug(Object obj
) {
725 OsgiBootUtils
.debug(obj
);
728 public boolean getDebug() {
732 public void setDebug(boolean debug
) {
736 public BundleContext
getBundleContext() {
737 return bundleContext
;
740 /** Whether to exclude Subversion directories (true by default) */
741 public boolean isExcludeSvn() {
745 public void setExcludeSvn(boolean excludeSvn
) {
746 this.excludeSvn
= excludeSvn
;
749 protected class BundlesSet
{
750 private String baseUrl
= "reference:file";// not used yet
751 private final String dir
;
752 private List includes
= new ArrayList();
753 private List excludes
= new ArrayList();
755 public BundlesSet(String def
) {
756 StringTokenizer st
= new StringTokenizer(def
, ";");
758 if (!st
.hasMoreTokens())
759 throw new RuntimeException("Base dir not defined.");
761 String dirPath
= st
.nextToken();
763 if (dirPath
.startsWith("file:"))
764 dirPath
= dirPath
.substring("file:".length());
766 dir
= new File(dirPath
.replace('/', File
.separatorChar
))
769 debug("Base dir: " + dir
);
770 } catch (IOException e
) {
771 throw new RuntimeException("Cannot convert to absolute path", e
);
774 while (st
.hasMoreTokens()) {
775 String tk
= st
.nextToken();
776 StringTokenizer stEq
= new StringTokenizer(tk
, "=");
777 String type
= stEq
.nextToken();
778 String pattern
= stEq
.nextToken();
779 if ("in".equals(type
) || "include".equals(type
)) {
780 includes
.add(pattern
);
781 } else if ("ex".equals(type
) || "exclude".equals(type
)) {
782 excludes
.add(pattern
);
783 } else if ("baseUrl".equals(type
)) {
786 System
.err
.println("Unkown bundles pattern type " + type
);
790 if (excludeSvn
&& !excludes
.contains(EXCLUDES_SVN_PATTERN
)) {
791 excludes
.add(EXCLUDES_SVN_PATTERN
);
795 public String
getDir() {
799 public List
getIncludes() {
803 public List
getExcludes() {
807 public String
getBaseUrl() {
813 public void setDefaultTimeout(long defaultTimeout
) {
814 this.defaultTimeout
= defaultTimeout
;
817 public void setModulesUrlSeparator(String modulesUrlSeparator
) {
818 this.modulesUrlSeparator
= modulesUrlSeparator
;