X-Git-Url: http://git.argeo.org/?a=blobdiff_plain;f=org.argeo.osgi.boot%2Fsrc%2Forg%2Fargeo%2Fosgi%2Fboot%2FOsgiBoot.java;h=38da0479f6d5579742f9d00c655c35fd2c254416;hb=79e0a2a5d751c7c077e52f9ee54469656dc96a44;hp=300ebb82dd48ba2802b3328cd832fd3a3dc1dbbe;hpb=575dfe19b8516b1213b6d56d9f34fc3bcdb62026;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/OsgiBoot.java b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/OsgiBoot.java index 300ebb82d..38da0479f 100644 --- a/org.argeo.osgi.boot/src/org/argeo/osgi/boot/OsgiBoot.java +++ b/org.argeo.osgi.boot/src/org/argeo/osgi/boot/OsgiBoot.java @@ -15,11 +15,12 @@ */ package org.argeo.osgi.boot; -import java.io.BufferedReader; +import static org.argeo.osgi.boot.OsgiBootUtils.debug; +import static org.argeo.osgi.boot.OsgiBootUtils.warn; + import java.io.File; -import java.io.IOException; -import java.io.InputStreamReader; -import java.net.URL; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; @@ -30,87 +31,71 @@ import java.util.Set; import java.util.SortedMap; import java.util.StringTokenizer; import java.util.TreeMap; -import java.util.TreeSet; +import org.argeo.osgi.a2.A2Source; +import org.argeo.osgi.a2.ProvisioningManager; import org.argeo.osgi.boot.internal.springutil.AntPathMatcher; import org.argeo.osgi.boot.internal.springutil.PathMatcher; import org.argeo.osgi.boot.internal.springutil.SystemPropertyUtils; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext; import org.osgi.framework.BundleException; -import org.osgi.framework.Constants; -import org.osgi.framework.ServiceReference; -import org.osgi.service.packageadmin.ExportedPackage; -import org.osgi.service.packageadmin.PackageAdmin; +import org.osgi.framework.FrameworkEvent; +import org.osgi.framework.Version; +import org.osgi.framework.startlevel.BundleStartLevel; +import org.osgi.framework.startlevel.FrameworkStartLevel; +import org.osgi.framework.wiring.FrameworkWiring; /** * Basic provisioning of an OSGi runtime via file path patterns and system - * properties. Java 1.4 compatible.
- * The approach is to generate list of URLs based on various methods, configured - * via system properties. + * properties. The approach is to generate list of URLs based on various + * methods, configured via properties. */ -public class OsgiBoot { - public final static String SYMBOLIC_NAME_OSGI_BOOT = "org.argeo.osgi.boot"; - public final static String SYMBOLIC_NAME_EQUINOX = "org.eclipse.osgi"; - - public final static String PROP_OSGI_STARTLEVEL = "osgi.startLevel"; - public final static String PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL = "osgi.bundles.defaultStartLevel"; - - public final static String PROP_ARGEO_OSGI_DATA_DIR = "argeo.osgi.data.dir"; - +public class OsgiBoot implements OsgiBootConstants { public final static String PROP_ARGEO_OSGI_START = "argeo.osgi.start"; + public final static String PROP_ARGEO_OSGI_SOURCES = "argeo.osgi.sources"; + public final static String PROP_ARGEO_OSGI_BUNDLES = "argeo.osgi.bundles"; - public final static String PROP_ARGEO_OSGI_LOCATIONS = "argeo.osgi.locations"; public final static String PROP_ARGEO_OSGI_BASE_URL = "argeo.osgi.baseUrl"; - /** @deprecated */ - public final static String PROP_ARGEO_OSGI_MODULES_URL = "argeo.osgi.modulesUrl"; + public final static String PROP_ARGEO_OSGI_LOCAL_CACHE = "argeo.osgi.localCache"; public final static String PROP_ARGEO_OSGI_DISTRIBUTION_URL = "argeo.osgi.distributionUrl"; // booleans public final static String PROP_ARGEO_OSGI_BOOT_DEBUG = "argeo.osgi.boot.debug"; - public final static String PROP_ARGEO_OSGI_BOOT_EXCLUDE_SVN = "argeo.osgi.boot.excludeSvn"; - public final static String PROP_ARGEO_OSGI_BOOT_INSTALL_IN_LEXICOGRAPHIC_ORDER = "argeo.osgi.boot.installInLexicographicOrder"; + // public final static String PROP_ARGEO_OSGI_BOOT_EXCLUDE_SVN = + // "argeo.osgi.boot.excludeSvn"; - public final static String PROP_ARGEO_OSGI_BOOT_DEFAULT_TIMEOUT = "argeo.osgi.boot.defaultTimeout"; - public final static String PROP_ARGEO_OSGI_BOOT_MODULES_URL_SEPARATOR = "argeo.osgi.boot.modulesUrlSeparator"; public final static String PROP_ARGEO_OSGI_BOOT_SYSTEM_PROPERTIES_FILE = "argeo.osgi.boot.systemPropertiesFile"; public final static String PROP_ARGEO_OSGI_BOOT_APPCLASS = "argeo.osgi.boot.appclass"; public final static String PROP_ARGEO_OSGI_BOOT_APPARGS = "argeo.osgi.boot.appargs"; public final static String DEFAULT_BASE_URL = "reference:file:"; - public final static String EXCLUDES_SVN_PATTERN = "**/.svn/**"; + // public final static String EXCLUDES_SVN_PATTERN = "**/.svn/**"; // OSGi system properties - public final static String INSTANCE_AREA_PROP = "osgi.instance.area"; - public final static String INSTANCE_AREA_DEFAULT_PROP = "osgi.instance.area.default"; - - private boolean debug = Boolean.valueOf( - System.getProperty(PROP_ARGEO_OSGI_BOOT_DEBUG, "false")) - .booleanValue(); - /** Exclude svn metadata implicitely(a bit costly) */ - private boolean excludeSvn = Boolean.valueOf( - System.getProperty(PROP_ARGEO_OSGI_BOOT_EXCLUDE_SVN, "false")) - .booleanValue(); + final static String PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL = "osgi.bundles.defaultStartLevel"; + final static String PROP_OSGI_STARTLEVEL = "osgi.startLevel"; + final static String INSTANCE_AREA_PROP = "osgi.instance.area"; + final static String CONFIGURATION_AREA_PROP = "osgi.configuration.area"; - /** - * The {@link #installUrls(List)} methods won't follow the list order but - * order the urls according to the alphabetical order of the file names - * (last part of the URL). The goal is to stay closer from Eclipse PDE way - * of installing target platform bundles. - */ - private boolean installInLexicographicOrder = Boolean - .valueOf( - System.getProperty( - PROP_ARGEO_OSGI_BOOT_INSTALL_IN_LEXICOGRAPHIC_ORDER, - "true")).booleanValue();; + // Symbolic names + public final static String SYMBOLIC_NAME_OSGI_BOOT = "org.argeo.osgi.boot"; + public final static String SYMBOLIC_NAME_EQUINOX = "org.eclipse.osgi"; - /** Default is 10s (set in constructor) */ - private long defaultTimeout; + /** Exclude svn metadata implicitely(a bit costly) */ + // private boolean excludeSvn = + // Boolean.valueOf(System.getProperty(PROP_ARGEO_OSGI_BOOT_EXCLUDE_SVN, + // "false")) + // .booleanValue(); - /** Default is ',' (set in constructor) */ - private String modulesUrlSeparator = ","; + /** Default is 10s */ + @Deprecated + private long defaultTimeout = 10000l; private final BundleContext bundleContext; + private final String localCache; + + private final ProvisioningManager provisioningManager; /* * INITIALIZATION @@ -118,36 +103,30 @@ public class OsgiBoot { /** Constructor */ public OsgiBoot(BundleContext bundleContext) { this.bundleContext = bundleContext; - defaultTimeout = Long.parseLong(OsgiBootUtils.getProperty( - PROP_ARGEO_OSGI_BOOT_DEFAULT_TIMEOUT, "10000")); - modulesUrlSeparator = OsgiBootUtils.getProperty( - PROP_ARGEO_OSGI_BOOT_MODULES_URL_SEPARATOR, ","); - initSystemProperties(); + Path homePath = Paths.get(System.getProperty("user.home")).toAbsolutePath(); + String homeUri = homePath.toUri().toString(); + localCache = getProperty(PROP_ARGEO_OSGI_LOCAL_CACHE, homeUri + ".m2/repository/"); + + provisioningManager = new ProvisioningManager(bundleContext); + String sources = getProperty(PROP_ARGEO_OSGI_SOURCES); + if (sources == null) { + provisioningManager.registerDefaultSource(); + } else { + for (String source : sources.split(",")) { + if (source.trim().equals(A2Source.DEFAULT_A2_URI)) { + provisioningManager + .registerSource(A2Source.SCHEME_A2 + "://" + homePath.toString() + "/.local/share/osgi"); + provisioningManager.registerSource(A2Source.SCHEME_A2 + ":///usr/local/share/osgi"); + provisioningManager.registerSource(A2Source.SCHEME_A2 + ":///usr/share/osgi"); + } else { + provisioningManager.registerSource(source); + } + } + } } - /** - * Set additional system properties, especially ${argeo.osgi.data.dir} as an - * OS file path (and not a file:// URL) - */ - protected void initSystemProperties() { - String osgiInstanceArea = System.getProperty(INSTANCE_AREA_PROP); - String osgiInstanceAreaDefault = System - .getProperty(INSTANCE_AREA_DEFAULT_PROP); - String tempDir = System.getProperty("java.io.tmpdir"); - - File dataDir = null; - if (osgiInstanceArea != null) { - // within OSGi with -data specified - osgiInstanceArea = removeFilePrefix(osgiInstanceArea); - dataDir = new File(osgiInstanceArea); - } else if (osgiInstanceAreaDefault != null) { - // within OSGi without -data specified - osgiInstanceAreaDefault = removeFilePrefix(osgiInstanceAreaDefault); - dataDir = new File(osgiInstanceAreaDefault); - } else {// outside OSGi - dataDir = new File(tempDir + File.separator + "argeoOsgiData"); - } - System.setProperty(PROP_ARGEO_OSGI_DATA_DIR, dataDir.getAbsolutePath()); + ProvisioningManager getProvisioningManager() { + return provisioningManager; } /* @@ -155,115 +134,137 @@ public class OsgiBoot { */ /** Bootstraps the OSGi runtime */ public void bootstrap() { - long begin = System.currentTimeMillis(); - System.out.println(); - OsgiBootUtils.info("OSGi bootstrap starting..."); - OsgiBootUtils.info("Writable data directory : " - + System.getProperty(PROP_ARGEO_OSGI_DATA_DIR) - + " (set as system property " + PROP_ARGEO_OSGI_DATA_DIR + ")"); - installUrls(getBundlesUrls()); - installUrls(getLocationsUrls()); - installUrls(getModulesUrls()); - installUrls(getDistributionUrls()); - checkUnresolved(); - startBundles(); - long duration = System.currentTimeMillis() - begin; - OsgiBootUtils.info("OSGi bootstrap completed in " - + Math.round(((double) duration) / 1000) + "s (" + duration - + "ms), " + bundleContext.getBundles().length + " bundles"); - - // display packages exported twice - if (debug) { - Map /* > */duplicatePackages = findPackagesExportedTwice(); + try { + long begin = System.currentTimeMillis(); + System.out.println(); + String osgiInstancePath = bundleContext.getProperty(INSTANCE_AREA_PROP); + OsgiBootUtils + .info("OSGi bootstrap starting" + (osgiInstancePath != null ? " (" + osgiInstancePath + ")" : "")); + installUrls(getBundlesUrls()); + installUrls(getDistributionUrls()); + provisioningManager.install(null); + startBundles(); + long duration = System.currentTimeMillis() - begin; + OsgiBootUtils.info("OSGi bootstrap completed in " + Math.round(((double) duration) / 1000) + "s (" + + duration + "ms), " + bundleContext.getBundles().length + " bundles"); + } catch (RuntimeException e) { + OsgiBootUtils.error("OSGi bootstrap FAILED", e); + throw e; + } + + // diagnostics + if (OsgiBootUtils.debug) { + OsgiBootDiagnostics diagnostics = new OsgiBootDiagnostics(bundleContext); + diagnostics.checkUnresolved(); + Map> duplicatePackages = diagnostics.findPackagesExportedTwice(); if (duplicatePackages.size() > 0) { OsgiBootUtils.info("Packages exported twice:"); - Iterator it = duplicatePackages.keySet().iterator(); + Iterator it = duplicatePackages.keySet().iterator(); while (it.hasNext()) { - String pkgName = it.next().toString(); + String pkgName = it.next(); OsgiBootUtils.info(pkgName); - Set bdles = (Set) duplicatePackages.get(pkgName); - Iterator bdlesIt = bdles.iterator(); + Set bdles = duplicatePackages.get(pkgName); + Iterator bdlesIt = bdles.iterator(); while (bdlesIt.hasNext()) OsgiBootUtils.info(" " + bdlesIt.next()); } } } - System.out.println(); } + public void update() { + provisioningManager.update(); + } + /* * INSTALLATION */ /** Install a single url. Convenience method. */ public Bundle installUrl(String url) { - List urls = new ArrayList(); + List urls = new ArrayList(); urls.add(url); installUrls(urls); return (Bundle) getBundlesByLocation().get(url); } /** Install the bundles at this URL list. */ - public void installUrls(List urls) { - Map installedBundles = getBundlesByLocation(); - - if (installInLexicographicOrder) { - SortedMap map = new TreeMap(); - // reorder - for (int i = 0; i < urls.size(); i++) { - String url = (String) urls.get(i); - int index = url.lastIndexOf('/'); - String fileName; - if (index >= 0) - fileName = url.substring(index + 1); - else - fileName = url; - map.put(fileName, url); - } - - // install - Iterator keys = map.keySet().iterator(); - while (keys.hasNext()) { - Object key = keys.next(); - String url = map.get(key).toString(); - installUrl(url, installedBundles); - } - } else { - for (int i = 0; i < urls.size(); i++) { - String url = (String) urls.get(i); - installUrl(url, installedBundles); - } + public void installUrls(List urls) { + Map installedBundles = getBundlesByLocation(); + for (int i = 0; i < urls.size(); i++) { + String url = (String) urls.get(i); + installUrl(url, installedBundles); } - + refreshFramework(); } /** Actually install the provided URL */ - protected void installUrl(String url, Map installedBundles) { + protected void installUrl(String url, Map installedBundles) { try { if (installedBundles.containsKey(url)) { Bundle bundle = (Bundle) installedBundles.get(url); - // bundle.update(); - if (debug) - debug("Bundle " + bundle.getSymbolicName() - + " already installed from " + url); + if (OsgiBootUtils.debug) + debug("Bundle " + bundle.getSymbolicName() + " already installed from " + url); + } else if (url.contains("/" + SYMBOLIC_NAME_EQUINOX + "/") + || url.contains("/" + SYMBOLIC_NAME_OSGI_BOOT + "/")) { + if (OsgiBootUtils.debug) + warn("Skip " + url); + return; } else { Bundle bundle = bundleContext.installBundle(url); - if (debug) - debug("Installed bundle " + bundle.getSymbolicName() - + " from " + url); + if (url.startsWith("http")) + OsgiBootUtils + .info("Installed " + bundle.getSymbolicName() + "-" + bundle.getVersion() + " from " + url); + else if (OsgiBootUtils.debug) + OsgiBootUtils.debug( + "Installed " + bundle.getSymbolicName() + "-" + bundle.getVersion() + " from " + url); + assert bundle.getSymbolicName() != null; + // uninstall previous versions + bundles: for (Bundle b : bundleContext.getBundles()) { + if (b.getSymbolicName() == null) + continue bundles; + if (bundle.getSymbolicName().equals(b.getSymbolicName())) { + Version bundleV = bundle.getVersion(); + Version bV = b.getVersion(); + if (bV == null) + continue bundles; + if (bundleV.getMajor() == bV.getMajor() && bundleV.getMinor() == bV.getMinor()) { + if (bundleV.getMicro() > bV.getMicro()) { + // uninstall older bundles + b.uninstall(); + OsgiBootUtils.debug("Uninstalled " + b); + } else if (bundleV.getMicro() < bV.getMicro()) { + // uninstall just installed bundle if newer + bundle.uninstall(); + OsgiBootUtils.debug("Uninstalled " + bundle); + break bundles; + } else { + // uninstall any other with same major/minor + if (!bundleV.getQualifier().equals(bV.getQualifier())) { + b.uninstall(); + OsgiBootUtils.debug("Uninstalled " + b); + } + } + } + } + } } } catch (BundleException e) { + final String ALREADY_INSTALLED = "is already installed"; String message = e.getMessage(); - if ((message.contains("Bundle \"" + SYMBOLIC_NAME_OSGI_BOOT + "\"") || message - .contains("Bundle \"" + SYMBOLIC_NAME_EQUINOX + "\"")) - && message.contains("has already been installed")) { + if ((message.contains("Bundle \"" + SYMBOLIC_NAME_OSGI_BOOT + "\"") + || message.contains("Bundle \"" + SYMBOLIC_NAME_EQUINOX + "\"")) + && message.contains(ALREADY_INSTALLED)) { // silent, in order to avoid warnings: we know that both // have already been installed... } else { - OsgiBootUtils.warn("Could not install bundle from " + url - + ": " + message); + if (message.contains(ALREADY_INSTALLED)) { + if (OsgiBootUtils.isDebug()) + OsgiBootUtils.warn("Duplicate install from " + url + ": " + message); + } else + OsgiBootUtils.warn("Could not install bundle from " + url + ": " + message); } - if (debug) + if (OsgiBootUtils.debug && !message.contains(ALREADY_INSTALLED)) e.printStackTrace(); } } @@ -272,42 +273,62 @@ public class OsgiBoot { * START */ public void startBundles() { + startBundles(System.getProperties()); + } + + public void startBundles(Properties properties) { + FrameworkStartLevel frameworkStartLevel = bundleContext.getBundle(0).adapt(FrameworkStartLevel.class); + // default and active start levels from System properties - Integer defaultStartLevel = new Integer(Integer.parseInt(OsgiBootUtils - .getProperty(PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL, "4"))); - Integer activeStartLevel = new Integer(OsgiBootUtils.getProperty( - PROP_OSGI_STARTLEVEL, "6")); - - SortedMap/* > */startLevels = new TreeMap(); - computeStartLevels(startLevels, System.getProperties(), - defaultStartLevel); - - Iterator/* */levels = startLevels.keySet().iterator(); - while (levels.hasNext()) { - Integer level = (Integer) levels.next(); - boolean allStarted = startBundles((List) startLevels.get(level)); - if (!allStarted) - OsgiBootUtils - .warn("Not all bundles started for level " + level); - if (level.equals(activeStartLevel)) - break;// active start level reached + Integer defaultStartLevel = new Integer( + Integer.parseInt(getProperty(PROP_OSGI_BUNDLES_DEFAULTSTARTLEVEL, "4"))); + Integer activeStartLevel = new Integer(getProperty(PROP_OSGI_STARTLEVEL, "6")); + + SortedMap> startLevels = new TreeMap>(); + computeStartLevels(startLevels, properties, defaultStartLevel); + // inverts the map for the time being, TODO optimise + Map bundleStartLevels = new HashMap<>(); + for (Integer level : startLevels.keySet()) { + for (String bsn : startLevels.get(level)) + bundleStartLevels.put(bsn, level); } - + for (Bundle bundle : bundleContext.getBundles()) { + String bsn = bundle.getSymbolicName(); + if (bundleStartLevels.containsKey(bsn)) { + BundleStartLevel bundleStartLevel = bundle.adapt(BundleStartLevel.class); + Integer level = bundleStartLevels.get(bsn); + if (bundleStartLevel.getStartLevel() != level || !bundleStartLevel.isPersistentlyStarted()) { + bundleStartLevel.setStartLevel(level); + try { + bundle.start(); + } catch (BundleException e) { + OsgiBootUtils.error("Cannot mark " + bsn + " as started", e); + } + if (getDebug()) + OsgiBootUtils.debug(bsn + " starts at level " + level); + } + } + } + frameworkStartLevel.setStartLevel(activeStartLevel, (FrameworkEvent event) -> { + if (getDebug()) + OsgiBootUtils.debug("Framework event: " + event); + int initialStartLevel = frameworkStartLevel.getInitialBundleStartLevel(); + int startLevel = frameworkStartLevel.getStartLevel(); + OsgiBootUtils.debug("Framework start level: " + startLevel + " (initial: " + initialStartLevel + ")"); + }); } - public static void computeStartLevels( - SortedMap/* > */startLevels, - Properties properties, Integer defaultStartLevel) { + private static void computeStartLevels(SortedMap> startLevels, Properties properties, + Integer defaultStartLevel) { // default (and previously, only behaviour) - appendToStartLevels(startLevels, defaultStartLevel, - properties.getProperty(PROP_ARGEO_OSGI_START, "")); + appendToStartLevels(startLevels, defaultStartLevel, properties.getProperty(PROP_ARGEO_OSGI_START, "")); // list argeo.osgi.start.* system properties - Iterator/* */keys = properties.keySet().iterator(); + Iterator keys = properties.keySet().iterator(); final String prefix = PROP_ARGEO_OSGI_START + "."; while (keys.hasNext()) { - String key = (String) keys.next(); + String key = keys.next().toString(); if (key.startsWith(prefix)) { Integer startLevel; String suffix = key.substring(prefix.length()); @@ -330,52 +351,35 @@ public class OsgiBoot { } /** Append a comma-separated list of bundles to the start levels. */ - private static void appendToStartLevels( - SortedMap/* > */startLevels, - Integer startLevel, String str) { + private static void appendToStartLevels(SortedMap> startLevels, Integer startLevel, + String str) { if (str == null || str.trim().equals("")) return; if (!startLevels.containsKey(startLevel)) - startLevels.put(startLevel, new ArrayList()); + startLevels.put(startLevel, new ArrayList()); String[] bundleNames = str.split(","); for (int i = 0; i < bundleNames.length; i++) { if (bundleNames[i] != null && !bundleNames[i].trim().equals("")) - ((List) startLevels.get(startLevel)).add(bundleNames[i]); + (startLevels.get(startLevel)).add(bundleNames[i]); } } - /** - * Convenience method accepting a comma-separated list of bundle to start - * - * @deprecated - */ - public void startBundles(String bundlesToStartStr) { - if (bundlesToStartStr == null) - return; - - StringTokenizer st = new StringTokenizer(bundlesToStartStr, ","); - List bundlesToStart = new ArrayList(); - while (st.hasMoreTokens()) { - String name = st.nextToken().trim(); - bundlesToStart.add(name); - } - startBundles(bundlesToStart); - } - /** * Start the provided list of bundles - * - * @return whether all bundlesa are now in active state + * + * @return whether all bundles are now in active state + * @deprecated */ - public boolean startBundles(List bundlesToStart) { + @Deprecated + public boolean startBundles(List bundlesToStart) { if (bundlesToStart.size() == 0) return true; // used to monitor ACTIVE states - List/* */startedBundles = new ArrayList(); + List startedBundles = new ArrayList(); // used to log the bundles not found - List/* */notFoundBundles = new ArrayList(bundlesToStart); + List notFoundBundles = new ArrayList(bundlesToStart); Bundle[] bundles = bundleContext.getBundles(); long startBegin = System.currentTimeMillis(); @@ -386,22 +390,19 @@ public class OsgiBoot { try { try { bundle.start(); - if (debug) + if (OsgiBootUtils.debug) debug("Bundle " + symbolicName + " started"); } catch (Exception e) { - OsgiBootUtils.warn("Start of bundle " + symbolicName - + " failed because of " + e - + ", maybe bundle is not yet resolved," - + " waiting and trying again."); + OsgiBootUtils.warn("Start of bundle " + symbolicName + " failed because of " + e + + ", maybe bundle is not yet resolved," + " waiting and trying again."); waitForBundleResolvedOrActive(startBegin, bundle); bundle.start(); startedBundles.add(bundle); } notFoundBundles.remove(symbolicName); } catch (Exception e) { - OsgiBootUtils.warn("Bundle " + symbolicName - + " cannot be started: " + e.getMessage()); - if (debug) + OsgiBootUtils.warn("Bundle " + symbolicName + " cannot be started: " + e.getMessage()); + if (OsgiBootUtils.debug) e.printStackTrace(); // was found even if start failed notFoundBundles.remove(symbolicName); @@ -409,16 +410,14 @@ public class OsgiBoot { } for (int i = 0; i < notFoundBundles.size(); i++) - OsgiBootUtils.warn("Bundle '" + notFoundBundles.get(i) - + "' not started because it was not found."); + OsgiBootUtils.warn("Bundle '" + notFoundBundles.get(i) + "' not started because it was not found."); // monitors that all bundles are started long beginMonitor = System.currentTimeMillis(); boolean allStarted = !(startedBundles.size() > 0); - List/* */notStarted = new ArrayList(); - while (!allStarted - && (System.currentTimeMillis() - beginMonitor) < defaultTimeout) { - notStarted = new ArrayList(); + List notStarted = new ArrayList(); + while (!allStarted && (System.currentTimeMillis() - beginMonitor) < defaultTimeout) { + notStarted = new ArrayList(); allStarted = true; for (int i = 0; i < startedBundles.size(); i++) { Bundle bundle = (Bundle) startedBundles.get(i); @@ -438,78 +437,16 @@ public class OsgiBoot { if (!allStarted) for (int i = 0; i < notStarted.size(); i++) - OsgiBootUtils.warn("Bundle '" + notStarted.get(i) - + "' not ACTIVE after " + (duration / 1000) + "s"); + OsgiBootUtils.warn("Bundle '" + notStarted.get(i) + "' not ACTIVE after " + (duration / 1000) + "s"); return allStarted; } - /* - * DIAGNOSTICS - */ - /** Check unresolved bundles */ - protected void checkUnresolved() { - // Refresh - ServiceReference packageAdminRef = bundleContext - .getServiceReference(PackageAdmin.class.getName()); - PackageAdmin packageAdmin = (PackageAdmin) bundleContext - .getService(packageAdminRef); - packageAdmin.resolveBundles(null); - - Bundle[] bundles = bundleContext.getBundles(); - List /* Bundle */unresolvedBundles = new ArrayList(); - for (int i = 0; i < bundles.length; i++) { - int bundleState = bundles[i].getState(); - if (!(bundleState == Bundle.ACTIVE - || bundleState == Bundle.RESOLVED || bundleState == Bundle.STARTING)) - unresolvedBundles.add(bundles[i]); - } - - if (unresolvedBundles.size() != 0) { - OsgiBootUtils.warn("Unresolved bundles " + unresolvedBundles); - } - } - - /** List packages exported twice. */ - public Map findPackagesExportedTwice() { - ServiceReference paSr = bundleContext - .getServiceReference(PackageAdmin.class.getName()); - PackageAdmin packageAdmin = (PackageAdmin) bundleContext - .getService(paSr); - - // find packages exported twice - Bundle[] bundles = bundleContext.getBundles(); - Map /* > */exportedPackages = new TreeMap(); - for (int i = 0; i < bundles.length; i++) { - Bundle bundle = bundles[i]; - ExportedPackage[] pkgs = packageAdmin.getExportedPackages(bundle); - if (pkgs != null) - for (int j = 0; j < pkgs.length; j++) { - String pkgName = pkgs[j].getName(); - if (!exportedPackages.containsKey(pkgName)) { - exportedPackages.put(pkgName, new TreeSet()); - } - ((Set) exportedPackages.get(pkgName)).add(bundle - .getSymbolicName() + "_" + bundle.getVersion()); - } - } - Map /* > */duplicatePackages = new TreeMap(); - Iterator it = exportedPackages.keySet().iterator(); - while (it.hasNext()) { - String pkgName = it.next().toString(); - Set bdles = (Set) exportedPackages.get(pkgName); - if (bdles.size() > 1) - duplicatePackages.put(pkgName, bdles); - } - return duplicatePackages; - } - /** Waits for a bundle to become active or resolved */ - protected void waitForBundleResolvedOrActive(long startBegin, Bundle bundle) - throws Exception { + @Deprecated + private void waitForBundleResolvedOrActive(long startBegin, Bundle bundle) throws Exception { int originalState = bundle.getState(); - if ((originalState == Bundle.RESOLVED) - || (originalState == Bundle.ACTIVE)) + if ((originalState == Bundle.RESOLVED) || (originalState == Bundle.ACTIVE)) return; String originalStateStr = OsgiBootUtils.stateAsString(originalState); @@ -518,10 +455,8 @@ public class OsgiBoot { while (!(currentState == Bundle.RESOLVED || currentState == Bundle.ACTIVE)) { long now = System.currentTimeMillis(); if ((now - startBegin) > defaultTimeout * 10) - throw new Exception("Bundle " + bundle.getSymbolicName() - + " was not RESOLVED or ACTIVE after " - + (now - startBegin) + "ms (originalState=" - + originalStateStr + ", currentState=" + throw new Exception("Bundle " + bundle.getSymbolicName() + " was not RESOLVED or ACTIVE after " + + (now - startBegin) + "ms (originalState=" + originalStateStr + ", currentState=" + OsgiBootUtils.stateAsString(currentState) + ")"); try { @@ -533,87 +468,53 @@ public class OsgiBoot { } } - /* - * EXPLICIT LOCATIONS INSTALLATION - */ - /** Gets the list of resolved explicit URL locations. */ - public List getLocationsUrls() { - String baseUrl = OsgiBootUtils.getProperty(PROP_ARGEO_OSGI_BASE_URL, - DEFAULT_BASE_URL); - String bundleLocations = OsgiBootUtils - .getProperty(PROP_ARGEO_OSGI_LOCATIONS); - return getLocationsUrls(baseUrl, bundleLocations); - } - - /** - * Gets a list of URLs based on explicit locations, resolving placeholder - * ${...} containing system properties, e.g. ${user.home}. - */ - public List getLocationsUrls(String baseUrl, String bundleLocations) { - List urls = new ArrayList(); - - if (bundleLocations == null) - return urls; - bundleLocations = SystemPropertyUtils - .resolvePlaceholders(bundleLocations); - if (debug) - debug(PROP_ARGEO_OSGI_LOCATIONS + "=" + bundleLocations); - - StringTokenizer st = new StringTokenizer(bundleLocations, - File.pathSeparator); - while (st.hasMoreTokens()) { - urls.add(locationToUrl(baseUrl, st.nextToken().trim())); - } - return urls; - } - /* * BUNDLE PATTERNS INSTALLATION */ /** - * Computes a list of URLs based on Ant-like incluide/exclude patterns - * defined by ${argeo.osgi.bundles} with the following format:
+ * Computes a list of URLs based on Ant-like include/exclude patterns defined by + * ${argeo.osgi.bundles} with the following format:
* /base/directory;in=*.jar;in=**;ex=org.eclipse.osgi_*;jar
* WARNING: /base/directory;in=*.jar,\ at the end of a file, - * without a new line causes a '.' to be appended with unexpected side - * effects. + * without a new line causes a '.' to be appended with unexpected side effects. */ - public List getBundlesUrls() { - String bundlePatterns = OsgiBootUtils - .getProperty(PROP_ARGEO_OSGI_BUNDLES); + public List getBundlesUrls() { + String bundlePatterns = getProperty(PROP_ARGEO_OSGI_BUNDLES); return getBundlesUrls(bundlePatterns); } /** - * Compute alist of URLs to install based on the provided patterns, with + * Compute a list of URLs to install based on the provided patterns, with * default base url */ - public List getBundlesUrls(String bundlePatterns) { - String baseUrl = OsgiBootUtils.getProperty(PROP_ARGEO_OSGI_BASE_URL, - DEFAULT_BASE_URL); + public List getBundlesUrls(String bundlePatterns) { + String baseUrl = getProperty(PROP_ARGEO_OSGI_BASE_URL, DEFAULT_BASE_URL); return getBundlesUrls(baseUrl, bundlePatterns); } /** Implements the path matching logic */ - List getBundlesUrls(String baseUrl, String bundlePatterns) { - List urls = new ArrayList(); + public List getBundlesUrls(String baseUrl, String bundlePatterns) { + List urls = new ArrayList(); if (bundlePatterns == null) return urls; - bundlePatterns = SystemPropertyUtils - .resolvePlaceholders(bundlePatterns); - if (debug) - debug(PROP_ARGEO_OSGI_BUNDLES + "=" + bundlePatterns - + " (excludeSvn=" + excludeSvn + ")"); + bundlePatterns = SystemPropertyUtils.resolvePlaceholders(bundlePatterns); + if (OsgiBootUtils.debug) + debug(PROP_ARGEO_OSGI_BUNDLES + "=" + bundlePatterns); StringTokenizer st = new StringTokenizer(bundlePatterns, ","); - List bundlesSets = new ArrayList(); + List bundlesSets = new ArrayList(); while (st.hasMoreTokens()) { - bundlesSets.add(new BundlesSet(st.nextToken())); + String token = st.nextToken(); + if (new File(token).exists()) { + String url = locationToUrl(baseUrl, token); + urls.add(url); + } else + bundlesSets.add(new BundlesSet(token)); } // find included - List included = new ArrayList(); + List included = new ArrayList(); PathMatcher matcher = new AntPathMatcher(); for (int i = 0; i < bundlesSets.size(); i++) { BundlesSet bundlesSet = (BundlesSet) bundlesSets.get(i); @@ -624,7 +525,7 @@ public class OsgiBoot { } // find excluded - List excluded = new ArrayList(); + List excluded = new ArrayList(); for (int i = 0; i < bundlesSets.size(); i++) { BundlesSet bundlesSet = (BundlesSet) bundlesSets.get(i); for (int j = 0; j < bundlesSet.getExcludes().size(); j++) { @@ -646,120 +547,73 @@ public class OsgiBoot { /* * DISTRIBUTION JAR INSTALLATION */ - public List getDistributionUrls() { - List urls = new ArrayList(); - String distributionUrl = OsgiBootUtils - .getProperty(PROP_ARGEO_OSGI_DISTRIBUTION_URL); + public List getDistributionUrls() { + String distributionUrl = getProperty(PROP_ARGEO_OSGI_DISTRIBUTION_URL); + String baseUrl = getProperty(PROP_ARGEO_OSGI_BASE_URL); + return getDistributionUrls(distributionUrl, baseUrl); + } + + public List getDistributionUrls(String distributionUrl, String baseUrl) { + List urls = new ArrayList(); if (distributionUrl == null) return urls; - String baseUrl = OsgiBootUtils.getProperty(PROP_ARGEO_OSGI_BASE_URL); DistributionBundle distributionBundle; - if (baseUrl != null - && !(distributionUrl.startsWith("http") || distributionUrl - .startsWith("file"))) { - // relative url - distributionBundle = new DistributionBundle(baseUrl, - distributionUrl); - } else { + if (distributionUrl.startsWith("http") || distributionUrl.startsWith("file")) { distributionBundle = new DistributionBundle(distributionUrl); if (baseUrl != null) distributionBundle.setBaseUrl(baseUrl); + } else { + // relative url + if (baseUrl == null) { + baseUrl = localCache; + } - } - distributionBundle.processUrl(); - return distributionBundle.listUrls(); - } - - /* - * MODULES LIST INSTALLATION (${argeo.osgi.modulesUrl}) - */ - /** - * Downloads a list of URLs in CSV format from ${argeo.osgi.modulesUrl}:
- * Bundle-SymbolicName,Bundle-Version,url)
- * If ${argeo.osgi.baseUrl} is set, URLs will be considered relative paths - * and be concatenated with the base URL, typically the root of a Maven - * repository. - * - * @deprecated - */ - public List getModulesUrls() { - List urls = new ArrayList(); - String modulesUrlStr = OsgiBootUtils - .getProperty(PROP_ARGEO_OSGI_MODULES_URL); - if (modulesUrlStr == null) - return urls; - - String baseUrl = OsgiBootUtils.getProperty(PROP_ARGEO_OSGI_BASE_URL); - - Map installedBundles = getBundlesBySymbolicName(); - - BufferedReader reader = null; - try { - URL modulesUrl = new URL(modulesUrlStr); - reader = new BufferedReader(new InputStreamReader( - modulesUrl.openStream())); - String line = null; - while ((line = reader.readLine()) != null) { - StringTokenizer st = new StringTokenizer(line, - modulesUrlSeparator); - String moduleName = st.nextToken(); - String moduleVersion = st.nextToken(); - String url = st.nextToken(); - if (baseUrl != null) - url = baseUrl + url; - - if (installedBundles.containsKey(moduleName)) { - Bundle bundle = (Bundle) installedBundles.get(moduleName); - String bundleVersion = bundle.getHeaders() - .get(Constants.BUNDLE_VERSION).toString(); - int comp = OsgiBootUtils.compareVersions(bundleVersion, - moduleVersion); - if (comp > 0) { - OsgiBootUtils.warn("Installed version " + bundleVersion - + " of bundle " + moduleName - + " is newer than provided version " - + moduleVersion); - } else if (comp < 0) { - urls.add(url); - OsgiBootUtils.info("Updated bundle " + moduleName - + " with version " + moduleVersion - + " (old version was " + bundleVersion + ")"); - } else { - // do nothing - } - } else { - urls.add(url); + if (distributionUrl.contains(":")) { + // TODO make it safer + String[] parts = distributionUrl.trim().split(":"); + String[] categoryParts = parts[0].split("\\."); + String artifactId = parts[1]; + String version = parts[2]; + StringBuilder sb = new StringBuilder(); + for (String categoryPart : categoryParts) { + sb.append(categoryPart).append('/'); } + sb.append(artifactId).append('/'); + sb.append(version).append('/'); + sb.append(artifactId).append('-').append(version).append(".jar"); + distributionUrl = sb.toString(); } - } catch (Exception e1) { - throw new RuntimeException("Cannot read url " + modulesUrlStr, e1); - } finally { - if (reader != null) - try { - reader.close(); - } catch (IOException e) { - e.printStackTrace(); - } + + distributionBundle = new DistributionBundle(baseUrl, distributionUrl, localCache); } - return urls; + // if (baseUrl != null && !(distributionUrl.startsWith("http") || + // distributionUrl.startsWith("file"))) { + // // relative url + // distributionBundle = new DistributionBundle(baseUrl, distributionUrl, + // localCache); + // } else { + // distributionBundle = new DistributionBundle(distributionUrl); + // if (baseUrl != null) + // distributionBundle.setBaseUrl(baseUrl); + // } + distributionBundle.processUrl(); + return distributionBundle.listUrls(); } /* * HIGH LEVEL UTILITIES */ /** Actually performs the matching logic. */ - protected void match(PathMatcher matcher, List matched, String base, - String currentPath, String pattern) { + protected void match(PathMatcher matcher, List matched, String base, String currentPath, String pattern) { if (currentPath == null) { // Init File baseDir = new File(base.replace('/', File.separatorChar)); File[] files = baseDir.listFiles(); if (files == null) { - if (debug) - OsgiBootUtils.warn("Base dir " + baseDir - + " has no children, exists=" + baseDir.exists() + if (OsgiBootUtils.debug) + OsgiBootUtils.warn("Base dir " + baseDir + " has no children, exists=" + baseDir.exists() + ", isDirectory=" + baseDir.isDirectory()); return; } @@ -784,29 +638,22 @@ public class OsgiBoot { File[] files = newFile.listFiles(); if (files != null) { for (int i = 0; i < files.length; i++) { - String newCurrentPath = currentPath + '/' - + files[i].getName(); + String newCurrentPath = currentPath + '/' + files[i].getName(); if (files[i].isDirectory()) { if (matcher.matchStart(pattern, newCurrentPath)) { // recurse only if start matches - match(matcher, matched, base, newCurrentPath, - pattern); + match(matcher, matched, base, newCurrentPath, pattern); } else { - if (debug) - debug(newCurrentPath - + " does not start match with " - + pattern); + if (OsgiBootUtils.debug) + debug(newCurrentPath + " does not start match with " + pattern); } } else { - boolean nonDirectoryOk = matcher.match(pattern, - newCurrentPath); - if (debug) - debug(currentPath + " " + (ok ? "" : " not ") - + " matched with " + pattern); + boolean nonDirectoryOk = matcher.match(pattern, newCurrentPath); + if (OsgiBootUtils.debug) + debug(currentPath + " " + (ok ? "" : " not ") + " matched with " + pattern); if (nonDirectoryOk) - matched.add(relativeToFullPath(base, - newCurrentPath)); + matched.add(relativeToFullPath(base, newCurrentPath)); } } } @@ -825,8 +672,8 @@ public class OsgiBoot { * The bundles already installed. Key is location (String) , value is a * {@link Bundle} */ - public Map getBundlesByLocation() { - Map installedBundles = new HashMap(); + public Map getBundlesByLocation() { + Map installedBundles = new HashMap(); Bundle[] bundles = bundleContext.getBundles(); for (int i = 0; i < bundles.length; i++) { installedBundles.put(bundles[i].getLocation(), bundles[i]); @@ -838,8 +685,8 @@ public class OsgiBoot { * The bundles already installed. Key is symbolic name (String) , value is a * {@link Bundle} */ - public Map getBundlesBySymbolicName() { - Map namedBundles = new HashMap(); + public Map getBundlesBySymbolicName() { + Map namedBundles = new HashMap(); Bundle[] bundles = bundleContext.getBundles(); for (int i = 0; i < bundles.length; i++) { namedBundles.put(bundles[i].getSymbolicName(), bundles[i]); @@ -849,14 +696,6 @@ public class OsgiBoot { /** Creates an URL from a location */ protected String locationToUrl(String baseUrl, String location) { - // int extInd = location.lastIndexOf('.'); - // String ext = null; - // if (extInd > 0) - // ext = location.substring(extInd); - // - // if (baseUrl.startsWith("reference:") && ".jar".equals(ext)) - // return "file:" + location; - // else return baseUrl + location; } @@ -865,21 +704,27 @@ public class OsgiBoot { return (basePath + '/' + relativePath).replace('/', File.separatorChar); } - private String removeFilePrefix(String url) { - if (url.startsWith("file:")) - return url.substring("file:".length()); - else if (url.startsWith("reference:file:")) - return url.substring("reference:file:".length()); - else - return url; + private void refreshFramework() { + Bundle systemBundle = bundleContext.getBundle(0); + FrameworkWiring frameworkWiring = systemBundle.adapt(FrameworkWiring.class); + frameworkWiring.refreshBundles(null); } /** - * Convenience method to avoid cluttering the code with - * OsgiBootUtils.debug() + * Gets a property value + * + * @return null when defaultValue is "" */ - protected void debug(Object obj) { - OsgiBootUtils.debug(obj); + public String getProperty(String name, String defaultValue) { + String value = bundleContext.getProperty(name); + if (value == null) + return defaultValue; // may be null + else + return value; + } + + public String getProperty(String name) { + return getProperty(name, null); } /* @@ -887,150 +732,35 @@ public class OsgiBoot { */ public boolean getDebug() { - return debug; + return OsgiBootUtils.debug; } - public void setDebug(boolean debug) { - this.debug = debug; - } + // public void setDebug(boolean debug) { + // this.debug = debug; + // } public BundleContext getBundleContext() { return bundleContext; } - public void setInstallInLexicographicOrder( - boolean installInAlphabeticalOrder) { - this.installInLexicographicOrder = installInAlphabeticalOrder; + public String getLocalCache() { + return localCache; } - public boolean isInstallInLexicographicOrder() { - return installInLexicographicOrder; - } - - public void setDefaultTimeout(long defaultTimeout) { - this.defaultTimeout = defaultTimeout; - } - - public void setModulesUrlSeparator(String modulesUrlSeparator) { - this.modulesUrlSeparator = modulesUrlSeparator; - } - - public boolean isExcludeSvn() { - return excludeSvn; - } + // public void setDefaultTimeout(long defaultTimeout) { + // this.defaultTimeout = defaultTimeout; + // } - public void setExcludeSvn(boolean excludeSvn) { - this.excludeSvn = excludeSvn; - } + // public boolean isExcludeSvn() { + // return excludeSvn; + // } + // + // public void setExcludeSvn(boolean excludeSvn) { + // this.excludeSvn = excludeSvn; + // } /* * INTERNAL CLASSES */ - /** Intermediary structure used by path matching */ - protected class BundlesSet { - private String baseUrl = "reference:file";// not used yet - private final String dir; - private List includes = new ArrayList(); - private List excludes = new ArrayList(); - - public BundlesSet(String def) { - StringTokenizer st = new StringTokenizer(def, ";"); - - if (!st.hasMoreTokens()) - throw new RuntimeException("Base dir not defined."); - try { - String dirPath = st.nextToken(); - - if (dirPath.startsWith("file:")) - dirPath = dirPath.substring("file:".length()); - - dir = new File(dirPath.replace('/', File.separatorChar)) - .getCanonicalPath(); - if (debug) - debug("Base dir: " + dir); - } catch (IOException e) { - throw new RuntimeException("Cannot convert to absolute path", e); - } - - while (st.hasMoreTokens()) { - String tk = st.nextToken(); - StringTokenizer stEq = new StringTokenizer(tk, "="); - String type = stEq.nextToken(); - String pattern = stEq.nextToken(); - if ("in".equals(type) || "include".equals(type)) { - includes.add(pattern); - } else if ("ex".equals(type) || "exclude".equals(type)) { - excludes.add(pattern); - } else if ("baseUrl".equals(type)) { - baseUrl = pattern; - } else { - System.err.println("Unkown bundles pattern type " + type); - } - } - - if (excludeSvn && !excludes.contains(EXCLUDES_SVN_PATTERN)) { - excludes.add(EXCLUDES_SVN_PATTERN); - } - } - - public String getDir() { - return dir; - } - - public List getIncludes() { - return includes; - } - - public List getExcludes() { - return excludes; - } - - public String getBaseUrl() { - return baseUrl; - } - - } - - /* @deprecated Doesn't seem to be used anymore. */ - // public void installOrUpdateUrls(Map urls) { - // Map installedBundles = getBundles(); - // - // for (Iterator modules = urls.keySet().iterator(); modules.hasNext();) { - // String moduleName = (String) modules.next(); - // String urlStr = (String) urls.get(moduleName); - // if (installedBundles.containsKey(moduleName)) { - // Bundle bundle = (Bundle) installedBundles.get(moduleName); - // InputStream in; - // try { - // URL url = new URL(urlStr); - // in = url.openStream(); - // bundle.update(in); - // OsgiBootUtils.info("Updated bundle " + moduleName - // + " from " + urlStr); - // } catch (Exception e) { - // throw new RuntimeException("Cannot update " + moduleName - // + " from " + urlStr); - // } - // if (in != null) - // try { - // in.close(); - // } catch (IOException e) { - // e.printStackTrace(); - // } - // } else { - // try { - // Bundle bundle = bundleContext.installBundle(urlStr); - // if (debug) - // debug("Installed bundle " + bundle.getSymbolicName() - // + " from " + urlStr); - // } catch (BundleException e) { - // OsgiBootUtils.warn("Could not install bundle from " - // + urlStr + ": " + e.getMessage()); - // } - // } - // } - // - // } - }