From: Mathieu Baudier Date: Tue, 13 Jul 2010 09:28:17 +0000 (+0000) Subject: Rename packages in OSGi boot X-Git-Tag: argeo-commons-2.1.30~1592 X-Git-Url: https://git.argeo.org/?a=commitdiff_plain;h=1b452a434924d7628c7b2eace3c5df8e62cdea1c;p=lgpl%2Fargeo-commons.git Rename packages in OSGi boot git-svn-id: https://svn.argeo.org/commons/trunk@3668 4cfe0d0a-d680-48aa-b62c-e0a02a3f76cc --- diff --git a/osgi/runtime/org.argeo.osgi.boot/pom.xml b/osgi/runtime/org.argeo.osgi.boot/pom.xml index c324ee78e..cb16149c7 100644 --- a/osgi/runtime/org.argeo.osgi.boot/pom.xml +++ b/osgi/runtime/org.argeo.osgi.boot/pom.xml @@ -37,7 +37,7 @@ ${version.maven-bundle-plugin} - org.argeo.slc.osgiboot.Activator + org.argeo.osgi.boot.Activator diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/Activator.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/Activator.java new file mode 100644 index 000000000..9eecf6cbd --- /dev/null +++ b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/Activator.java @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2010 Mathieu Baudier + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.argeo.osgi.boot; + +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; + +/** + * An OSGi configurator. See http: + * //wiki.eclipse.org/Configurator + */ +public class Activator implements BundleActivator { + + public void start(BundleContext bundleContext) throws Exception { + OsgiBoot osgiBoot = new OsgiBoot(bundleContext); + osgiBoot.bootstrap(); + } + + public void stop(BundleContext context) throws Exception { + } +} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/Launcher.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/Launcher.java new file mode 100644 index 000000000..98d7503e3 --- /dev/null +++ b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/Launcher.java @@ -0,0 +1,147 @@ +/* + * Copyright (C) 2010 Mathieu Baudier + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.argeo.osgi.boot; + +import java.io.FileInputStream; +import java.io.IOException; +import java.lang.reflect.Method; +import java.util.List; +import java.util.Vector; + +import org.eclipse.core.runtime.adaptor.EclipseStarter; +import org.osgi.framework.BundleContext; + +public class Launcher { + + public static void main(String[] args) { + // Try to load system properties + String systemPropertiesFilePath = OsgiBootUtils.getPropertyCompat( + OsgiBoot.PROP_ARGEO_OSGI_BOOT_SYSTEM_PROPERTIES_FILE, + OsgiBoot.PROP_SLC_OSGIBOOT_SYSTEM_PROPERTIES_FILE); + if (systemPropertiesFilePath != null) { + FileInputStream in; + try { + in = new FileInputStream(systemPropertiesFilePath); + System.getProperties().load(in); + } catch (IOException e1) { + throw new RuntimeException( + "Cannot load system properties from " + + systemPropertiesFilePath, e1); + } + if (in != null) { + try { + in.close(); + } catch (Exception e) { + // silent + } + } + } + + // Start main class + startMainClass(); + + // Start Equinox + BundleContext bundleContext = null; + try { + bundleContext = EclipseStarter.startup(args, null); + } catch (Exception e) { + throw new RuntimeException("Cannot start Equinox.", e); + } + + // OSGi bootstrap + OsgiBoot osgiBoot = new OsgiBoot(bundleContext); + osgiBoot.bootstrap(); + } + + protected static void startMainClass() { + // Properties config = System.getProperties(); + // String className = config.getProperty("slc.osgiboot.appclass"); + String className = OsgiBootUtils.getPropertyCompat( + OsgiBoot.PROP_ARGEO_OSGI_BOOT_APPCLASS, + OsgiBoot.PROP_SLC_OSGIBOOT_APPCLASS); + if (className == null) + return; + + // should use OsgiBootUtils.getPropertyCompat(), but it does not + // work for "" as default value + // so no warning displayed if PROP_SLC_OSGIBOOT_APPARGS is used + // FIXME: change OsgiBootUtils.getPropertyCompat() + String line = System.getProperty(OsgiBoot.PROP_ARGEO_OSGI_BOOT_APPARGS, + System.getProperty(OsgiBoot.PROP_SLC_OSGIBOOT_APPARGS, "")); + + String[] uiArgs = readArgumentsFromLine(line); + + try { + // Launch main method using reflection + Class clss = Class.forName(className); + Class[] mainArgsClasses = new Class[] { uiArgs.getClass() }; + Object[] mainArgs = { uiArgs }; + Method mainMethod = clss.getMethod("main", mainArgsClasses); + mainMethod.invoke(null, mainArgs); + } catch (Exception e) { + throw new RuntimeException("Cannot start main class.", e); + } + + } + + /** + * Transform a line into an array of arguments, taking "" as single + * arguments. (nested \" are not supported) + */ + private static String[] readArgumentsFromLine(String lineOrig) { + + String line = lineOrig.trim();// remove trailing spaces + // System.out.println("line=" + line); + List args = new Vector(); + StringBuffer curr = new StringBuffer(""); + boolean inQuote = false; + char[] arr = line.toCharArray(); + for (int i = 0; i < arr.length; i++) { + char c = arr[i]; + switch (c) { + case '\"': + inQuote = !inQuote; + break; + case ' ': + if (!inQuote) {// otherwise, no break: goes to default + if (curr.length() > 0) { + args.add(curr.toString()); + curr = new StringBuffer(""); + } + break; + } + default: + curr.append(c); + break; + } + } + + // Add last arg + if (curr.length() > 0) { + args.add(curr.toString()); + curr = null; + } + + String[] res = new String[args.size()]; + for (int i = 0; i < args.size(); i++) { + res[i] = args.get(i).toString(); + // System.out.println("res[i]=" + res[i]); + } + return res; + } + +} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBoot.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBoot.java new file mode 100644 index 000000000..af28c8aba --- /dev/null +++ b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBoot.java @@ -0,0 +1,763 @@ +/* + * Copyright (C) 2010 Mathieu Baudier + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.argeo.osgi.boot; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; + +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.PackageAdmin; + +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_ARGEO_OSGI_DATA_DIR = "argeo.osgi.data.dir"; + + public final static String PROP_ARGEO_OSGI_START = "argeo.osgi.start"; + 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"; + public final static String PROP_ARGEO_OSGI_MODULES_URL = "argeo.osgi.modulesUrl"; + + public final static String PROP_ARGEO_OSGI_BOOT_DEBUG = "argeo.osgi.boot.debug"; + 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"; + + /** @deprecated */ + public final static String PROP_SLC_OSGI_START = "slc.osgi.start"; + /** @deprecated */ + public final static String PROP_SLC_OSGI_BUNDLES = "slc.osgi.bundles"; + /** @deprecated */ + public final static String PROP_SLC_OSGI_LOCATIONS = "slc.osgi.locations"; + /** @deprecated */ + public final static String PROP_SLC_OSGI_BASE_URL = "slc.osgi.baseUrl"; + /** @deprecated */ + public final static String PROP_SLC_OSGI_MODULES_URL = "slc.osgi.modulesUrl"; + + /** @deprecated */ + public final static String PROP_SLC_OSGIBOOT_DEBUG = "slc.osgiboot.debug"; + /** @deprecated */ + public final static String PROP_SLC_OSGIBOOT_DEFAULT_TIMEOUT = "slc.osgiboot.defaultTimeout"; + /** @deprecated */ + public final static String PROP_SLC_OSGIBOOT_MODULES_URL_SEPARATOR = "slc.osgiboot.modulesUrlSeparator"; + /** @deprecated */ + public final static String PROP_SLC_OSGIBOOT_SYSTEM_PROPERTIES_FILE = "slc.osgiboot.systemPropertiesFile"; + /** @deprecated */ + public final static String PROP_SLC_OSGIBOOT_APPCLASS = "slc.osgiboot.appclass"; + /** @deprecated */ + public final static String PROP_SLC_OSGIBOOT_APPARGS = "slc.osgiboot.appargs"; + + + + public final static String DEFAULT_BASE_URL = "reference:file:"; + public final static String EXCLUDES_SVN_PATTERN = "**/.svn/**"; + + private boolean debug = Boolean.valueOf( + System.getProperty(PROP_ARGEO_OSGI_BOOT_DEBUG, System.getProperty( + PROP_SLC_OSGIBOOT_DEBUG, "false"))).booleanValue(); + /** Default is 10s (set in constructor) */ + private long defaultTimeout; + + private boolean excludeSvn = true; + /** Default is ',' (set in constructor) */ + private String modulesUrlSeparator = ","; + + private final BundleContext bundleContext; + + public OsgiBoot(BundleContext bundleContext) { + this.bundleContext = bundleContext; + defaultTimeout = Long.parseLong(OsgiBootUtils.getPropertyCompat( + PROP_ARGEO_OSGI_BOOT_DEFAULT_TIMEOUT, + PROP_SLC_OSGIBOOT_DEFAULT_TIMEOUT, "10000")); + modulesUrlSeparator = OsgiBootUtils.getPropertyCompat( + PROP_ARGEO_OSGI_BOOT_MODULES_URL_SEPARATOR, + PROP_SLC_OSGIBOOT_MODULES_URL_SEPARATOR, ","); + initSystemProperties(); + } + + protected void initSystemProperties() { + String osgiInstanceArea = System.getProperty("osgi.instance.area"); + String osgiInstanceAreaDefault = System + .getProperty("osgi.instance.area.default"); + 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()); + + // TODO: Load additional system properties from file + // Properties additionalSystemProperties = new Properties(); + + } + + public static 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; + } + + 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()); + 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"); + System.out.println(); + } + + public void installUrls(List urls) { + Map installedBundles = getInstalledBundles(); + for (int i = 0; i < urls.size(); i++) { + String url = (String) urls.get(i); + try { + if (installedBundles.containsKey(url)) { + Bundle bundle = (Bundle) installedBundles.get(url); + // bundle.update(); + if (debug) + debug("Bundle " + bundle.getSymbolicName() + + " already installed from " + url); + } else { + Bundle bundle = bundleContext.installBundle(url); + if (debug) + debug("Installed bundle " + bundle.getSymbolicName() + + " from " + url); + } + } catch (BundleException e) { + String message = e.getMessage(); + if ((message.contains("Bundle \"" + SYMBOLIC_NAME_OSGI_BOOT + + "\"") || message.contains("Bundle \"" + + SYMBOLIC_NAME_EQUINOX + "\"")) + && message.contains("has already been 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 (debug) + e.printStackTrace(); + } + } + + } + + 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()); + } + } + } + + } + + public void startBundles() { + String bundlesToStart = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_START, + PROP_SLC_OSGI_START); + startBundles(bundlesToStart); + } + + 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); + } + + public void startBundles(List bundlesToStart) { + if (bundlesToStart.size() == 0) + return; + + // used to log the bundles not found + List notFoundBundles = new ArrayList(bundlesToStart); + + Bundle[] bundles = bundleContext.getBundles(); + long startBegin = System.currentTimeMillis(); + for (int i = 0; i < bundles.length; i++) { + Bundle bundle = bundles[i]; + String symbolicName = bundle.getSymbolicName(); + if (bundlesToStart.contains(symbolicName)) + try { + try { + bundle.start(); + } catch (Exception e) { + 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(); + } + notFoundBundles.remove(symbolicName); + } catch (Exception e) { + OsgiBootUtils.warn("Bundle " + symbolicName + " cannot be started: " + + e.getMessage()); + if (debug) + e.printStackTrace(); + // was found even if start failed + notFoundBundles.remove(symbolicName); + } + } + + for (int i = 0; i < notFoundBundles.size(); i++) + OsgiBootUtils.warn("Bundle " + notFoundBundles.get(i) + + " not started because it was not found."); + } + + 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); + } + } + + protected void waitForBundleResolvedOrActive(long startBegin, Bundle bundle) + throws Exception { + int originalState = bundle.getState(); + if ((originalState == Bundle.RESOLVED) + || (originalState == Bundle.ACTIVE)) + return; + + String originalStateStr = stateAsString(originalState); + + int currentState = bundle.getState(); + while (!(currentState == Bundle.RESOLVED || currentState == Bundle.ACTIVE)) { + long now = System.currentTimeMillis(); + if ((now - startBegin) > defaultTimeout) + throw new Exception("Bundle " + bundle.getSymbolicName() + + " was not RESOLVED or ACTIVE after " + + (now - startBegin) + "ms (originalState=" + + originalStateStr + ", currentState=" + + stateAsString(currentState) + ")"); + + try { + Thread.sleep(100l); + } catch (InterruptedException e) { + // silent + } + currentState = bundle.getState(); + } + } + + public static String stateAsString(int state) { + switch (state) { + case Bundle.UNINSTALLED: + return "UNINSTALLED"; + case Bundle.INSTALLED: + return "INSTALLED"; + case Bundle.RESOLVED: + return "RESOLVED"; + case Bundle.STARTING: + return "STARTING"; + case Bundle.ACTIVE: + return "ACTIVE"; + case Bundle.STOPPING: + return "STOPPING"; + default: + return Integer.toString(state); + } + } + + /** Key is location */ + public Map getInstalledBundles() { + Map installedBundles = new HashMap(); + + Bundle[] bundles = bundleContext.getBundles(); + for (int i = 0; i < bundles.length; i++) { + installedBundles.put(bundles[i].getLocation(), bundles[i]); + } + return installedBundles; + } + + /** Key is symbolic name */ + public Map getBundles() { + Map namedBundles = new HashMap(); + Bundle[] bundles = bundleContext.getBundles(); + for (int i = 0; i < bundles.length; i++) { + namedBundles.put(bundles[i].getSymbolicName(), bundles[i]); + } + return namedBundles; + } + + public List getLocationsUrls() { + String baseUrl = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_BASE_URL, + PROP_SLC_OSGI_BASE_URL, DEFAULT_BASE_URL); + String bundleLocations = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_LOCATIONS, + PROP_SLC_OSGI_LOCATIONS); + return getLocationsUrls(baseUrl, bundleLocations); + } + + public List getModulesUrls() { + List urls = new ArrayList(); + String modulesUrlStr = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_MODULES_URL, + PROP_SLC_OSGI_MODULES_URL); + if (modulesUrlStr == null) + return urls; + + String baseUrl = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_BASE_URL, + PROP_SLC_OSGI_BASE_URL); + + Map installedBundles = getBundles(); + + 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 = 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); + } + } + } catch (Exception e1) { + throw new RuntimeException("Cannot read url " + modulesUrlStr, e1); + } finally { + if (reader != null) + try { + reader.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + return urls; + } + + /** + * @return ==0: versions are identical, <0: tested version is newer, >0: + * currentVersion is newer. + */ + protected int compareVersions(String currentVersion, String testedVersion) { + List cToks = new ArrayList(); + StringTokenizer cSt = new StringTokenizer(currentVersion, "."); + while (cSt.hasMoreTokens()) + cToks.add(cSt.nextToken()); + List tToks = new ArrayList(); + StringTokenizer tSt = new StringTokenizer(currentVersion, "."); + while (tSt.hasMoreTokens()) + tToks.add(tSt.nextToken()); + + int comp = 0; + comp: for (int i = 0; i < cToks.size(); i++) { + if (tToks.size() <= i) { + // equals until then, tested shorter + comp = 1; + break comp; + } + + String c = (String) cToks.get(i); + String t = (String) tToks.get(i); + + try { + int cInt = Integer.parseInt(c); + int tInt = Integer.parseInt(t); + if (cInt == tInt) + continue comp; + else { + comp = (cInt - tInt); + break comp; + } + } catch (NumberFormatException e) { + if (c.equals(t)) + continue comp; + else { + comp = c.compareTo(t); + break comp; + } + } + } + + if (comp == 0 && tToks.size() > cToks.size()) { + // equals until then, current shorter + comp = -1; + } + + return comp; + } + + 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; + } + + public List getBundlesUrls() { + String baseUrl = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_BASE_URL, + PROP_SLC_OSGI_BASE_URL, DEFAULT_BASE_URL); + String bundlePatterns = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_BUNDLES, + PROP_SLC_OSGI_BUNDLES); + return getBundlesUrls(baseUrl, bundlePatterns); + } + + public List getBundlesUrls(String baseUrl, String bundlePatterns) { + List urls = new ArrayList(); + + List bundlesSets = new ArrayList(); + if (bundlePatterns == null) + return urls; + bundlePatterns = SystemPropertyUtils + .resolvePlaceholders(bundlePatterns); + if (debug) + debug(PROP_ARGEO_OSGI_BUNDLES + "=" + bundlePatterns + + " (excludeSvn=" + excludeSvn + ")"); + + StringTokenizer st = new StringTokenizer(bundlePatterns, ","); + while (st.hasMoreTokens()) { + bundlesSets.add(new BundlesSet(st.nextToken())); + } + + List included = new ArrayList(); + PathMatcher matcher = new AntPathMatcher(); + for (int i = 0; i < bundlesSets.size(); i++) { + BundlesSet bundlesSet = (BundlesSet) bundlesSets.get(i); + for (int j = 0; j < bundlesSet.getIncludes().size(); j++) { + String pattern = (String) bundlesSet.getIncludes().get(j); + match(matcher, included, bundlesSet.getDir(), null, pattern); + } + } + + 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++) { + String pattern = (String) bundlesSet.getExcludes().get(j); + match(matcher, excluded, bundlesSet.getDir(), null, pattern); + } + } + + for (int i = 0; i < included.size(); i++) { + String fullPath = (String) included.get(i); + if (!excluded.contains(fullPath)) + urls.add(locationToUrl(baseUrl, fullPath)); + } + + return urls; + } + + 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) { + OsgiBootUtils.warn("Base dir " + baseDir + " has no children, exists=" + + baseDir.exists() + ", isDirectory=" + + baseDir.isDirectory()); + return; + } + + for (int i = 0; i < files.length; i++) + match(matcher, matched, base, files[i].getName(), pattern); + } else { + String fullPath = base + '/' + currentPath; + if (matched.contains(fullPath)) + return;// don't try deeper if already matched + + boolean ok = matcher.match(pattern, currentPath); + if (debug) + debug(currentPath + " " + (ok ? "" : " not ") + + " matched with " + pattern); + if (ok) { + matched.add(fullPath); + return; + } else { + String newFullPath = relativeToFullPath(base, currentPath); + File newFile = new File(newFullPath); + File[] files = newFile.listFiles(); + if (files != null) { + for (int i = 0; i < files.length; i++) { + 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); + } else { + if (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); + if (nonDirectoryOk) + matched.add(relativeToFullPath(base, + newCurrentPath)); + } + } + } + } + } + } + + 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; + } + + /** Transforms a relative path in a full system path. */ + protected String relativeToFullPath(String basePath, String relativePath) { + return (basePath + '/' + relativePath).replace('/', File.separatorChar); + } + + protected void debug(Object obj) { + if (debug) + OsgiBootUtils.debug(obj); + } + + public boolean getDebug() { + return debug; + } + + public void setDebug(boolean debug) { + this.debug = debug; + } + + public BundleContext getBundleContext() { + return bundleContext; + } + + /** Whether to exclude Subversion directories (true by default) */ + public boolean isExcludeSvn() { + return excludeSvn; + } + + public void setExcludeSvn(boolean excludeSvn) { + this.excludeSvn = excludeSvn; + } + + 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; + } + + } + + public void setDefaultTimeout(long defaultTimeout) { + this.defaultTimeout = defaultTimeout; + } + + public void setModulesUrlSeparator(String modulesUrlSeparator) { + this.modulesUrlSeparator = modulesUrlSeparator; + } + +} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBootUtils.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBootUtils.java new file mode 100644 index 000000000..a9067a213 --- /dev/null +++ b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/OsgiBootUtils.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2010 Mathieu Baudier + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.argeo.osgi.boot; + +public class OsgiBootUtils { + + public static void info(Object obj) { + System.out.println("# OSGiBOOT # " + obj); + } + + public static void debug(Object obj) { + System.out.println("# OSGiBOOT DBG # " + obj); + } + + public static void warn(Object obj) { + System.out.println("# OSGiBOOT WARN # " + obj); + // Because of a weird bug under Windows when starting it in a forked VM + // if (System.getProperty("os.name").contains("Windows")) + // System.out.println("# WARN " + obj); + // else + // System.err.println("# WARN " + obj); + } + + //FIXE: returns null when defaultValue is "" + public static String getProperty(String name, String defaultValue) { + final String value; + if (defaultValue != null) + value = System.getProperty(name, defaultValue); + else + value = System.getProperty(name); + + if (value == null || value.equals("")) + return null; + else + return value; + } + + public static String getProperty(String name) { + return getProperty(name, null); + } + + public static String getPropertyCompat(String name, String oldName) { + return getPropertyCompat(name, oldName, null); + } + + public static String getPropertyCompat(String name, String oldName, + String defaultValue) { + String res = null; + + if (defaultValue != null) { + res = getProperty(name, defaultValue); + if (res.equals(defaultValue)) { + res = getProperty(oldName, defaultValue); + if (!res.equals(defaultValue)) + warnDeprecated(name, oldName); + } + } else { + res = getProperty(name, null); + if (res == null) { + res = getProperty(oldName, null); + if (res != null) + warnDeprecated(name, oldName); + } + } + return res; + } + + public static void warnDeprecated(String name, String oldName) { + warn("Property '" + oldName + + "' is deprecated and will be removed soon, use '" + name + + "' instead."); + } + +} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/AntPathMatcher.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/AntPathMatcher.java new file mode 100644 index 000000000..0b9ad1a23 --- /dev/null +++ b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/AntPathMatcher.java @@ -0,0 +1,411 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.argeo.osgi.boot.internal.springutil; + +/** + * PathMatcher implementation for Ant-style path patterns. + * Examples are provided below. + * + *

Part of this mapping code has been kindly borrowed from + * Apache Ant. + * + *

The mapping matches URLs using the following rules:
+ *

    + *
  • ? matches one character
  • + *
  • * matches zero or more characters
  • + *
  • ** matches zero or more 'directories' in a path
  • + *
+ * + *

Some examples:
+ *

    + *
  • com/t?st.jsp - matches com/test.jsp but also + * com/tast.jsp or com/txst.jsp
  • + *
  • com/*.jsp - matches all .jsp files in the + * com directory
  • + *
  • com/**/test.jsp - matches all test.jsp + * files underneath the com path
  • + *
  • org/springframework/**/*.jsp - matches all .jsp + * files underneath the org/springframework path
  • + *
  • org/**/servlet/bla.jsp - matches + * org/springframework/servlet/bla.jsp but also + * org/springframework/testing/servlet/bla.jsp and + * org/servlet/bla.jsp
  • + *
+ * + * @author Alef Arendsen + * @author Juergen Hoeller + * @author Rob Harrop + * @since 16.07.2003 + */ +public class AntPathMatcher implements PathMatcher { + + /** Default path separator: "/" */ + public static final String DEFAULT_PATH_SEPARATOR = "/"; + + private String pathSeparator = DEFAULT_PATH_SEPARATOR; + + + /** + * Set the path separator to use for pattern parsing. + * Default is "/", as in Ant. + */ + public void setPathSeparator(String pathSeparator) { + this.pathSeparator = (pathSeparator != null ? pathSeparator : DEFAULT_PATH_SEPARATOR); + } + + + public boolean isPattern(String path) { + return (path.indexOf('*') != -1 || path.indexOf('?') != -1); + } + + public boolean match(String pattern, String path) { + return doMatch(pattern, path, true); + } + + public boolean matchStart(String pattern, String path) { + return doMatch(pattern, path, false); + } + + + /** + * Actually match the given path against the given pattern. + * @param pattern the pattern to match against + * @param path the path String to test + * @param fullMatch whether a full pattern match is required + * (else a pattern match as far as the given base path goes is sufficient) + * @return true if the supplied path matched, + * false if it didn't + */ + protected boolean doMatch(String pattern, String path, boolean fullMatch) { + if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) { + return false; + } + + String[] pattDirs = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator); + String[] pathDirs = StringUtils.tokenizeToStringArray(path, this.pathSeparator); + + int pattIdxStart = 0; + int pattIdxEnd = pattDirs.length - 1; + int pathIdxStart = 0; + int pathIdxEnd = pathDirs.length - 1; + + // Match all elements up to the first ** + while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) { + String patDir = pattDirs[pattIdxStart]; + if ("**".equals(patDir)) { + break; + } + if (!matchStrings(patDir, pathDirs[pathIdxStart])) { + return false; + } + pattIdxStart++; + pathIdxStart++; + } + + if (pathIdxStart > pathIdxEnd) { + // Path is exhausted, only match if rest of pattern is * or **'s + if (pattIdxStart > pattIdxEnd) { + return (pattern.endsWith(this.pathSeparator) ? + path.endsWith(this.pathSeparator) : !path.endsWith(this.pathSeparator)); + } + if (!fullMatch) { + return true; + } + if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*") && + path.endsWith(this.pathSeparator)) { + return true; + } + for (int i = pattIdxStart; i <= pattIdxEnd; i++) { + if (!pattDirs[i].equals("**")) { + return false; + } + } + return true; + } + else if (pattIdxStart > pattIdxEnd) { + // String not exhausted, but pattern is. Failure. + return false; + } + else if (!fullMatch && "**".equals(pattDirs[pattIdxStart])) { + // Path start definitely matches due to "**" part in pattern. + return true; + } + + // up to last '**' + while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) { + String patDir = pattDirs[pattIdxEnd]; + if (patDir.equals("**")) { + break; + } + if (!matchStrings(patDir, pathDirs[pathIdxEnd])) { + return false; + } + pattIdxEnd--; + pathIdxEnd--; + } + if (pathIdxStart > pathIdxEnd) { + // String is exhausted + for (int i = pattIdxStart; i <= pattIdxEnd; i++) { + if (!pattDirs[i].equals("**")) { + return false; + } + } + return true; + } + + while (pattIdxStart != pattIdxEnd && pathIdxStart <= pathIdxEnd) { + int patIdxTmp = -1; + for (int i = pattIdxStart + 1; i <= pattIdxEnd; i++) { + if (pattDirs[i].equals("**")) { + patIdxTmp = i; + break; + } + } + if (patIdxTmp == pattIdxStart + 1) { + // '**/**' situation, so skip one + pattIdxStart++; + continue; + } + // Find the pattern between padIdxStart & padIdxTmp in str between + // strIdxStart & strIdxEnd + int patLength = (patIdxTmp - pattIdxStart - 1); + int strLength = (pathIdxEnd - pathIdxStart + 1); + int foundIdx = -1; + + strLoop: + for (int i = 0; i <= strLength - patLength; i++) { + for (int j = 0; j < patLength; j++) { + String subPat = (String) pattDirs[pattIdxStart + j + 1]; + String subStr = (String) pathDirs[pathIdxStart + i + j]; + if (!matchStrings(subPat, subStr)) { + continue strLoop; + } + } + foundIdx = pathIdxStart + i; + break; + } + + if (foundIdx == -1) { + return false; + } + + pattIdxStart = patIdxTmp; + pathIdxStart = foundIdx + patLength; + } + + for (int i = pattIdxStart; i <= pattIdxEnd; i++) { + if (!pattDirs[i].equals("**")) { + return false; + } + } + + return true; + } + + /** + * Tests whether or not a string matches against a pattern. + * The pattern may contain two special characters:
+ * '*' means zero or more characters
+ * '?' means one and only one character + * @param pattern pattern to match against. + * Must not be null. + * @param str string which must be matched against the pattern. + * Must not be null. + * @return true if the string matches against the + * pattern, or false otherwise. + */ + private boolean matchStrings(String pattern, String str) { + char[] patArr = pattern.toCharArray(); + char[] strArr = str.toCharArray(); + int patIdxStart = 0; + int patIdxEnd = patArr.length - 1; + int strIdxStart = 0; + int strIdxEnd = strArr.length - 1; + char ch; + + boolean containsStar = false; + for (int i = 0; i < patArr.length; i++) { + if (patArr[i] == '*') { + containsStar = true; + break; + } + } + + if (!containsStar) { + // No '*'s, so we make a shortcut + if (patIdxEnd != strIdxEnd) { + return false; // Pattern and string do not have the same size + } + for (int i = 0; i <= patIdxEnd; i++) { + ch = patArr[i]; + if (ch != '?') { + if (ch != strArr[i]) { + return false;// Character mismatch + } + } + } + return true; // String matches against pattern + } + + + if (patIdxEnd == 0) { + return true; // Pattern contains only '*', which matches anything + } + + // Process characters before first star + while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) { + if (ch != '?') { + if (ch != strArr[strIdxStart]) { + return false;// Character mismatch + } + } + patIdxStart++; + strIdxStart++; + } + if (strIdxStart > strIdxEnd) { + // All characters in the string are used. Check if only '*'s are + // left in the pattern. If so, we succeeded. Otherwise failure. + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (patArr[i] != '*') { + return false; + } + } + return true; + } + + // Process characters after last star + while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) { + if (ch != '?') { + if (ch != strArr[strIdxEnd]) { + return false;// Character mismatch + } + } + patIdxEnd--; + strIdxEnd--; + } + if (strIdxStart > strIdxEnd) { + // All characters in the string are used. Check if only '*'s are + // left in the pattern. If so, we succeeded. Otherwise failure. + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (patArr[i] != '*') { + return false; + } + } + return true; + } + + // process pattern between stars. padIdxStart and patIdxEnd point + // always to a '*'. + while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { + int patIdxTmp = -1; + for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { + if (patArr[i] == '*') { + patIdxTmp = i; + break; + } + } + if (patIdxTmp == patIdxStart + 1) { + // Two stars next to each other, skip the first one. + patIdxStart++; + continue; + } + // Find the pattern between padIdxStart & padIdxTmp in str between + // strIdxStart & strIdxEnd + int patLength = (patIdxTmp - patIdxStart - 1); + int strLength = (strIdxEnd - strIdxStart + 1); + int foundIdx = -1; + strLoop: + for (int i = 0; i <= strLength - patLength; i++) { + for (int j = 0; j < patLength; j++) { + ch = patArr[patIdxStart + j + 1]; + if (ch != '?') { + if (ch != strArr[strIdxStart + i + j]) { + continue strLoop; + } + } + } + + foundIdx = strIdxStart + i; + break; + } + + if (foundIdx == -1) { + return false; + } + + patIdxStart = patIdxTmp; + strIdxStart = foundIdx + patLength; + } + + // All characters in the string are used. Check if only '*'s are left + // in the pattern. If so, we succeeded. Otherwise failure. + for (int i = patIdxStart; i <= patIdxEnd; i++) { + if (patArr[i] != '*') { + return false; + } + } + + return true; + } + + /** + * Given a pattern and a full path, determine the pattern-mapped part. + *

For example: + *

    + *
  • '/docs/cvs/commit.html' and '/docs/cvs/commit.html -> ''
  • + *
  • '/docs/*' and '/docs/cvs/commit -> 'cvs/commit'
  • + *
  • '/docs/cvs/*.html' and '/docs/cvs/commit.html -> 'commit.html'
  • + *
  • '/docs/**' and '/docs/cvs/commit -> 'cvs/commit'
  • + *
  • '/docs/**\/*.html' and '/docs/cvs/commit.html -> 'cvs/commit.html'
  • + *
  • '/*.html' and '/docs/cvs/commit.html -> 'docs/cvs/commit.html'
  • + *
  • '*.html' and '/docs/cvs/commit.html -> '/docs/cvs/commit.html'
  • + *
  • '*' and '/docs/cvs/commit.html -> '/docs/cvs/commit.html'
  • + *
+ *

Assumes that {@link #match} returns true for 'pattern' + * and 'path', but does not enforce this. + */ + public String extractPathWithinPattern(String pattern, String path) { + String[] patternParts = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator); + String[] pathParts = StringUtils.tokenizeToStringArray(path, this.pathSeparator); + + StringBuffer buffer = new StringBuffer(); + + // Add any path parts that have a wildcarded pattern part. + int puts = 0; + for (int i = 0; i < patternParts.length; i++) { + String patternPart = patternParts[i]; + if ((patternPart.indexOf('*') > -1 || patternPart.indexOf('?') > -1) && pathParts.length >= i + 1) { + if (puts > 0 || (i == 0 && !pattern.startsWith(this.pathSeparator))) { + buffer.append(this.pathSeparator); + } + buffer.append(pathParts[i]); + puts++; + } + } + + // Append any trailing path parts. + for (int i = patternParts.length; i < pathParts.length; i++) { + if (puts > 0 || i > 0) { + buffer.append(this.pathSeparator); + } + buffer.append(pathParts[i]); + } + + return buffer.toString(); + } + +} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/CollectionUtils.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/CollectionUtils.java new file mode 100644 index 000000000..ad0154293 --- /dev/null +++ b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/CollectionUtils.java @@ -0,0 +1,275 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.argeo.osgi.boot.internal.springutil; + +import java.util.Arrays; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +/** + * Miscellaneous collection utility methods. + * Mainly for internal use within the framework. + * + * @author Juergen Hoeller + * @author Rob Harrop + * @since 1.1.3 + */ +public abstract class CollectionUtils { + + /** + * Return true if the supplied Collection is null + * or empty. Otherwise, return false. + * @param collection the Collection to check + * @return whether the given Collection is empty + */ + public static boolean isEmpty(Collection collection) { + return (collection == null || collection.isEmpty()); + } + + /** + * Return true if the supplied Map is null + * or empty. Otherwise, return false. + * @param map the Map to check + * @return whether the given Map is empty + */ + public static boolean isEmpty(Map map) { + return (map == null || map.isEmpty()); + } + + /** + * Convert the supplied array into a List. A primitive array gets + * converted into a List of the appropriate wrapper type. + *

A null source value will be converted to an + * empty List. + * @param source the (potentially primitive) array + * @return the converted List result + * @see ObjectUtils#toObjectArray(Object) + */ + public static List arrayToList(Object source) { + return Arrays.asList(ObjectUtils.toObjectArray(source)); + } + + /** + * Merge the given array into the given Collection. + * @param array the array to merge (may be null) + * @param collection the target Collection to merge the array into + */ + public static void mergeArrayIntoCollection(Object array, Collection collection) { + if (collection == null) { + throw new IllegalArgumentException("Collection must not be null"); + } + Object[] arr = ObjectUtils.toObjectArray(array); + for (int i = 0; i < arr.length; i++) { + collection.add(arr[i]); + } + } + + /** + * Merge the given Properties instance into the given Map, + * copying all properties (key-value pairs) over. + *

Uses Properties.propertyNames() to even catch + * default properties linked into the original Properties instance. + * @param props the Properties instance to merge (may be null) + * @param map the target Map to merge the properties into + */ + public static void mergePropertiesIntoMap(Properties props, Map map) { + if (map == null) { + throw new IllegalArgumentException("Map must not be null"); + } + if (props != null) { + for (Enumeration en = props.propertyNames(); en.hasMoreElements();) { + String key = (String) en.nextElement(); + map.put(key, props.getProperty(key)); + } + } + } + + + /** + * Check whether the given Iterator contains the given element. + * @param iterator the Iterator to check + * @param element the element to look for + * @return true if found, false else + */ + public static boolean contains(Iterator iterator, Object element) { + if (iterator != null) { + while (iterator.hasNext()) { + Object candidate = iterator.next(); + if (ObjectUtils.nullSafeEquals(candidate, element)) { + return true; + } + } + } + return false; + } + + /** + * Check whether the given Enumeration contains the given element. + * @param enumeration the Enumeration to check + * @param element the element to look for + * @return true if found, false else + */ + public static boolean contains(Enumeration enumeration, Object element) { + if (enumeration != null) { + while (enumeration.hasMoreElements()) { + Object candidate = enumeration.nextElement(); + if (ObjectUtils.nullSafeEquals(candidate, element)) { + return true; + } + } + } + return false; + } + + /** + * Check whether the given Collection contains the given element instance. + *

Enforces the given instance to be present, rather than returning + * true for an equal element as well. + * @param collection the Collection to check + * @param element the element to look for + * @return true if found, false else + */ + public static boolean containsInstance(Collection collection, Object element) { + if (collection != null) { + for (Iterator it = collection.iterator(); it.hasNext();) { + Object candidate = it.next(); + if (candidate == element) { + return true; + } + } + } + return false; + } + + /** + * Return true if any element in 'candidates' is + * contained in 'source'; otherwise returns false. + * @param source the source Collection + * @param candidates the candidates to search for + * @return whether any of the candidates has been found + */ + public static boolean containsAny(Collection source, Collection candidates) { + if (isEmpty(source) || isEmpty(candidates)) { + return false; + } + for (Iterator it = candidates.iterator(); it.hasNext();) { + if (source.contains(it.next())) { + return true; + } + } + return false; + } + + /** + * Return the first element in 'candidates' that is contained in + * 'source'. If no element in 'candidates' is present in + * 'source' returns null. Iteration order is + * {@link Collection} implementation specific. + * @param source the source Collection + * @param candidates the candidates to search for + * @return the first present object, or null if not found + */ + public static Object findFirstMatch(Collection source, Collection candidates) { + if (isEmpty(source) || isEmpty(candidates)) { + return null; + } + for (Iterator it = candidates.iterator(); it.hasNext();) { + Object candidate = it.next(); + if (source.contains(candidate)) { + return candidate; + } + } + return null; + } + + /** + * Find a single value of the given type in the given Collection. + * @param collection the Collection to search + * @param type the type to look for + * @return a value of the given type found if there is a clear match, + * or null if none or more than one such value found + */ + public static Object findValueOfType(Collection collection, Class type) { + if (isEmpty(collection)) { + return null; + } + Object value = null; + for (Iterator it = collection.iterator(); it.hasNext();) { + Object obj = it.next(); + if (type == null || type.isInstance(obj)) { + if (value != null) { + // More than one value found... no clear single value. + return null; + } + value = obj; + } + } + return value; + } + + /** + * Find a single value of one of the given types in the given Collection: + * searching the Collection for a value of the first type, then + * searching for a value of the second type, etc. + * @param collection the collection to search + * @param types the types to look for, in prioritized order + * @return a value of one of the given types found if there is a clear match, + * or null if none or more than one such value found + */ + public static Object findValueOfType(Collection collection, Class[] types) { + if (isEmpty(collection) || ObjectUtils.isEmpty(types)) { + return null; + } + for (int i = 0; i < types.length; i++) { + Object value = findValueOfType(collection, types[i]); + if (value != null) { + return value; + } + } + return null; + } + + /** + * Determine whether the given Collection only contains a single unique object. + * @param collection the Collection to check + * @return true if the collection contains a single reference or + * multiple references to the same instance, false else + */ + public static boolean hasUniqueObject(Collection collection) { + if (isEmpty(collection)) { + return false; + } + boolean hasCandidate = false; + Object candidate = null; + for (Iterator it = collection.iterator(); it.hasNext();) { + Object elem = it.next(); + if (!hasCandidate) { + hasCandidate = true; + candidate = elem; + } + else if (candidate != elem) { + return false; + } + } + return true; + } + +} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/ObjectUtils.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/ObjectUtils.java new file mode 100644 index 000000000..223b2a1c1 --- /dev/null +++ b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/ObjectUtils.java @@ -0,0 +1,833 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.argeo.osgi.boot.internal.springutil; + +import java.lang.reflect.Array; +import java.util.Arrays; + +/** + * Miscellaneous object utility methods. Mainly for internal use within the + * framework; consider Jakarta's Commons Lang for a more comprehensive suite + * of object utilities. + * + * @author Juergen Hoeller + * @author Keith Donald + * @author Rod Johnson + * @author Rob Harrop + * @author Alex Ruiz + * @since 19.03.2004 + * @see org.apache.commons.lang.ObjectUtils + */ +public abstract class ObjectUtils { + + private static final int INITIAL_HASH = 7; + private static final int MULTIPLIER = 31; + + private static final String EMPTY_STRING = ""; + private static final String NULL_STRING = "null"; + private static final String ARRAY_START = "{"; + private static final String ARRAY_END = "}"; + private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END; + private static final String ARRAY_ELEMENT_SEPARATOR = ", "; + + + /** + * Return whether the given throwable is a checked exception: + * that is, neither a RuntimeException nor an Error. + * @param ex the throwable to check + * @return whether the throwable is a checked exception + * @see java.lang.Exception + * @see java.lang.RuntimeException + * @see java.lang.Error + */ + public static boolean isCheckedException(Throwable ex) { + return !(ex instanceof RuntimeException || ex instanceof Error); + } + + /** + * Check whether the given exception is compatible with the exceptions + * declared in a throws clause. + * @param ex the exception to checked + * @param declaredExceptions the exceptions declared in the throws clause + * @return whether the given exception is compatible + */ + public static boolean isCompatibleWithThrowsClause(Throwable ex, Class[] declaredExceptions) { + if (!isCheckedException(ex)) { + return true; + } + if (declaredExceptions != null) { + for (int i = 0; i < declaredExceptions.length; i++) { + if (declaredExceptions[i].isAssignableFrom(ex.getClass())) { + return true; + } + } + } + return false; + } + + /** + * Return whether the given array is empty: that is, null + * or of zero length. + * @param array the array to check + * @return whether the given array is empty + */ + public static boolean isEmpty(Object[] array) { + return (array == null || array.length == 0); + } + + /** + * Check whether the given array contains the given element. + * @param array the array to check (may be null, + * in which case the return value will always be false) + * @param element the element to check for + * @return whether the element has been found in the given array + */ + public static boolean containsElement(Object[] array, Object element) { + if (array == null) { + return false; + } + for (int i = 0; i < array.length; i++) { + if (nullSafeEquals(array[i], element)) { + return true; + } + } + return false; + } + + /** + * Append the given Object to the given array, returning a new array + * consisting of the input array contents plus the given Object. + * @param array the array to append to (can be null) + * @param obj the Object to append + * @return the new array (of the same component type; never null) + */ + public static Object[] addObjectToArray(Object[] array, Object obj) { + Class compType = Object.class; + if (array != null) { + compType = array.getClass().getComponentType(); + } + else if (obj != null) { + compType = obj.getClass(); + } + int newArrLength = (array != null ? array.length + 1 : 1); + Object[] newArr = (Object[]) Array.newInstance(compType, newArrLength); + if (array != null) { + System.arraycopy(array, 0, newArr, 0, array.length); + } + newArr[newArr.length - 1] = obj; + return newArr; + } + + /** + * Convert the given array (which may be a primitive array) to an + * object array (if necessary of primitive wrapper objects). + *

A null source value will be converted to an + * empty Object array. + * @param source the (potentially primitive) array + * @return the corresponding object array (never null) + * @throws IllegalArgumentException if the parameter is not an array + */ + public static Object[] toObjectArray(Object source) { + if (source instanceof Object[]) { + return (Object[]) source; + } + if (source == null) { + return new Object[0]; + } + if (!source.getClass().isArray()) { + throw new IllegalArgumentException("Source is not an array: " + source); + } + int length = Array.getLength(source); + if (length == 0) { + return new Object[0]; + } + Class wrapperType = Array.get(source, 0).getClass(); + Object[] newArray = (Object[]) Array.newInstance(wrapperType, length); + for (int i = 0; i < length; i++) { + newArray[i] = Array.get(source, i); + } + return newArray; + } + + + //--------------------------------------------------------------------- + // Convenience methods for content-based equality/hash-code handling + //--------------------------------------------------------------------- + + /** + * Determine if the given objects are equal, returning true + * if both are null or false if only one is + * null. + *

Compares arrays with Arrays.equals, performing an equality + * check based on the array elements rather than the array reference. + * @param o1 first Object to compare + * @param o2 second Object to compare + * @return whether the given objects are equal + * @see java.util.Arrays#equals + */ + public static boolean nullSafeEquals(Object o1, Object o2) { + if (o1 == o2) { + return true; + } + if (o1 == null || o2 == null) { + return false; + } + if (o1.equals(o2)) { + return true; + } + if (o1.getClass().isArray() && o2.getClass().isArray()) { + if (o1 instanceof Object[] && o2 instanceof Object[]) { + return Arrays.equals((Object[]) o1, (Object[]) o2); + } + if (o1 instanceof boolean[] && o2 instanceof boolean[]) { + return Arrays.equals((boolean[]) o1, (boolean[]) o2); + } + if (o1 instanceof byte[] && o2 instanceof byte[]) { + return Arrays.equals((byte[]) o1, (byte[]) o2); + } + if (o1 instanceof char[] && o2 instanceof char[]) { + return Arrays.equals((char[]) o1, (char[]) o2); + } + if (o1 instanceof double[] && o2 instanceof double[]) { + return Arrays.equals((double[]) o1, (double[]) o2); + } + if (o1 instanceof float[] && o2 instanceof float[]) { + return Arrays.equals((float[]) o1, (float[]) o2); + } + if (o1 instanceof int[] && o2 instanceof int[]) { + return Arrays.equals((int[]) o1, (int[]) o2); + } + if (o1 instanceof long[] && o2 instanceof long[]) { + return Arrays.equals((long[]) o1, (long[]) o2); + } + if (o1 instanceof short[] && o2 instanceof short[]) { + return Arrays.equals((short[]) o1, (short[]) o2); + } + } + return false; + } + + /** + * Return as hash code for the given object; typically the value of + * {@link Object#hashCode()}. If the object is an array, + * this method will delegate to any of the nullSafeHashCode + * methods for arrays in this class. If the object is null, + * this method returns 0. + * @see #nullSafeHashCode(Object[]) + * @see #nullSafeHashCode(boolean[]) + * @see #nullSafeHashCode(byte[]) + * @see #nullSafeHashCode(char[]) + * @see #nullSafeHashCode(double[]) + * @see #nullSafeHashCode(float[]) + * @see #nullSafeHashCode(int[]) + * @see #nullSafeHashCode(long[]) + * @see #nullSafeHashCode(short[]) + */ + public static int nullSafeHashCode(Object obj) { + if (obj == null) { + return 0; + } + if (obj.getClass().isArray()) { + if (obj instanceof Object[]) { + return nullSafeHashCode((Object[]) obj); + } + if (obj instanceof boolean[]) { + return nullSafeHashCode((boolean[]) obj); + } + if (obj instanceof byte[]) { + return nullSafeHashCode((byte[]) obj); + } + if (obj instanceof char[]) { + return nullSafeHashCode((char[]) obj); + } + if (obj instanceof double[]) { + return nullSafeHashCode((double[]) obj); + } + if (obj instanceof float[]) { + return nullSafeHashCode((float[]) obj); + } + if (obj instanceof int[]) { + return nullSafeHashCode((int[]) obj); + } + if (obj instanceof long[]) { + return nullSafeHashCode((long[]) obj); + } + if (obj instanceof short[]) { + return nullSafeHashCode((short[]) obj); + } + } + return obj.hashCode(); + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(Object[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + nullSafeHashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(boolean[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + hashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(byte[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + array[i]; + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(char[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + array[i]; + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(double[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + hashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(float[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + hashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(int[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + array[i]; + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(long[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + hashCode(array[i]); + } + return hash; + } + + /** + * Return a hash code based on the contents of the specified array. + * If array is null, this method returns 0. + */ + public static int nullSafeHashCode(short[] array) { + if (array == null) { + return 0; + } + int hash = INITIAL_HASH; + int arraySize = array.length; + for (int i = 0; i < arraySize; i++) { + hash = MULTIPLIER * hash + array[i]; + } + return hash; + } + + /** + * Return the same value as {@link Boolean#hashCode()}. + * @see Boolean#hashCode() + */ + public static int hashCode(boolean bool) { + return bool ? 1231 : 1237; + } + + /** + * Return the same value as {@link Double#hashCode()}. + * @see Double#hashCode() + */ + public static int hashCode(double dbl) { + long bits = Double.doubleToLongBits(dbl); + return hashCode(bits); + } + + /** + * Return the same value as {@link Float#hashCode()}. + * @see Float#hashCode() + */ + public static int hashCode(float flt) { + return Float.floatToIntBits(flt); + } + + /** + * Return the same value as {@link Long#hashCode()}. + * @see Long#hashCode() + */ + public static int hashCode(long lng) { + return (int) (lng ^ (lng >>> 32)); + } + + + //--------------------------------------------------------------------- + // Convenience methods for toString output + //--------------------------------------------------------------------- + + /** + * Return a String representation of an object's overall identity. + * @param obj the object (may be null) + * @return the object's identity as String representation, + * or an empty String if the object was null + */ + public static String identityToString(Object obj) { + if (obj == null) { + return EMPTY_STRING; + } + return obj.getClass().getName() + "@" + getIdentityHexString(obj); + } + + /** + * Return a hex String form of an object's identity hash code. + * @param obj the object + * @return the object's identity code in hex notation + */ + public static String getIdentityHexString(Object obj) { + return Integer.toHexString(System.identityHashCode(obj)); + } + + /** + * Return a content-based String representation if obj is + * not null; otherwise returns an empty String. + *

Differs from {@link #nullSafeToString(Object)} in that it returns + * an empty String rather than "null" for a null value. + * @param obj the object to build a display String for + * @return a display String representation of obj + * @see #nullSafeToString(Object) + */ + public static String getDisplayString(Object obj) { + if (obj == null) { + return EMPTY_STRING; + } + return nullSafeToString(obj); + } + + /** + * Determine the class name for the given object. + *

Returns "null" if obj is null. + * @param obj the object to introspect (may be null) + * @return the corresponding class name + */ + public static String nullSafeClassName(Object obj) { + return (obj != null ? obj.getClass().getName() : NULL_STRING); + } + + /** + * Return a String representation of the specified Object. + *

Builds a String representation of the contents in case of an array. + * Returns "null" if obj is null. + * @param obj the object to build a String representation for + * @return a String representation of obj + */ + public static String nullSafeToString(Object obj) { + if (obj == null) { + return NULL_STRING; + } + if (obj instanceof String) { + return (String) obj; + } + if (obj instanceof Object[]) { + return nullSafeToString((Object[]) obj); + } + if (obj instanceof boolean[]) { + return nullSafeToString((boolean[]) obj); + } + if (obj instanceof byte[]) { + return nullSafeToString((byte[]) obj); + } + if (obj instanceof char[]) { + return nullSafeToString((char[]) obj); + } + if (obj instanceof double[]) { + return nullSafeToString((double[]) obj); + } + if (obj instanceof float[]) { + return nullSafeToString((float[]) obj); + } + if (obj instanceof int[]) { + return nullSafeToString((int[]) obj); + } + if (obj instanceof long[]) { + return nullSafeToString((long[]) obj); + } + if (obj instanceof short[]) { + return nullSafeToString((short[]) obj); + } + String str = obj.toString(); + return (str != null ? str : EMPTY_STRING); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(Object[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + buffer.append(String.valueOf(array[i])); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(boolean[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(byte[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(char[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + buffer.append("'").append(array[i]).append("'"); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(double[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(float[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(int[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(long[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + + /** + * Return a String representation of the contents of the specified array. + *

The String representation consists of a list of the array's elements, + * enclosed in curly braces ("{}"). Adjacent elements are separated + * by the characters ", " (a comma followed by a space). Returns + * "null" if array is null. + * @param array the array to build a String representation for + * @return a String representation of array + */ + public static String nullSafeToString(short[] array) { + if (array == null) { + return NULL_STRING; + } + int length = array.length; + if (length == 0) { + return EMPTY_ARRAY; + } + StringBuffer buffer = new StringBuffer(); + for (int i = 0; i < length; i++) { + if (i == 0) { + buffer.append(ARRAY_START); + } + else { + buffer.append(ARRAY_ELEMENT_SEPARATOR); + } + buffer.append(array[i]); + } + buffer.append(ARRAY_END); + return buffer.toString(); + } + +} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/PathMatcher.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/PathMatcher.java new file mode 100644 index 000000000..d7a23221b --- /dev/null +++ b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/PathMatcher.java @@ -0,0 +1,91 @@ +/* + * Copyright 2002-2007 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.argeo.osgi.boot.internal.springutil; + +/** + * Strategy interface for String-based path matching. + * + *

Used by {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}, + * {@link org.springframework.web.servlet.handler.AbstractUrlHandlerMapping}, + * {@link org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver}, + * and {@link org.springframework.web.servlet.mvc.WebContentInterceptor}. + * + *

The default implementation is {@link AntPathMatcher}, supporting the + * Ant-style pattern syntax. + * + * @author Juergen Hoeller + * @since 1.2 + * @see AntPathMatcher + */ +public interface PathMatcher { + + /** + * Does the given path represent a pattern that can be matched + * by an implementation of this interface? + *

If the return value is false, then the {@link #match} + * method does not have to be used because direct equality comparisons + * on the static path Strings will lead to the same result. + * @param path the path String to check + * @return true if the given path represents a pattern + */ + boolean isPattern(String path); + + /** + * Match the given path against the given pattern, + * according to this PathMatcher's matching strategy. + * @param pattern the pattern to match against + * @param path the path String to test + * @return true if the supplied path matched, + * false if it didn't + */ + boolean match(String pattern, String path); + + /** + * Match the given path against the corresponding part of the given + * pattern, according to this PathMatcher's matching strategy. + *

Determines whether the pattern at least matches as far as the given base + * path goes, assuming that a full path may then match as well. + * @param pattern the pattern to match against + * @param path the path String to test + * @return true if the supplied path matched, + * false if it didn't + */ + boolean matchStart(String pattern, String path); + + /** + * Given a pattern and a full path, determine the pattern-mapped part. + *

This method is supposed to find out which part of the path is matched + * dynamically through an actual pattern, that is, it strips off a statically + * defined leading path from the given full path, returning only the actually + * pattern-matched part of the path. + *

For example: For "myroot/*.html" as pattern and "myroot/myfile.html" + * as full path, this method should return "myfile.html". The detailed + * determination rules are specified to this PathMatcher's matching strategy. + *

A simple implementation may return the given full path as-is in case + * of an actual pattern, and the empty String in case of the pattern not + * containing any dynamic parts (i.e. the pattern parameter being + * a static path that wouldn't qualify as an actual {@link #isPattern pattern}). + * A sophisticated implementation will differentiate between the static parts + * and the dynamic parts of the given path pattern. + * @param pattern the path pattern + * @param path the full path to introspect + * @return the pattern-mapped part of the given path + * (never null) + */ + String extractPathWithinPattern(String pattern, String path); + +} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/StringUtils.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/StringUtils.java new file mode 100644 index 000000000..262659044 --- /dev/null +++ b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/StringUtils.java @@ -0,0 +1,1113 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.argeo.osgi.boot.internal.springutil; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Enumeration; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Properties; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeSet; + +/** + * Miscellaneous {@link String} utility methods. + * + *

Mainly for internal use within the framework; consider + * Jakarta's Commons Lang + * for a more comprehensive suite of String utilities. + * + *

This class delivers some simple functionality that should really + * be provided by the core Java String and {@link StringBuffer} + * classes, such as the ability to {@link #replace} all occurrences of a given + * substring in a target string. It also provides easy-to-use methods to convert + * between delimited strings, such as CSV strings, and collections and arrays. + * + * @author Rod Johnson + * @author Juergen Hoeller + * @author Keith Donald + * @author Rob Harrop + * @author Rick Evans + * @since 16 April 2001 + * @see org.apache.commons.lang.StringUtils + */ +public abstract class StringUtils { + + private static final String FOLDER_SEPARATOR = "/"; + + private static final String WINDOWS_FOLDER_SEPARATOR = "\\"; + + private static final String TOP_PATH = ".."; + + private static final String CURRENT_PATH = "."; + + private static final char EXTENSION_SEPARATOR = '.'; + + + //--------------------------------------------------------------------- + // General convenience methods for working with Strings + //--------------------------------------------------------------------- + + /** + * Check that the given CharSequence is neither null nor of length 0. + * Note: Will return true for a CharSequence that purely consists of whitespace. + *

+	 * StringUtils.hasLength(null) = false
+	 * StringUtils.hasLength("") = false
+	 * StringUtils.hasLength(" ") = true
+	 * StringUtils.hasLength("Hello") = true
+	 * 
+ * @param str the CharSequence to check (may be null) + * @return true if the CharSequence is not null and has length + * @see #hasText(String) + */ + public static boolean hasLength(CharSequence str) { + return (str != null && str.length() > 0); + } + + /** + * Check that the given String is neither null nor of length 0. + * Note: Will return true for a String that purely consists of whitespace. + * @param str the String to check (may be null) + * @return true if the String is not null and has length + * @see #hasLength(CharSequence) + */ + public static boolean hasLength(String str) { + return hasLength((CharSequence) str); + } + + /** + * Check whether the given CharSequence has actual text. + * More specifically, returns true if the string not null, + * its length is greater than 0, and it contains at least one non-whitespace character. + *

+	 * StringUtils.hasText(null) = false
+	 * StringUtils.hasText("") = false
+	 * StringUtils.hasText(" ") = false
+	 * StringUtils.hasText("12345") = true
+	 * StringUtils.hasText(" 12345 ") = true
+	 * 
+ * @param str the CharSequence to check (may be null) + * @return true if the CharSequence is not null, + * its length is greater than 0, and it does not contain whitespace only + * @see java.lang.Character#isWhitespace + */ + public static boolean hasText(CharSequence str) { + if (!hasLength(str)) { + return false; + } + int strLen = str.length(); + for (int i = 0; i < strLen; i++) { + if (!Character.isWhitespace(str.charAt(i))) { + return true; + } + } + return false; + } + + /** + * Check whether the given String has actual text. + * More specifically, returns true if the string not null, + * its length is greater than 0, and it contains at least one non-whitespace character. + * @param str the String to check (may be null) + * @return true if the String is not null, its length is + * greater than 0, and it does not contain whitespace only + * @see #hasText(CharSequence) + */ + public static boolean hasText(String str) { + return hasText((CharSequence) str); + } + + /** + * Check whether the given CharSequence contains any whitespace characters. + * @param str the CharSequence to check (may be null) + * @return true if the CharSequence is not empty and + * contains at least 1 whitespace character + * @see java.lang.Character#isWhitespace + */ + public static boolean containsWhitespace(CharSequence str) { + if (!hasLength(str)) { + return false; + } + int strLen = str.length(); + for (int i = 0; i < strLen; i++) { + if (Character.isWhitespace(str.charAt(i))) { + return true; + } + } + return false; + } + + /** + * Check whether the given String contains any whitespace characters. + * @param str the String to check (may be null) + * @return true if the String is not empty and + * contains at least 1 whitespace character + * @see #containsWhitespace(CharSequence) + */ + public static boolean containsWhitespace(String str) { + return containsWhitespace((CharSequence) str); + } + + /** + * Trim leading and trailing whitespace from the given String. + * @param str the String to check + * @return the trimmed String + * @see java.lang.Character#isWhitespace + */ + public static String trimWhitespace(String str) { + if (!hasLength(str)) { + return str; + } + StringBuffer buf = new StringBuffer(str); + while (buf.length() > 0 && Character.isWhitespace(buf.charAt(0))) { + buf.deleteCharAt(0); + } + while (buf.length() > 0 && Character.isWhitespace(buf.charAt(buf.length() - 1))) { + buf.deleteCharAt(buf.length() - 1); + } + return buf.toString(); + } + + /** + * Trim all whitespace from the given String: + * leading, trailing, and inbetween characters. + * @param str the String to check + * @return the trimmed String + * @see java.lang.Character#isWhitespace + */ + public static String trimAllWhitespace(String str) { + if (!hasLength(str)) { + return str; + } + StringBuffer buf = new StringBuffer(str); + int index = 0; + while (buf.length() > index) { + if (Character.isWhitespace(buf.charAt(index))) { + buf.deleteCharAt(index); + } + else { + index++; + } + } + return buf.toString(); + } + + /** + * Trim leading whitespace from the given String. + * @param str the String to check + * @return the trimmed String + * @see java.lang.Character#isWhitespace + */ + public static String trimLeadingWhitespace(String str) { + if (!hasLength(str)) { + return str; + } + StringBuffer buf = new StringBuffer(str); + while (buf.length() > 0 && Character.isWhitespace(buf.charAt(0))) { + buf.deleteCharAt(0); + } + return buf.toString(); + } + + /** + * Trim trailing whitespace from the given String. + * @param str the String to check + * @return the trimmed String + * @see java.lang.Character#isWhitespace + */ + public static String trimTrailingWhitespace(String str) { + if (!hasLength(str)) { + return str; + } + StringBuffer buf = new StringBuffer(str); + while (buf.length() > 0 && Character.isWhitespace(buf.charAt(buf.length() - 1))) { + buf.deleteCharAt(buf.length() - 1); + } + return buf.toString(); + } + + /** + * Trim all occurences of the supplied leading character from the given String. + * @param str the String to check + * @param leadingCharacter the leading character to be trimmed + * @return the trimmed String + */ + public static String trimLeadingCharacter(String str, char leadingCharacter) { + if (!hasLength(str)) { + return str; + } + StringBuffer buf = new StringBuffer(str); + while (buf.length() > 0 && buf.charAt(0) == leadingCharacter) { + buf.deleteCharAt(0); + } + return buf.toString(); + } + + /** + * Trim all occurences of the supplied trailing character from the given String. + * @param str the String to check + * @param trailingCharacter the trailing character to be trimmed + * @return the trimmed String + */ + public static String trimTrailingCharacter(String str, char trailingCharacter) { + if (!hasLength(str)) { + return str; + } + StringBuffer buf = new StringBuffer(str); + while (buf.length() > 0 && buf.charAt(buf.length() - 1) == trailingCharacter) { + buf.deleteCharAt(buf.length() - 1); + } + return buf.toString(); + } + + + /** + * Test if the given String starts with the specified prefix, + * ignoring upper/lower case. + * @param str the String to check + * @param prefix the prefix to look for + * @see java.lang.String#startsWith + */ + public static boolean startsWithIgnoreCase(String str, String prefix) { + if (str == null || prefix == null) { + return false; + } + if (str.startsWith(prefix)) { + return true; + } + if (str.length() < prefix.length()) { + return false; + } + String lcStr = str.substring(0, prefix.length()).toLowerCase(); + String lcPrefix = prefix.toLowerCase(); + return lcStr.equals(lcPrefix); + } + + /** + * Test if the given String ends with the specified suffix, + * ignoring upper/lower case. + * @param str the String to check + * @param suffix the suffix to look for + * @see java.lang.String#endsWith + */ + public static boolean endsWithIgnoreCase(String str, String suffix) { + if (str == null || suffix == null) { + return false; + } + if (str.endsWith(suffix)) { + return true; + } + if (str.length() < suffix.length()) { + return false; + } + + String lcStr = str.substring(str.length() - suffix.length()).toLowerCase(); + String lcSuffix = suffix.toLowerCase(); + return lcStr.equals(lcSuffix); + } + + /** + * Test whether the given string matches the given substring + * at the given index. + * @param str the original string (or StringBuffer) + * @param index the index in the original string to start matching against + * @param substring the substring to match at the given index + */ + public static boolean substringMatch(CharSequence str, int index, CharSequence substring) { + for (int j = 0; j < substring.length(); j++) { + int i = index + j; + if (i >= str.length() || str.charAt(i) != substring.charAt(j)) { + return false; + } + } + return true; + } + + /** + * Count the occurrences of the substring in string s. + * @param str string to search in. Return 0 if this is null. + * @param sub string to search for. Return 0 if this is null. + */ + public static int countOccurrencesOf(String str, String sub) { + if (str == null || sub == null || str.length() == 0 || sub.length() == 0) { + return 0; + } + int count = 0, pos = 0, idx = 0; + while ((idx = str.indexOf(sub, pos)) != -1) { + ++count; + pos = idx + sub.length(); + } + return count; + } + + /** + * Replace all occurences of a substring within a string with + * another string. + * @param inString String to examine + * @param oldPattern String to replace + * @param newPattern String to insert + * @return a String with the replacements + */ + public static String replace(String inString, String oldPattern, String newPattern) { + if (!hasLength(inString) || !hasLength(oldPattern) || newPattern == null) { + return inString; + } + StringBuffer sbuf = new StringBuffer(); + // output StringBuffer we'll build up + int pos = 0; // our position in the old string + int index = inString.indexOf(oldPattern); + // the index of an occurrence we've found, or -1 + int patLen = oldPattern.length(); + while (index >= 0) { + sbuf.append(inString.substring(pos, index)); + sbuf.append(newPattern); + pos = index + patLen; + index = inString.indexOf(oldPattern, pos); + } + sbuf.append(inString.substring(pos)); + // remember to append any characters to the right of a match + return sbuf.toString(); + } + + /** + * Delete all occurrences of the given substring. + * @param inString the original String + * @param pattern the pattern to delete all occurrences of + * @return the resulting String + */ + public static String delete(String inString, String pattern) { + return replace(inString, pattern, ""); + } + + /** + * Delete any character in a given String. + * @param inString the original String + * @param charsToDelete a set of characters to delete. + * E.g. "az\n" will delete 'a's, 'z's and new lines. + * @return the resulting String + */ + public static String deleteAny(String inString, String charsToDelete) { + if (!hasLength(inString) || !hasLength(charsToDelete)) { + return inString; + } + StringBuffer out = new StringBuffer(); + for (int i = 0; i < inString.length(); i++) { + char c = inString.charAt(i); + if (charsToDelete.indexOf(c) == -1) { + out.append(c); + } + } + return out.toString(); + } + + + //--------------------------------------------------------------------- + // Convenience methods for working with formatted Strings + //--------------------------------------------------------------------- + + /** + * Quote the given String with single quotes. + * @param str the input String (e.g. "myString") + * @return the quoted String (e.g. "'myString'"), + * or null if the input was null + */ + public static String quote(String str) { + return (str != null ? "'" + str + "'" : null); + } + + /** + * Turn the given Object into a String with single quotes + * if it is a String; keeping the Object as-is else. + * @param obj the input Object (e.g. "myString") + * @return the quoted String (e.g. "'myString'"), + * or the input object as-is if not a String + */ + public static Object quoteIfString(Object obj) { + return (obj instanceof String ? quote((String) obj) : obj); + } + + /** + * Unqualify a string qualified by a '.' dot character. For example, + * "this.name.is.qualified", returns "qualified". + * @param qualifiedName the qualified name + */ + public static String unqualify(String qualifiedName) { + return unqualify(qualifiedName, '.'); + } + + /** + * Unqualify a string qualified by a separator character. For example, + * "this:name:is:qualified" returns "qualified" if using a ':' separator. + * @param qualifiedName the qualified name + * @param separator the separator + */ + public static String unqualify(String qualifiedName, char separator) { + return qualifiedName.substring(qualifiedName.lastIndexOf(separator) + 1); + } + + /** + * Capitalize a String, changing the first letter to + * upper case as per {@link Character#toUpperCase(char)}. + * No other letters are changed. + * @param str the String to capitalize, may be null + * @return the capitalized String, null if null + */ + public static String capitalize(String str) { + return changeFirstCharacterCase(str, true); + } + + /** + * Uncapitalize a String, changing the first letter to + * lower case as per {@link Character#toLowerCase(char)}. + * No other letters are changed. + * @param str the String to uncapitalize, may be null + * @return the uncapitalized String, null if null + */ + public static String uncapitalize(String str) { + return changeFirstCharacterCase(str, false); + } + + private static String changeFirstCharacterCase(String str, boolean capitalize) { + if (str == null || str.length() == 0) { + return str; + } + StringBuffer buf = new StringBuffer(str.length()); + if (capitalize) { + buf.append(Character.toUpperCase(str.charAt(0))); + } + else { + buf.append(Character.toLowerCase(str.charAt(0))); + } + buf.append(str.substring(1)); + return buf.toString(); + } + + /** + * Extract the filename from the given path, + * e.g. "mypath/myfile.txt" -> "myfile.txt". + * @param path the file path (may be null) + * @return the extracted filename, or null if none + */ + public static String getFilename(String path) { + if (path == null) { + return null; + } + int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); + return (separatorIndex != -1 ? path.substring(separatorIndex + 1) : path); + } + + /** + * Extract the filename extension from the given path, + * e.g. "mypath/myfile.txt" -> "txt". + * @param path the file path (may be null) + * @return the extracted filename extension, or null if none + */ + public static String getFilenameExtension(String path) { + if (path == null) { + return null; + } + int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR); + return (sepIndex != -1 ? path.substring(sepIndex + 1) : null); + } + + /** + * Strip the filename extension from the given path, + * e.g. "mypath/myfile.txt" -> "mypath/myfile". + * @param path the file path (may be null) + * @return the path with stripped filename extension, + * or null if none + */ + public static String stripFilenameExtension(String path) { + if (path == null) { + return null; + } + int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR); + return (sepIndex != -1 ? path.substring(0, sepIndex) : path); + } + + /** + * Apply the given relative path to the given path, + * assuming standard Java folder separation (i.e. "/" separators); + * @param path the path to start from (usually a full file path) + * @param relativePath the relative path to apply + * (relative to the full file path above) + * @return the full file path that results from applying the relative path + */ + public static String applyRelativePath(String path, String relativePath) { + int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); + if (separatorIndex != -1) { + String newPath = path.substring(0, separatorIndex); + if (!relativePath.startsWith(FOLDER_SEPARATOR)) { + newPath += FOLDER_SEPARATOR; + } + return newPath + relativePath; + } + else { + return relativePath; + } + } + + /** + * Normalize the path by suppressing sequences like "path/.." and + * inner simple dots. + *

The result is convenient for path comparison. For other uses, + * notice that Windows separators ("\") are replaced by simple slashes. + * @param path the original path + * @return the normalized path + */ + public static String cleanPath(String path) { + if (path == null) { + return null; + } + String pathToUse = replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR); + + // Strip prefix from path to analyze, to not treat it as part of the + // first path element. This is necessary to correctly parse paths like + // "file:core/../core/io/Resource.class", where the ".." should just + // strip the first "core" directory while keeping the "file:" prefix. + int prefixIndex = pathToUse.indexOf(":"); + String prefix = ""; + if (prefixIndex != -1) { + prefix = pathToUse.substring(0, prefixIndex + 1); + pathToUse = pathToUse.substring(prefixIndex + 1); + } + if (pathToUse.startsWith(FOLDER_SEPARATOR)) { + prefix = prefix + FOLDER_SEPARATOR; + pathToUse = pathToUse.substring(1); + } + + String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR); + List pathElements = new LinkedList(); + int tops = 0; + + for (int i = pathArray.length - 1; i >= 0; i--) { + String element = pathArray[i]; + if (CURRENT_PATH.equals(element)) { + // Points to current directory - drop it. + } + else if (TOP_PATH.equals(element)) { + // Registering top path found. + tops++; + } + else { + if (tops > 0) { + // Merging path element with element corresponding to top path. + tops--; + } + else { + // Normal path element found. + pathElements.add(0, element); + } + } + } + + // Remaining top paths need to be retained. + for (int i = 0; i < tops; i++) { + pathElements.add(0, TOP_PATH); + } + + return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR); + } + + /** + * Compare two paths after normalization of them. + * @param path1 first path for comparison + * @param path2 second path for comparison + * @return whether the two paths are equivalent after normalization + */ + public static boolean pathEquals(String path1, String path2) { + return cleanPath(path1).equals(cleanPath(path2)); + } + + /** + * Parse the given localeString into a {@link Locale}. + *

This is the inverse operation of {@link Locale#toString Locale's toString}. + * @param localeString the locale string, following Locale's + * toString() format ("en", "en_UK", etc); + * also accepts spaces as separators, as an alternative to underscores + * @return a corresponding Locale instance + */ + public static Locale parseLocaleString(String localeString) { + String[] parts = tokenizeToStringArray(localeString, "_ ", false, false); + String language = (parts.length > 0 ? parts[0] : ""); + String country = (parts.length > 1 ? parts[1] : ""); + String variant = ""; + if (parts.length >= 2) { + // There is definitely a variant, and it is everything after the country + // code sans the separator between the country code and the variant. + int endIndexOfCountryCode = localeString.indexOf(country) + country.length(); + // Strip off any leading '_' and whitespace, what's left is the variant. + variant = trimLeadingWhitespace(localeString.substring(endIndexOfCountryCode)); + if (variant.startsWith("_")) { + variant = trimLeadingCharacter(variant, '_'); + } + } + return (language.length() > 0 ? new Locale(language, country, variant) : null); + } + + /** + * Determine the RFC 3066 compliant language tag, + * as used for the HTTP "Accept-Language" header. + * @param locale the Locale to transform to a language tag + * @return the RFC 3066 compliant language tag as String + */ + public static String toLanguageTag(Locale locale) { + return locale.getLanguage() + (hasText(locale.getCountry()) ? "-" + locale.getCountry() : ""); + } + + + //--------------------------------------------------------------------- + // Convenience methods for working with String arrays + //--------------------------------------------------------------------- + + /** + * Append the given String to the given String array, returning a new array + * consisting of the input array contents plus the given String. + * @param array the array to append to (can be null) + * @param str the String to append + * @return the new array (never null) + */ + public static String[] addStringToArray(String[] array, String str) { + if (ObjectUtils.isEmpty(array)) { + return new String[] {str}; + } + String[] newArr = new String[array.length + 1]; + System.arraycopy(array, 0, newArr, 0, array.length); + newArr[array.length] = str; + return newArr; + } + + /** + * Concatenate the given String arrays into one, + * with overlapping array elements included twice. + *

The order of elements in the original arrays is preserved. + * @param array1 the first array (can be null) + * @param array2 the second array (can be null) + * @return the new array (null if both given arrays were null) + */ + public static String[] concatenateStringArrays(String[] array1, String[] array2) { + if (ObjectUtils.isEmpty(array1)) { + return array2; + } + if (ObjectUtils.isEmpty(array2)) { + return array1; + } + String[] newArr = new String[array1.length + array2.length]; + System.arraycopy(array1, 0, newArr, 0, array1.length); + System.arraycopy(array2, 0, newArr, array1.length, array2.length); + return newArr; + } + + /** + * Merge the given String arrays into one, with overlapping + * array elements only included once. + *

The order of elements in the original arrays is preserved + * (with the exception of overlapping elements, which are only + * included on their first occurence). + * @param array1 the first array (can be null) + * @param array2 the second array (can be null) + * @return the new array (null if both given arrays were null) + */ + public static String[] mergeStringArrays(String[] array1, String[] array2) { + if (ObjectUtils.isEmpty(array1)) { + return array2; + } + if (ObjectUtils.isEmpty(array2)) { + return array1; + } + List result = new ArrayList(); + result.addAll(Arrays.asList(array1)); + for (int i = 0; i < array2.length; i++) { + String str = array2[i]; + if (!result.contains(str)) { + result.add(str); + } + } + return toStringArray(result); + } + + /** + * Turn given source String array into sorted array. + * @param array the source array + * @return the sorted array (never null) + */ + public static String[] sortStringArray(String[] array) { + if (ObjectUtils.isEmpty(array)) { + return new String[0]; + } + Arrays.sort(array); + return array; + } + + /** + * Copy the given Collection into a String array. + * The Collection must contain String elements only. + * @param collection the Collection to copy + * @return the String array (null if the passed-in + * Collection was null) + */ + public static String[] toStringArray(Collection collection) { + if (collection == null) { + return null; + } + return (String[]) collection.toArray(new String[collection.size()]); + } + + /** + * Copy the given Enumeration into a String array. + * The Enumeration must contain String elements only. + * @param enumeration the Enumeration to copy + * @return the String array (null if the passed-in + * Enumeration was null) + */ + public static String[] toStringArray(Enumeration enumeration) { + if (enumeration == null) { + return null; + } + List list = Collections.list(enumeration); + return (String[]) list.toArray(new String[list.size()]); + } + + /** + * Trim the elements of the given String array, + * calling String.trim() on each of them. + * @param array the original String array + * @return the resulting array (of the same size) with trimmed elements + */ + public static String[] trimArrayElements(String[] array) { + if (ObjectUtils.isEmpty(array)) { + return new String[0]; + } + String[] result = new String[array.length]; + for (int i = 0; i < array.length; i++) { + String element = array[i]; + result[i] = (element != null ? element.trim() : null); + } + return result; + } + + /** + * Remove duplicate Strings from the given array. + * Also sorts the array, as it uses a TreeSet. + * @param array the String array + * @return an array without duplicates, in natural sort order + */ + public static String[] removeDuplicateStrings(String[] array) { + if (ObjectUtils.isEmpty(array)) { + return array; + } + Set set = new TreeSet(); + for (int i = 0; i < array.length; i++) { + set.add(array[i]); + } + return toStringArray(set); + } + + /** + * Split a String at the first occurrence of the delimiter. + * Does not include the delimiter in the result. + * @param toSplit the string to split + * @param delimiter to split the string up with + * @return a two element array with index 0 being before the delimiter, and + * index 1 being after the delimiter (neither element includes the delimiter); + * or null if the delimiter wasn't found in the given input String + */ + public static String[] split(String toSplit, String delimiter) { + if (!hasLength(toSplit) || !hasLength(delimiter)) { + return null; + } + int offset = toSplit.indexOf(delimiter); + if (offset < 0) { + return null; + } + String beforeDelimiter = toSplit.substring(0, offset); + String afterDelimiter = toSplit.substring(offset + delimiter.length()); + return new String[] {beforeDelimiter, afterDelimiter}; + } + + /** + * Take an array Strings and split each element based on the given delimiter. + * A Properties instance is then generated, with the left of the + * delimiter providing the key, and the right of the delimiter providing the value. + *

Will trim both the key and value before adding them to the + * Properties instance. + * @param array the array to process + * @param delimiter to split each element using (typically the equals symbol) + * @return a Properties instance representing the array contents, + * or null if the array to process was null or empty + */ + public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter) { + return splitArrayElementsIntoProperties(array, delimiter, null); + } + + /** + * Take an array Strings and split each element based on the given delimiter. + * A Properties instance is then generated, with the left of the + * delimiter providing the key, and the right of the delimiter providing the value. + *

Will trim both the key and value before adding them to the + * Properties instance. + * @param array the array to process + * @param delimiter to split each element using (typically the equals symbol) + * @param charsToDelete one or more characters to remove from each element + * prior to attempting the split operation (typically the quotation mark + * symbol), or null if no removal should occur + * @return a Properties instance representing the array contents, + * or null if the array to process was null or empty + */ + public static Properties splitArrayElementsIntoProperties( + String[] array, String delimiter, String charsToDelete) { + + if (ObjectUtils.isEmpty(array)) { + return null; + } + Properties result = new Properties(); + for (int i = 0; i < array.length; i++) { + String element = array[i]; + if (charsToDelete != null) { + element = deleteAny(array[i], charsToDelete); + } + String[] splittedElement = split(element, delimiter); + if (splittedElement == null) { + continue; + } + result.setProperty(splittedElement[0].trim(), splittedElement[1].trim()); + } + return result; + } + + /** + * Tokenize the given String into a String array via a StringTokenizer. + * Trims tokens and omits empty tokens. + *

The given delimiters string is supposed to consist of any number of + * delimiter characters. Each of those characters can be used to separate + * tokens. A delimiter is always a single character; for multi-character + * delimiters, consider using delimitedListToStringArray + * @param str the String to tokenize + * @param delimiters the delimiter characters, assembled as String + * (each of those characters is individually considered as delimiter). + * @return an array of the tokens + * @see java.util.StringTokenizer + * @see java.lang.String#trim() + * @see #delimitedListToStringArray + */ + public static String[] tokenizeToStringArray(String str, String delimiters) { + return tokenizeToStringArray(str, delimiters, true, true); + } + + /** + * Tokenize the given String into a String array via a StringTokenizer. + *

The given delimiters string is supposed to consist of any number of + * delimiter characters. Each of those characters can be used to separate + * tokens. A delimiter is always a single character; for multi-character + * delimiters, consider using delimitedListToStringArray + * @param str the String to tokenize + * @param delimiters the delimiter characters, assembled as String + * (each of those characters is individually considered as delimiter) + * @param trimTokens trim the tokens via String's trim + * @param ignoreEmptyTokens omit empty tokens from the result array + * (only applies to tokens that are empty after trimming; StringTokenizer + * will not consider subsequent delimiters as token in the first place). + * @return an array of the tokens (null if the input String + * was null) + * @see java.util.StringTokenizer + * @see java.lang.String#trim() + * @see #delimitedListToStringArray + */ + public static String[] tokenizeToStringArray( + String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) { + + if (str == null) { + return null; + } + StringTokenizer st = new StringTokenizer(str, delimiters); + List tokens = new ArrayList(); + while (st.hasMoreTokens()) { + String token = st.nextToken(); + if (trimTokens) { + token = token.trim(); + } + if (!ignoreEmptyTokens || token.length() > 0) { + tokens.add(token); + } + } + return toStringArray(tokens); + } + + /** + * Take a String which is a delimited list and convert it to a String array. + *

A single delimiter can consists of more than one character: It will still + * be considered as single delimiter string, rather than as bunch of potential + * delimiter characters - in contrast to tokenizeToStringArray. + * @param str the input String + * @param delimiter the delimiter between elements (this is a single delimiter, + * rather than a bunch individual delimiter characters) + * @return an array of the tokens in the list + * @see #tokenizeToStringArray + */ + public static String[] delimitedListToStringArray(String str, String delimiter) { + return delimitedListToStringArray(str, delimiter, null); + } + + /** + * Take a String which is a delimited list and convert it to a String array. + *

A single delimiter can consists of more than one character: It will still + * be considered as single delimiter string, rather than as bunch of potential + * delimiter characters - in contrast to tokenizeToStringArray. + * @param str the input String + * @param delimiter the delimiter between elements (this is a single delimiter, + * rather than a bunch individual delimiter characters) + * @param charsToDelete a set of characters to delete. Useful for deleting unwanted + * line breaks: e.g. "\r\n\f" will delete all new lines and line feeds in a String. + * @return an array of the tokens in the list + * @see #tokenizeToStringArray + */ + public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) { + if (str == null) { + return new String[0]; + } + if (delimiter == null) { + return new String[] {str}; + } + List result = new ArrayList(); + if ("".equals(delimiter)) { + for (int i = 0; i < str.length(); i++) { + result.add(deleteAny(str.substring(i, i + 1), charsToDelete)); + } + } + else { + int pos = 0; + int delPos = 0; + while ((delPos = str.indexOf(delimiter, pos)) != -1) { + result.add(deleteAny(str.substring(pos, delPos), charsToDelete)); + pos = delPos + delimiter.length(); + } + if (str.length() > 0 && pos <= str.length()) { + // Add rest of String, but not in case of empty input. + result.add(deleteAny(str.substring(pos), charsToDelete)); + } + } + return toStringArray(result); + } + + /** + * Convert a CSV list into an array of Strings. + * @param str the input String + * @return an array of Strings, or the empty array in case of empty input + */ + public static String[] commaDelimitedListToStringArray(String str) { + return delimitedListToStringArray(str, ","); + } + + /** + * Convenience method to convert a CSV string list to a set. + * Note that this will suppress duplicates. + * @param str the input String + * @return a Set of String entries in the list + */ + public static Set commaDelimitedListToSet(String str) { + Set set = new TreeSet(); + String[] tokens = commaDelimitedListToStringArray(str); + for (int i = 0; i < tokens.length; i++) { + set.add(tokens[i]); + } + return set; + } + + /** + * Convenience method to return a Collection as a delimited (e.g. CSV) + * String. E.g. useful for toString() implementations. + * @param coll the Collection to display + * @param delim the delimiter to use (probably a ",") + * @param prefix the String to start each element with + * @param suffix the String to end each element with + * @return the delimited String + */ + public static String collectionToDelimitedString(Collection coll, String delim, String prefix, String suffix) { + if (CollectionUtils.isEmpty(coll)) { + return ""; + } + StringBuffer sb = new StringBuffer(); + Iterator it = coll.iterator(); + while (it.hasNext()) { + sb.append(prefix).append(it.next()).append(suffix); + if (it.hasNext()) { + sb.append(delim); + } + } + return sb.toString(); + } + + /** + * Convenience method to return a Collection as a delimited (e.g. CSV) + * String. E.g. useful for toString() implementations. + * @param coll the Collection to display + * @param delim the delimiter to use (probably a ",") + * @return the delimited String + */ + public static String collectionToDelimitedString(Collection coll, String delim) { + return collectionToDelimitedString(coll, delim, "", ""); + } + + /** + * Convenience method to return a Collection as a CSV String. + * E.g. useful for toString() implementations. + * @param coll the Collection to display + * @return the delimited String + */ + public static String collectionToCommaDelimitedString(Collection coll) { + return collectionToDelimitedString(coll, ","); + } + + /** + * Convenience method to return a String array as a delimited (e.g. CSV) + * String. E.g. useful for toString() implementations. + * @param arr the array to display + * @param delim the delimiter to use (probably a ",") + * @return the delimited String + */ + public static String arrayToDelimitedString(Object[] arr, String delim) { + if (ObjectUtils.isEmpty(arr)) { + return ""; + } + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < arr.length; i++) { + if (i > 0) { + sb.append(delim); + } + sb.append(arr[i]); + } + return sb.toString(); + } + + /** + * Convenience method to return a String array as a CSV String. + * E.g. useful for toString() implementations. + * @param arr the array to display + * @return the delimited String + */ + public static String arrayToCommaDelimitedString(Object[] arr) { + return arrayToDelimitedString(arr, ","); + } + +} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/SystemPropertyUtils.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/SystemPropertyUtils.java new file mode 100644 index 000000000..f81adc25b --- /dev/null +++ b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/osgi/boot/internal/springutil/SystemPropertyUtils.java @@ -0,0 +1,87 @@ +/* + * Copyright 2002-2008 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.argeo.osgi.boot.internal.springutil; + +/** + * Helper class for resolving placeholders in texts. Usually applied to file paths. + * + *

A text may contain ${...} placeholders, to be resolved as + * system properties: e.g. ${user.dir}. + * + * @author Juergen Hoeller + * @since 1.2.5 + * @see #PLACEHOLDER_PREFIX + * @see #PLACEHOLDER_SUFFIX + * @see System#getProperty(String) + */ +public abstract class SystemPropertyUtils { + + /** Prefix for system property placeholders: "${" */ + public static final String PLACEHOLDER_PREFIX = "${"; + + /** Suffix for system property placeholders: "}" */ + public static final String PLACEHOLDER_SUFFIX = "}"; + + + /** + * Resolve ${...} placeholders in the given text, + * replacing them with corresponding system property values. + * @param text the String to resolve + * @return the resolved String + * @see #PLACEHOLDER_PREFIX + * @see #PLACEHOLDER_SUFFIX + */ + public static String resolvePlaceholders(String text) { + StringBuffer buf = new StringBuffer(text); + + int startIndex = buf.indexOf(PLACEHOLDER_PREFIX); + while (startIndex != -1) { + int endIndex = buf.indexOf(PLACEHOLDER_SUFFIX, startIndex + PLACEHOLDER_PREFIX.length()); + if (endIndex != -1) { + String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex); + int nextIndex = endIndex + PLACEHOLDER_SUFFIX.length(); + try { + String propVal = System.getProperty(placeholder); + if (propVal == null) { + // Fall back to searching the system environment. + //propVal = System.getenv(placeholder);// mbaudier - 2009-07-26 + throw new Error("getenv no longer supported, use properties and -D instead: " + placeholder); + } + if (propVal != null) { + buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal); + nextIndex = startIndex + propVal.length(); + } + else { + System.err.println("Could not resolve placeholder '" + placeholder + "' in [" + text + + "] as system property: neither system property nor environment variable found"); + } + } + catch (Throwable ex) { + System.err.println("Could not resolve placeholder '" + placeholder + "' in [" + text + + "] as system property: " + ex); + } + startIndex = buf.indexOf(PLACEHOLDER_PREFIX, nextIndex); + } + else { + startIndex = -1; + } + } + + return buf.toString(); + } + +} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/Activator.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/Activator.java deleted file mode 100644 index 74b3482e6..000000000 --- a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/Activator.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright (C) 2010 Mathieu Baudier - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.argeo.slc.osgiboot; - -import org.osgi.framework.BundleActivator; -import org.osgi.framework.BundleContext; - -/** - * An OSGi configurator. See http: - * //wiki.eclipse.org/Configurator - */ -public class Activator implements BundleActivator { - - public void start(BundleContext bundleContext) throws Exception { - OsgiBoot osgiBoot = new OsgiBoot(bundleContext); - osgiBoot.bootstrap(); - } - - public void stop(BundleContext context) throws Exception { - } -} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/Launcher.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/Launcher.java deleted file mode 100644 index cd7b723b8..000000000 --- a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/Launcher.java +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright (C) 2010 Mathieu Baudier - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.argeo.slc.osgiboot; - -import java.io.FileInputStream; -import java.io.IOException; -import java.lang.reflect.Method; -import java.util.List; -import java.util.Vector; - -import org.eclipse.core.runtime.adaptor.EclipseStarter; -import org.osgi.framework.BundleContext; - -public class Launcher { - - public static void main(String[] args) { - // Try to load system properties - String systemPropertiesFilePath = OsgiBootUtils.getPropertyCompat( - OsgiBoot.PROP_ARGEO_OSGI_BOOT_SYSTEM_PROPERTIES_FILE, - OsgiBoot.PROP_SLC_OSGIBOOT_SYSTEM_PROPERTIES_FILE); - if (systemPropertiesFilePath != null) { - FileInputStream in; - try { - in = new FileInputStream(systemPropertiesFilePath); - System.getProperties().load(in); - } catch (IOException e1) { - throw new RuntimeException( - "Cannot load system properties from " - + systemPropertiesFilePath, e1); - } - if (in != null) { - try { - in.close(); - } catch (Exception e) { - // silent - } - } - } - - // Start main class - startMainClass(); - - // Start Equinox - BundleContext bundleContext = null; - try { - bundleContext = EclipseStarter.startup(args, null); - } catch (Exception e) { - throw new RuntimeException("Cannot start Equinox.", e); - } - - // OSGi bootstrap - OsgiBoot osgiBoot = new OsgiBoot(bundleContext); - osgiBoot.bootstrap(); - } - - protected static void startMainClass() { - // Properties config = System.getProperties(); - // String className = config.getProperty("slc.osgiboot.appclass"); - String className = OsgiBootUtils.getPropertyCompat( - OsgiBoot.PROP_ARGEO_OSGI_BOOT_APPCLASS, - OsgiBoot.PROP_SLC_OSGIBOOT_APPCLASS); - if (className == null) - return; - - // should use OsgiBootUtils.getPropertyCompat(), but it does not - // work for "" as default value - // so no warning displayed if PROP_SLC_OSGIBOOT_APPARGS is used - // FIXME: change OsgiBootUtils.getPropertyCompat() - String line = System.getProperty(OsgiBoot.PROP_ARGEO_OSGI_BOOT_APPARGS, - System.getProperty(OsgiBoot.PROP_SLC_OSGIBOOT_APPARGS, "")); - - String[] uiArgs = readArgumentsFromLine(line); - - try { - // Launch main method using reflection - Class clss = Class.forName(className); - Class[] mainArgsClasses = new Class[] { uiArgs.getClass() }; - Object[] mainArgs = { uiArgs }; - Method mainMethod = clss.getMethod("main", mainArgsClasses); - mainMethod.invoke(null, mainArgs); - } catch (Exception e) { - throw new RuntimeException("Cannot start main class.", e); - } - - } - - /** - * Transform a line into an array of arguments, taking "" as single - * arguments. (nested \" are not supported) - */ - private static String[] readArgumentsFromLine(String lineOrig) { - - String line = lineOrig.trim();// remove trailing spaces - // System.out.println("line=" + line); - List args = new Vector(); - StringBuffer curr = new StringBuffer(""); - boolean inQuote = false; - char[] arr = line.toCharArray(); - for (int i = 0; i < arr.length; i++) { - char c = arr[i]; - switch (c) { - case '\"': - inQuote = !inQuote; - break; - case ' ': - if (!inQuote) {// otherwise, no break: goes to default - if (curr.length() > 0) { - args.add(curr.toString()); - curr = new StringBuffer(""); - } - break; - } - default: - curr.append(c); - break; - } - } - - // Add last arg - if (curr.length() > 0) { - args.add(curr.toString()); - curr = null; - } - - String[] res = new String[args.size()]; - for (int i = 0; i < args.size(); i++) { - res[i] = args.get(i).toString(); - // System.out.println("res[i]=" + res[i]); - } - return res; - } - -} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/OsgiBoot.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/OsgiBoot.java deleted file mode 100644 index ccaa17cf4..000000000 --- a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/OsgiBoot.java +++ /dev/null @@ -1,763 +0,0 @@ -/* - * Copyright (C) 2010 Mathieu Baudier - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.argeo.slc.osgiboot; - -import java.io.BufferedReader; -import java.io.File; -import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.net.URL; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.StringTokenizer; - -import org.argeo.slc.osgiboot.internal.springutil.AntPathMatcher; -import org.argeo.slc.osgiboot.internal.springutil.PathMatcher; -import org.argeo.slc.osgiboot.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.PackageAdmin; - -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_ARGEO_OSGI_DATA_DIR = "argeo.osgi.data.dir"; - - public final static String PROP_ARGEO_OSGI_START = "argeo.osgi.start"; - 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"; - public final static String PROP_ARGEO_OSGI_MODULES_URL = "argeo.osgi.modulesUrl"; - - public final static String PROP_ARGEO_OSGI_BOOT_DEBUG = "argeo.osgi.boot.debug"; - 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"; - - /** @deprecated */ - public final static String PROP_SLC_OSGI_START = "slc.osgi.start"; - /** @deprecated */ - public final static String PROP_SLC_OSGI_BUNDLES = "slc.osgi.bundles"; - /** @deprecated */ - public final static String PROP_SLC_OSGI_LOCATIONS = "slc.osgi.locations"; - /** @deprecated */ - public final static String PROP_SLC_OSGI_BASE_URL = "slc.osgi.baseUrl"; - /** @deprecated */ - public final static String PROP_SLC_OSGI_MODULES_URL = "slc.osgi.modulesUrl"; - - /** @deprecated */ - public final static String PROP_SLC_OSGIBOOT_DEBUG = "slc.osgiboot.debug"; - /** @deprecated */ - public final static String PROP_SLC_OSGIBOOT_DEFAULT_TIMEOUT = "slc.osgiboot.defaultTimeout"; - /** @deprecated */ - public final static String PROP_SLC_OSGIBOOT_MODULES_URL_SEPARATOR = "slc.osgiboot.modulesUrlSeparator"; - /** @deprecated */ - public final static String PROP_SLC_OSGIBOOT_SYSTEM_PROPERTIES_FILE = "slc.osgiboot.systemPropertiesFile"; - /** @deprecated */ - public final static String PROP_SLC_OSGIBOOT_APPCLASS = "slc.osgiboot.appclass"; - /** @deprecated */ - public final static String PROP_SLC_OSGIBOOT_APPARGS = "slc.osgiboot.appargs"; - - - - public final static String DEFAULT_BASE_URL = "reference:file:"; - public final static String EXCLUDES_SVN_PATTERN = "**/.svn/**"; - - private boolean debug = Boolean.valueOf( - System.getProperty(PROP_ARGEO_OSGI_BOOT_DEBUG, System.getProperty( - PROP_SLC_OSGIBOOT_DEBUG, "false"))).booleanValue(); - /** Default is 10s (set in constructor) */ - private long defaultTimeout; - - private boolean excludeSvn = true; - /** Default is ',' (set in constructor) */ - private String modulesUrlSeparator = ","; - - private final BundleContext bundleContext; - - public OsgiBoot(BundleContext bundleContext) { - this.bundleContext = bundleContext; - defaultTimeout = Long.parseLong(OsgiBootUtils.getPropertyCompat( - PROP_ARGEO_OSGI_BOOT_DEFAULT_TIMEOUT, - PROP_SLC_OSGIBOOT_DEFAULT_TIMEOUT, "10000")); - modulesUrlSeparator = OsgiBootUtils.getPropertyCompat( - PROP_ARGEO_OSGI_BOOT_MODULES_URL_SEPARATOR, - PROP_SLC_OSGIBOOT_MODULES_URL_SEPARATOR, ","); - initSystemProperties(); - } - - protected void initSystemProperties() { - String osgiInstanceArea = System.getProperty("osgi.instance.area"); - String osgiInstanceAreaDefault = System - .getProperty("osgi.instance.area.default"); - 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()); - - // TODO: Load additional system properties from file - // Properties additionalSystemProperties = new Properties(); - - } - - public static 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; - } - - 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()); - 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"); - System.out.println(); - } - - public void installUrls(List urls) { - Map installedBundles = getInstalledBundles(); - for (int i = 0; i < urls.size(); i++) { - String url = (String) urls.get(i); - try { - if (installedBundles.containsKey(url)) { - Bundle bundle = (Bundle) installedBundles.get(url); - // bundle.update(); - if (debug) - debug("Bundle " + bundle.getSymbolicName() - + " already installed from " + url); - } else { - Bundle bundle = bundleContext.installBundle(url); - if (debug) - debug("Installed bundle " + bundle.getSymbolicName() - + " from " + url); - } - } catch (BundleException e) { - String message = e.getMessage(); - if ((message.contains("Bundle \"" + SYMBOLIC_NAME_OSGI_BOOT - + "\"") || message.contains("Bundle \"" - + SYMBOLIC_NAME_EQUINOX + "\"")) - && message.contains("has already been 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 (debug) - e.printStackTrace(); - } - } - - } - - 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()); - } - } - } - - } - - public void startBundles() { - String bundlesToStart = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_START, - PROP_SLC_OSGI_START); - startBundles(bundlesToStart); - } - - 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); - } - - public void startBundles(List bundlesToStart) { - if (bundlesToStart.size() == 0) - return; - - // used to log the bundles not found - List notFoundBundles = new ArrayList(bundlesToStart); - - Bundle[] bundles = bundleContext.getBundles(); - long startBegin = System.currentTimeMillis(); - for (int i = 0; i < bundles.length; i++) { - Bundle bundle = bundles[i]; - String symbolicName = bundle.getSymbolicName(); - if (bundlesToStart.contains(symbolicName)) - try { - try { - bundle.start(); - } catch (Exception e) { - 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(); - } - notFoundBundles.remove(symbolicName); - } catch (Exception e) { - OsgiBootUtils.warn("Bundle " + symbolicName + " cannot be started: " - + e.getMessage()); - if (debug) - e.printStackTrace(); - // was found even if start failed - notFoundBundles.remove(symbolicName); - } - } - - for (int i = 0; i < notFoundBundles.size(); i++) - OsgiBootUtils.warn("Bundle " + notFoundBundles.get(i) - + " not started because it was not found."); - } - - 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); - } - } - - protected void waitForBundleResolvedOrActive(long startBegin, Bundle bundle) - throws Exception { - int originalState = bundle.getState(); - if ((originalState == Bundle.RESOLVED) - || (originalState == Bundle.ACTIVE)) - return; - - String originalStateStr = stateAsString(originalState); - - int currentState = bundle.getState(); - while (!(currentState == Bundle.RESOLVED || currentState == Bundle.ACTIVE)) { - long now = System.currentTimeMillis(); - if ((now - startBegin) > defaultTimeout) - throw new Exception("Bundle " + bundle.getSymbolicName() - + " was not RESOLVED or ACTIVE after " - + (now - startBegin) + "ms (originalState=" - + originalStateStr + ", currentState=" - + stateAsString(currentState) + ")"); - - try { - Thread.sleep(100l); - } catch (InterruptedException e) { - // silent - } - currentState = bundle.getState(); - } - } - - public static String stateAsString(int state) { - switch (state) { - case Bundle.UNINSTALLED: - return "UNINSTALLED"; - case Bundle.INSTALLED: - return "INSTALLED"; - case Bundle.RESOLVED: - return "RESOLVED"; - case Bundle.STARTING: - return "STARTING"; - case Bundle.ACTIVE: - return "ACTIVE"; - case Bundle.STOPPING: - return "STOPPING"; - default: - return Integer.toString(state); - } - } - - /** Key is location */ - public Map getInstalledBundles() { - Map installedBundles = new HashMap(); - - Bundle[] bundles = bundleContext.getBundles(); - for (int i = 0; i < bundles.length; i++) { - installedBundles.put(bundles[i].getLocation(), bundles[i]); - } - return installedBundles; - } - - /** Key is symbolic name */ - public Map getBundles() { - Map namedBundles = new HashMap(); - Bundle[] bundles = bundleContext.getBundles(); - for (int i = 0; i < bundles.length; i++) { - namedBundles.put(bundles[i].getSymbolicName(), bundles[i]); - } - return namedBundles; - } - - public List getLocationsUrls() { - String baseUrl = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_BASE_URL, - PROP_SLC_OSGI_BASE_URL, DEFAULT_BASE_URL); - String bundleLocations = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_LOCATIONS, - PROP_SLC_OSGI_LOCATIONS); - return getLocationsUrls(baseUrl, bundleLocations); - } - - public List getModulesUrls() { - List urls = new ArrayList(); - String modulesUrlStr = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_MODULES_URL, - PROP_SLC_OSGI_MODULES_URL); - if (modulesUrlStr == null) - return urls; - - String baseUrl = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_BASE_URL, - PROP_SLC_OSGI_BASE_URL); - - Map installedBundles = getBundles(); - - 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 = 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); - } - } - } catch (Exception e1) { - throw new RuntimeException("Cannot read url " + modulesUrlStr, e1); - } finally { - if (reader != null) - try { - reader.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return urls; - } - - /** - * @return ==0: versions are identical, <0: tested version is newer, >0: - * currentVersion is newer. - */ - protected int compareVersions(String currentVersion, String testedVersion) { - List cToks = new ArrayList(); - StringTokenizer cSt = new StringTokenizer(currentVersion, "."); - while (cSt.hasMoreTokens()) - cToks.add(cSt.nextToken()); - List tToks = new ArrayList(); - StringTokenizer tSt = new StringTokenizer(currentVersion, "."); - while (tSt.hasMoreTokens()) - tToks.add(tSt.nextToken()); - - int comp = 0; - comp: for (int i = 0; i < cToks.size(); i++) { - if (tToks.size() <= i) { - // equals until then, tested shorter - comp = 1; - break comp; - } - - String c = (String) cToks.get(i); - String t = (String) tToks.get(i); - - try { - int cInt = Integer.parseInt(c); - int tInt = Integer.parseInt(t); - if (cInt == tInt) - continue comp; - else { - comp = (cInt - tInt); - break comp; - } - } catch (NumberFormatException e) { - if (c.equals(t)) - continue comp; - else { - comp = c.compareTo(t); - break comp; - } - } - } - - if (comp == 0 && tToks.size() > cToks.size()) { - // equals until then, current shorter - comp = -1; - } - - return comp; - } - - 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; - } - - public List getBundlesUrls() { - String baseUrl = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_BASE_URL, - PROP_SLC_OSGI_BASE_URL, DEFAULT_BASE_URL); - String bundlePatterns = OsgiBootUtils.getPropertyCompat(PROP_ARGEO_OSGI_BUNDLES, - PROP_SLC_OSGI_BUNDLES); - return getBundlesUrls(baseUrl, bundlePatterns); - } - - public List getBundlesUrls(String baseUrl, String bundlePatterns) { - List urls = new ArrayList(); - - List bundlesSets = new ArrayList(); - if (bundlePatterns == null) - return urls; - bundlePatterns = SystemPropertyUtils - .resolvePlaceholders(bundlePatterns); - if (debug) - debug(PROP_ARGEO_OSGI_BUNDLES + "=" + bundlePatterns - + " (excludeSvn=" + excludeSvn + ")"); - - StringTokenizer st = new StringTokenizer(bundlePatterns, ","); - while (st.hasMoreTokens()) { - bundlesSets.add(new BundlesSet(st.nextToken())); - } - - List included = new ArrayList(); - PathMatcher matcher = new AntPathMatcher(); - for (int i = 0; i < bundlesSets.size(); i++) { - BundlesSet bundlesSet = (BundlesSet) bundlesSets.get(i); - for (int j = 0; j < bundlesSet.getIncludes().size(); j++) { - String pattern = (String) bundlesSet.getIncludes().get(j); - match(matcher, included, bundlesSet.getDir(), null, pattern); - } - } - - 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++) { - String pattern = (String) bundlesSet.getExcludes().get(j); - match(matcher, excluded, bundlesSet.getDir(), null, pattern); - } - } - - for (int i = 0; i < included.size(); i++) { - String fullPath = (String) included.get(i); - if (!excluded.contains(fullPath)) - urls.add(locationToUrl(baseUrl, fullPath)); - } - - return urls; - } - - 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) { - OsgiBootUtils.warn("Base dir " + baseDir + " has no children, exists=" - + baseDir.exists() + ", isDirectory=" - + baseDir.isDirectory()); - return; - } - - for (int i = 0; i < files.length; i++) - match(matcher, matched, base, files[i].getName(), pattern); - } else { - String fullPath = base + '/' + currentPath; - if (matched.contains(fullPath)) - return;// don't try deeper if already matched - - boolean ok = matcher.match(pattern, currentPath); - if (debug) - debug(currentPath + " " + (ok ? "" : " not ") - + " matched with " + pattern); - if (ok) { - matched.add(fullPath); - return; - } else { - String newFullPath = relativeToFullPath(base, currentPath); - File newFile = new File(newFullPath); - File[] files = newFile.listFiles(); - if (files != null) { - for (int i = 0; i < files.length; i++) { - 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); - } else { - if (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); - if (nonDirectoryOk) - matched.add(relativeToFullPath(base, - newCurrentPath)); - } - } - } - } - } - } - - 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; - } - - /** Transforms a relative path in a full system path. */ - protected String relativeToFullPath(String basePath, String relativePath) { - return (basePath + '/' + relativePath).replace('/', File.separatorChar); - } - - protected void debug(Object obj) { - if (debug) - OsgiBootUtils.debug(obj); - } - - public boolean getDebug() { - return debug; - } - - public void setDebug(boolean debug) { - this.debug = debug; - } - - public BundleContext getBundleContext() { - return bundleContext; - } - - /** Whether to exclude Subversion directories (true by default) */ - public boolean isExcludeSvn() { - return excludeSvn; - } - - public void setExcludeSvn(boolean excludeSvn) { - this.excludeSvn = excludeSvn; - } - - 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; - } - - } - - public void setDefaultTimeout(long defaultTimeout) { - this.defaultTimeout = defaultTimeout; - } - - public void setModulesUrlSeparator(String modulesUrlSeparator) { - this.modulesUrlSeparator = modulesUrlSeparator; - } - -} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/OsgiBootUtils.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/OsgiBootUtils.java deleted file mode 100644 index 8c690cf57..000000000 --- a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/OsgiBootUtils.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2010 Mathieu Baudier - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.argeo.slc.osgiboot; - -public class OsgiBootUtils { - - public static void info(Object obj) { - System.out.println("# OSGiBOOT # " + obj); - } - - public static void debug(Object obj) { - System.out.println("# OSGiBOOT DBG # " + obj); - } - - public static void warn(Object obj) { - System.out.println("# OSGiBOOT WARN # " + obj); - // Because of a weird bug under Windows when starting it in a forked VM - // if (System.getProperty("os.name").contains("Windows")) - // System.out.println("# WARN " + obj); - // else - // System.err.println("# WARN " + obj); - } - - //FIXE: returns null when defaultValue is "" - public static String getProperty(String name, String defaultValue) { - final String value; - if (defaultValue != null) - value = System.getProperty(name, defaultValue); - else - value = System.getProperty(name); - - if (value == null || value.equals("")) - return null; - else - return value; - } - - public static String getProperty(String name) { - return getProperty(name, null); - } - - public static String getPropertyCompat(String name, String oldName) { - return getPropertyCompat(name, oldName, null); - } - - public static String getPropertyCompat(String name, String oldName, - String defaultValue) { - String res = null; - - if (defaultValue != null) { - res = getProperty(name, defaultValue); - if (res.equals(defaultValue)) { - res = getProperty(oldName, defaultValue); - if (!res.equals(defaultValue)) - warnDeprecated(name, oldName); - } - } else { - res = getProperty(name, null); - if (res == null) { - res = getProperty(oldName, null); - if (res != null) - warnDeprecated(name, oldName); - } - } - return res; - } - - public static void warnDeprecated(String name, String oldName) { - warn("Property '" + oldName - + "' is deprecated and will be removed soon, use '" + name - + "' instead."); - } - -} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/AntPathMatcher.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/AntPathMatcher.java deleted file mode 100644 index c426e1f64..000000000 --- a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/AntPathMatcher.java +++ /dev/null @@ -1,411 +0,0 @@ -/* - * Copyright 2002-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.argeo.slc.osgiboot.internal.springutil; - -/** - * PathMatcher implementation for Ant-style path patterns. - * Examples are provided below. - * - *

Part of this mapping code has been kindly borrowed from - * Apache Ant. - * - *

The mapping matches URLs using the following rules:
- *

    - *
  • ? matches one character
  • - *
  • * matches zero or more characters
  • - *
  • ** matches zero or more 'directories' in a path
  • - *
- * - *

Some examples:
- *

    - *
  • com/t?st.jsp - matches com/test.jsp but also - * com/tast.jsp or com/txst.jsp
  • - *
  • com/*.jsp - matches all .jsp files in the - * com directory
  • - *
  • com/**/test.jsp - matches all test.jsp - * files underneath the com path
  • - *
  • org/springframework/**/*.jsp - matches all .jsp - * files underneath the org/springframework path
  • - *
  • org/**/servlet/bla.jsp - matches - * org/springframework/servlet/bla.jsp but also - * org/springframework/testing/servlet/bla.jsp and - * org/servlet/bla.jsp
  • - *
- * - * @author Alef Arendsen - * @author Juergen Hoeller - * @author Rob Harrop - * @since 16.07.2003 - */ -public class AntPathMatcher implements PathMatcher { - - /** Default path separator: "/" */ - public static final String DEFAULT_PATH_SEPARATOR = "/"; - - private String pathSeparator = DEFAULT_PATH_SEPARATOR; - - - /** - * Set the path separator to use for pattern parsing. - * Default is "/", as in Ant. - */ - public void setPathSeparator(String pathSeparator) { - this.pathSeparator = (pathSeparator != null ? pathSeparator : DEFAULT_PATH_SEPARATOR); - } - - - public boolean isPattern(String path) { - return (path.indexOf('*') != -1 || path.indexOf('?') != -1); - } - - public boolean match(String pattern, String path) { - return doMatch(pattern, path, true); - } - - public boolean matchStart(String pattern, String path) { - return doMatch(pattern, path, false); - } - - - /** - * Actually match the given path against the given pattern. - * @param pattern the pattern to match against - * @param path the path String to test - * @param fullMatch whether a full pattern match is required - * (else a pattern match as far as the given base path goes is sufficient) - * @return true if the supplied path matched, - * false if it didn't - */ - protected boolean doMatch(String pattern, String path, boolean fullMatch) { - if (path.startsWith(this.pathSeparator) != pattern.startsWith(this.pathSeparator)) { - return false; - } - - String[] pattDirs = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator); - String[] pathDirs = StringUtils.tokenizeToStringArray(path, this.pathSeparator); - - int pattIdxStart = 0; - int pattIdxEnd = pattDirs.length - 1; - int pathIdxStart = 0; - int pathIdxEnd = pathDirs.length - 1; - - // Match all elements up to the first ** - while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) { - String patDir = pattDirs[pattIdxStart]; - if ("**".equals(patDir)) { - break; - } - if (!matchStrings(patDir, pathDirs[pathIdxStart])) { - return false; - } - pattIdxStart++; - pathIdxStart++; - } - - if (pathIdxStart > pathIdxEnd) { - // Path is exhausted, only match if rest of pattern is * or **'s - if (pattIdxStart > pattIdxEnd) { - return (pattern.endsWith(this.pathSeparator) ? - path.endsWith(this.pathSeparator) : !path.endsWith(this.pathSeparator)); - } - if (!fullMatch) { - return true; - } - if (pattIdxStart == pattIdxEnd && pattDirs[pattIdxStart].equals("*") && - path.endsWith(this.pathSeparator)) { - return true; - } - for (int i = pattIdxStart; i <= pattIdxEnd; i++) { - if (!pattDirs[i].equals("**")) { - return false; - } - } - return true; - } - else if (pattIdxStart > pattIdxEnd) { - // String not exhausted, but pattern is. Failure. - return false; - } - else if (!fullMatch && "**".equals(pattDirs[pattIdxStart])) { - // Path start definitely matches due to "**" part in pattern. - return true; - } - - // up to last '**' - while (pattIdxStart <= pattIdxEnd && pathIdxStart <= pathIdxEnd) { - String patDir = pattDirs[pattIdxEnd]; - if (patDir.equals("**")) { - break; - } - if (!matchStrings(patDir, pathDirs[pathIdxEnd])) { - return false; - } - pattIdxEnd--; - pathIdxEnd--; - } - if (pathIdxStart > pathIdxEnd) { - // String is exhausted - for (int i = pattIdxStart; i <= pattIdxEnd; i++) { - if (!pattDirs[i].equals("**")) { - return false; - } - } - return true; - } - - while (pattIdxStart != pattIdxEnd && pathIdxStart <= pathIdxEnd) { - int patIdxTmp = -1; - for (int i = pattIdxStart + 1; i <= pattIdxEnd; i++) { - if (pattDirs[i].equals("**")) { - patIdxTmp = i; - break; - } - } - if (patIdxTmp == pattIdxStart + 1) { - // '**/**' situation, so skip one - pattIdxStart++; - continue; - } - // Find the pattern between padIdxStart & padIdxTmp in str between - // strIdxStart & strIdxEnd - int patLength = (patIdxTmp - pattIdxStart - 1); - int strLength = (pathIdxEnd - pathIdxStart + 1); - int foundIdx = -1; - - strLoop: - for (int i = 0; i <= strLength - patLength; i++) { - for (int j = 0; j < patLength; j++) { - String subPat = (String) pattDirs[pattIdxStart + j + 1]; - String subStr = (String) pathDirs[pathIdxStart + i + j]; - if (!matchStrings(subPat, subStr)) { - continue strLoop; - } - } - foundIdx = pathIdxStart + i; - break; - } - - if (foundIdx == -1) { - return false; - } - - pattIdxStart = patIdxTmp; - pathIdxStart = foundIdx + patLength; - } - - for (int i = pattIdxStart; i <= pattIdxEnd; i++) { - if (!pattDirs[i].equals("**")) { - return false; - } - } - - return true; - } - - /** - * Tests whether or not a string matches against a pattern. - * The pattern may contain two special characters:
- * '*' means zero or more characters
- * '?' means one and only one character - * @param pattern pattern to match against. - * Must not be null. - * @param str string which must be matched against the pattern. - * Must not be null. - * @return true if the string matches against the - * pattern, or false otherwise. - */ - private boolean matchStrings(String pattern, String str) { - char[] patArr = pattern.toCharArray(); - char[] strArr = str.toCharArray(); - int patIdxStart = 0; - int patIdxEnd = patArr.length - 1; - int strIdxStart = 0; - int strIdxEnd = strArr.length - 1; - char ch; - - boolean containsStar = false; - for (int i = 0; i < patArr.length; i++) { - if (patArr[i] == '*') { - containsStar = true; - break; - } - } - - if (!containsStar) { - // No '*'s, so we make a shortcut - if (patIdxEnd != strIdxEnd) { - return false; // Pattern and string do not have the same size - } - for (int i = 0; i <= patIdxEnd; i++) { - ch = patArr[i]; - if (ch != '?') { - if (ch != strArr[i]) { - return false;// Character mismatch - } - } - } - return true; // String matches against pattern - } - - - if (patIdxEnd == 0) { - return true; // Pattern contains only '*', which matches anything - } - - // Process characters before first star - while ((ch = patArr[patIdxStart]) != '*' && strIdxStart <= strIdxEnd) { - if (ch != '?') { - if (ch != strArr[strIdxStart]) { - return false;// Character mismatch - } - } - patIdxStart++; - strIdxStart++; - } - if (strIdxStart > strIdxEnd) { - // All characters in the string are used. Check if only '*'s are - // left in the pattern. If so, we succeeded. Otherwise failure. - for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (patArr[i] != '*') { - return false; - } - } - return true; - } - - // Process characters after last star - while ((ch = patArr[patIdxEnd]) != '*' && strIdxStart <= strIdxEnd) { - if (ch != '?') { - if (ch != strArr[strIdxEnd]) { - return false;// Character mismatch - } - } - patIdxEnd--; - strIdxEnd--; - } - if (strIdxStart > strIdxEnd) { - // All characters in the string are used. Check if only '*'s are - // left in the pattern. If so, we succeeded. Otherwise failure. - for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (patArr[i] != '*') { - return false; - } - } - return true; - } - - // process pattern between stars. padIdxStart and patIdxEnd point - // always to a '*'. - while (patIdxStart != patIdxEnd && strIdxStart <= strIdxEnd) { - int patIdxTmp = -1; - for (int i = patIdxStart + 1; i <= patIdxEnd; i++) { - if (patArr[i] == '*') { - patIdxTmp = i; - break; - } - } - if (patIdxTmp == patIdxStart + 1) { - // Two stars next to each other, skip the first one. - patIdxStart++; - continue; - } - // Find the pattern between padIdxStart & padIdxTmp in str between - // strIdxStart & strIdxEnd - int patLength = (patIdxTmp - patIdxStart - 1); - int strLength = (strIdxEnd - strIdxStart + 1); - int foundIdx = -1; - strLoop: - for (int i = 0; i <= strLength - patLength; i++) { - for (int j = 0; j < patLength; j++) { - ch = patArr[patIdxStart + j + 1]; - if (ch != '?') { - if (ch != strArr[strIdxStart + i + j]) { - continue strLoop; - } - } - } - - foundIdx = strIdxStart + i; - break; - } - - if (foundIdx == -1) { - return false; - } - - patIdxStart = patIdxTmp; - strIdxStart = foundIdx + patLength; - } - - // All characters in the string are used. Check if only '*'s are left - // in the pattern. If so, we succeeded. Otherwise failure. - for (int i = patIdxStart; i <= patIdxEnd; i++) { - if (patArr[i] != '*') { - return false; - } - } - - return true; - } - - /** - * Given a pattern and a full path, determine the pattern-mapped part. - *

For example: - *

    - *
  • '/docs/cvs/commit.html' and '/docs/cvs/commit.html -> ''
  • - *
  • '/docs/*' and '/docs/cvs/commit -> 'cvs/commit'
  • - *
  • '/docs/cvs/*.html' and '/docs/cvs/commit.html -> 'commit.html'
  • - *
  • '/docs/**' and '/docs/cvs/commit -> 'cvs/commit'
  • - *
  • '/docs/**\/*.html' and '/docs/cvs/commit.html -> 'cvs/commit.html'
  • - *
  • '/*.html' and '/docs/cvs/commit.html -> 'docs/cvs/commit.html'
  • - *
  • '*.html' and '/docs/cvs/commit.html -> '/docs/cvs/commit.html'
  • - *
  • '*' and '/docs/cvs/commit.html -> '/docs/cvs/commit.html'
  • - *
- *

Assumes that {@link #match} returns true for 'pattern' - * and 'path', but does not enforce this. - */ - public String extractPathWithinPattern(String pattern, String path) { - String[] patternParts = StringUtils.tokenizeToStringArray(pattern, this.pathSeparator); - String[] pathParts = StringUtils.tokenizeToStringArray(path, this.pathSeparator); - - StringBuffer buffer = new StringBuffer(); - - // Add any path parts that have a wildcarded pattern part. - int puts = 0; - for (int i = 0; i < patternParts.length; i++) { - String patternPart = patternParts[i]; - if ((patternPart.indexOf('*') > -1 || patternPart.indexOf('?') > -1) && pathParts.length >= i + 1) { - if (puts > 0 || (i == 0 && !pattern.startsWith(this.pathSeparator))) { - buffer.append(this.pathSeparator); - } - buffer.append(pathParts[i]); - puts++; - } - } - - // Append any trailing path parts. - for (int i = patternParts.length; i < pathParts.length; i++) { - if (puts > 0 || i > 0) { - buffer.append(this.pathSeparator); - } - buffer.append(pathParts[i]); - } - - return buffer.toString(); - } - -} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/CollectionUtils.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/CollectionUtils.java deleted file mode 100644 index 61a611a69..000000000 --- a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/CollectionUtils.java +++ /dev/null @@ -1,275 +0,0 @@ -/* - * Copyright 2002-2008 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.argeo.slc.osgiboot.internal.springutil; - -import java.util.Arrays; -import java.util.Collection; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Properties; - -/** - * Miscellaneous collection utility methods. - * Mainly for internal use within the framework. - * - * @author Juergen Hoeller - * @author Rob Harrop - * @since 1.1.3 - */ -public abstract class CollectionUtils { - - /** - * Return true if the supplied Collection is null - * or empty. Otherwise, return false. - * @param collection the Collection to check - * @return whether the given Collection is empty - */ - public static boolean isEmpty(Collection collection) { - return (collection == null || collection.isEmpty()); - } - - /** - * Return true if the supplied Map is null - * or empty. Otherwise, return false. - * @param map the Map to check - * @return whether the given Map is empty - */ - public static boolean isEmpty(Map map) { - return (map == null || map.isEmpty()); - } - - /** - * Convert the supplied array into a List. A primitive array gets - * converted into a List of the appropriate wrapper type. - *

A null source value will be converted to an - * empty List. - * @param source the (potentially primitive) array - * @return the converted List result - * @see ObjectUtils#toObjectArray(Object) - */ - public static List arrayToList(Object source) { - return Arrays.asList(ObjectUtils.toObjectArray(source)); - } - - /** - * Merge the given array into the given Collection. - * @param array the array to merge (may be null) - * @param collection the target Collection to merge the array into - */ - public static void mergeArrayIntoCollection(Object array, Collection collection) { - if (collection == null) { - throw new IllegalArgumentException("Collection must not be null"); - } - Object[] arr = ObjectUtils.toObjectArray(array); - for (int i = 0; i < arr.length; i++) { - collection.add(arr[i]); - } - } - - /** - * Merge the given Properties instance into the given Map, - * copying all properties (key-value pairs) over. - *

Uses Properties.propertyNames() to even catch - * default properties linked into the original Properties instance. - * @param props the Properties instance to merge (may be null) - * @param map the target Map to merge the properties into - */ - public static void mergePropertiesIntoMap(Properties props, Map map) { - if (map == null) { - throw new IllegalArgumentException("Map must not be null"); - } - if (props != null) { - for (Enumeration en = props.propertyNames(); en.hasMoreElements();) { - String key = (String) en.nextElement(); - map.put(key, props.getProperty(key)); - } - } - } - - - /** - * Check whether the given Iterator contains the given element. - * @param iterator the Iterator to check - * @param element the element to look for - * @return true if found, false else - */ - public static boolean contains(Iterator iterator, Object element) { - if (iterator != null) { - while (iterator.hasNext()) { - Object candidate = iterator.next(); - if (ObjectUtils.nullSafeEquals(candidate, element)) { - return true; - } - } - } - return false; - } - - /** - * Check whether the given Enumeration contains the given element. - * @param enumeration the Enumeration to check - * @param element the element to look for - * @return true if found, false else - */ - public static boolean contains(Enumeration enumeration, Object element) { - if (enumeration != null) { - while (enumeration.hasMoreElements()) { - Object candidate = enumeration.nextElement(); - if (ObjectUtils.nullSafeEquals(candidate, element)) { - return true; - } - } - } - return false; - } - - /** - * Check whether the given Collection contains the given element instance. - *

Enforces the given instance to be present, rather than returning - * true for an equal element as well. - * @param collection the Collection to check - * @param element the element to look for - * @return true if found, false else - */ - public static boolean containsInstance(Collection collection, Object element) { - if (collection != null) { - for (Iterator it = collection.iterator(); it.hasNext();) { - Object candidate = it.next(); - if (candidate == element) { - return true; - } - } - } - return false; - } - - /** - * Return true if any element in 'candidates' is - * contained in 'source'; otherwise returns false. - * @param source the source Collection - * @param candidates the candidates to search for - * @return whether any of the candidates has been found - */ - public static boolean containsAny(Collection source, Collection candidates) { - if (isEmpty(source) || isEmpty(candidates)) { - return false; - } - for (Iterator it = candidates.iterator(); it.hasNext();) { - if (source.contains(it.next())) { - return true; - } - } - return false; - } - - /** - * Return the first element in 'candidates' that is contained in - * 'source'. If no element in 'candidates' is present in - * 'source' returns null. Iteration order is - * {@link Collection} implementation specific. - * @param source the source Collection - * @param candidates the candidates to search for - * @return the first present object, or null if not found - */ - public static Object findFirstMatch(Collection source, Collection candidates) { - if (isEmpty(source) || isEmpty(candidates)) { - return null; - } - for (Iterator it = candidates.iterator(); it.hasNext();) { - Object candidate = it.next(); - if (source.contains(candidate)) { - return candidate; - } - } - return null; - } - - /** - * Find a single value of the given type in the given Collection. - * @param collection the Collection to search - * @param type the type to look for - * @return a value of the given type found if there is a clear match, - * or null if none or more than one such value found - */ - public static Object findValueOfType(Collection collection, Class type) { - if (isEmpty(collection)) { - return null; - } - Object value = null; - for (Iterator it = collection.iterator(); it.hasNext();) { - Object obj = it.next(); - if (type == null || type.isInstance(obj)) { - if (value != null) { - // More than one value found... no clear single value. - return null; - } - value = obj; - } - } - return value; - } - - /** - * Find a single value of one of the given types in the given Collection: - * searching the Collection for a value of the first type, then - * searching for a value of the second type, etc. - * @param collection the collection to search - * @param types the types to look for, in prioritized order - * @return a value of one of the given types found if there is a clear match, - * or null if none or more than one such value found - */ - public static Object findValueOfType(Collection collection, Class[] types) { - if (isEmpty(collection) || ObjectUtils.isEmpty(types)) { - return null; - } - for (int i = 0; i < types.length; i++) { - Object value = findValueOfType(collection, types[i]); - if (value != null) { - return value; - } - } - return null; - } - - /** - * Determine whether the given Collection only contains a single unique object. - * @param collection the Collection to check - * @return true if the collection contains a single reference or - * multiple references to the same instance, false else - */ - public static boolean hasUniqueObject(Collection collection) { - if (isEmpty(collection)) { - return false; - } - boolean hasCandidate = false; - Object candidate = null; - for (Iterator it = collection.iterator(); it.hasNext();) { - Object elem = it.next(); - if (!hasCandidate) { - hasCandidate = true; - candidate = elem; - } - else if (candidate != elem) { - return false; - } - } - return true; - } - -} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/ObjectUtils.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/ObjectUtils.java deleted file mode 100644 index 5d6e98726..000000000 --- a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/ObjectUtils.java +++ /dev/null @@ -1,833 +0,0 @@ -/* - * Copyright 2002-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.argeo.slc.osgiboot.internal.springutil; - -import java.lang.reflect.Array; -import java.util.Arrays; - -/** - * Miscellaneous object utility methods. Mainly for internal use within the - * framework; consider Jakarta's Commons Lang for a more comprehensive suite - * of object utilities. - * - * @author Juergen Hoeller - * @author Keith Donald - * @author Rod Johnson - * @author Rob Harrop - * @author Alex Ruiz - * @since 19.03.2004 - * @see org.apache.commons.lang.ObjectUtils - */ -public abstract class ObjectUtils { - - private static final int INITIAL_HASH = 7; - private static final int MULTIPLIER = 31; - - private static final String EMPTY_STRING = ""; - private static final String NULL_STRING = "null"; - private static final String ARRAY_START = "{"; - private static final String ARRAY_END = "}"; - private static final String EMPTY_ARRAY = ARRAY_START + ARRAY_END; - private static final String ARRAY_ELEMENT_SEPARATOR = ", "; - - - /** - * Return whether the given throwable is a checked exception: - * that is, neither a RuntimeException nor an Error. - * @param ex the throwable to check - * @return whether the throwable is a checked exception - * @see java.lang.Exception - * @see java.lang.RuntimeException - * @see java.lang.Error - */ - public static boolean isCheckedException(Throwable ex) { - return !(ex instanceof RuntimeException || ex instanceof Error); - } - - /** - * Check whether the given exception is compatible with the exceptions - * declared in a throws clause. - * @param ex the exception to checked - * @param declaredExceptions the exceptions declared in the throws clause - * @return whether the given exception is compatible - */ - public static boolean isCompatibleWithThrowsClause(Throwable ex, Class[] declaredExceptions) { - if (!isCheckedException(ex)) { - return true; - } - if (declaredExceptions != null) { - for (int i = 0; i < declaredExceptions.length; i++) { - if (declaredExceptions[i].isAssignableFrom(ex.getClass())) { - return true; - } - } - } - return false; - } - - /** - * Return whether the given array is empty: that is, null - * or of zero length. - * @param array the array to check - * @return whether the given array is empty - */ - public static boolean isEmpty(Object[] array) { - return (array == null || array.length == 0); - } - - /** - * Check whether the given array contains the given element. - * @param array the array to check (may be null, - * in which case the return value will always be false) - * @param element the element to check for - * @return whether the element has been found in the given array - */ - public static boolean containsElement(Object[] array, Object element) { - if (array == null) { - return false; - } - for (int i = 0; i < array.length; i++) { - if (nullSafeEquals(array[i], element)) { - return true; - } - } - return false; - } - - /** - * Append the given Object to the given array, returning a new array - * consisting of the input array contents plus the given Object. - * @param array the array to append to (can be null) - * @param obj the Object to append - * @return the new array (of the same component type; never null) - */ - public static Object[] addObjectToArray(Object[] array, Object obj) { - Class compType = Object.class; - if (array != null) { - compType = array.getClass().getComponentType(); - } - else if (obj != null) { - compType = obj.getClass(); - } - int newArrLength = (array != null ? array.length + 1 : 1); - Object[] newArr = (Object[]) Array.newInstance(compType, newArrLength); - if (array != null) { - System.arraycopy(array, 0, newArr, 0, array.length); - } - newArr[newArr.length - 1] = obj; - return newArr; - } - - /** - * Convert the given array (which may be a primitive array) to an - * object array (if necessary of primitive wrapper objects). - *

A null source value will be converted to an - * empty Object array. - * @param source the (potentially primitive) array - * @return the corresponding object array (never null) - * @throws IllegalArgumentException if the parameter is not an array - */ - public static Object[] toObjectArray(Object source) { - if (source instanceof Object[]) { - return (Object[]) source; - } - if (source == null) { - return new Object[0]; - } - if (!source.getClass().isArray()) { - throw new IllegalArgumentException("Source is not an array: " + source); - } - int length = Array.getLength(source); - if (length == 0) { - return new Object[0]; - } - Class wrapperType = Array.get(source, 0).getClass(); - Object[] newArray = (Object[]) Array.newInstance(wrapperType, length); - for (int i = 0; i < length; i++) { - newArray[i] = Array.get(source, i); - } - return newArray; - } - - - //--------------------------------------------------------------------- - // Convenience methods for content-based equality/hash-code handling - //--------------------------------------------------------------------- - - /** - * Determine if the given objects are equal, returning true - * if both are null or false if only one is - * null. - *

Compares arrays with Arrays.equals, performing an equality - * check based on the array elements rather than the array reference. - * @param o1 first Object to compare - * @param o2 second Object to compare - * @return whether the given objects are equal - * @see java.util.Arrays#equals - */ - public static boolean nullSafeEquals(Object o1, Object o2) { - if (o1 == o2) { - return true; - } - if (o1 == null || o2 == null) { - return false; - } - if (o1.equals(o2)) { - return true; - } - if (o1.getClass().isArray() && o2.getClass().isArray()) { - if (o1 instanceof Object[] && o2 instanceof Object[]) { - return Arrays.equals((Object[]) o1, (Object[]) o2); - } - if (o1 instanceof boolean[] && o2 instanceof boolean[]) { - return Arrays.equals((boolean[]) o1, (boolean[]) o2); - } - if (o1 instanceof byte[] && o2 instanceof byte[]) { - return Arrays.equals((byte[]) o1, (byte[]) o2); - } - if (o1 instanceof char[] && o2 instanceof char[]) { - return Arrays.equals((char[]) o1, (char[]) o2); - } - if (o1 instanceof double[] && o2 instanceof double[]) { - return Arrays.equals((double[]) o1, (double[]) o2); - } - if (o1 instanceof float[] && o2 instanceof float[]) { - return Arrays.equals((float[]) o1, (float[]) o2); - } - if (o1 instanceof int[] && o2 instanceof int[]) { - return Arrays.equals((int[]) o1, (int[]) o2); - } - if (o1 instanceof long[] && o2 instanceof long[]) { - return Arrays.equals((long[]) o1, (long[]) o2); - } - if (o1 instanceof short[] && o2 instanceof short[]) { - return Arrays.equals((short[]) o1, (short[]) o2); - } - } - return false; - } - - /** - * Return as hash code for the given object; typically the value of - * {@link Object#hashCode()}. If the object is an array, - * this method will delegate to any of the nullSafeHashCode - * methods for arrays in this class. If the object is null, - * this method returns 0. - * @see #nullSafeHashCode(Object[]) - * @see #nullSafeHashCode(boolean[]) - * @see #nullSafeHashCode(byte[]) - * @see #nullSafeHashCode(char[]) - * @see #nullSafeHashCode(double[]) - * @see #nullSafeHashCode(float[]) - * @see #nullSafeHashCode(int[]) - * @see #nullSafeHashCode(long[]) - * @see #nullSafeHashCode(short[]) - */ - public static int nullSafeHashCode(Object obj) { - if (obj == null) { - return 0; - } - if (obj.getClass().isArray()) { - if (obj instanceof Object[]) { - return nullSafeHashCode((Object[]) obj); - } - if (obj instanceof boolean[]) { - return nullSafeHashCode((boolean[]) obj); - } - if (obj instanceof byte[]) { - return nullSafeHashCode((byte[]) obj); - } - if (obj instanceof char[]) { - return nullSafeHashCode((char[]) obj); - } - if (obj instanceof double[]) { - return nullSafeHashCode((double[]) obj); - } - if (obj instanceof float[]) { - return nullSafeHashCode((float[]) obj); - } - if (obj instanceof int[]) { - return nullSafeHashCode((int[]) obj); - } - if (obj instanceof long[]) { - return nullSafeHashCode((long[]) obj); - } - if (obj instanceof short[]) { - return nullSafeHashCode((short[]) obj); - } - } - return obj.hashCode(); - } - - /** - * Return a hash code based on the contents of the specified array. - * If array is null, this method returns 0. - */ - public static int nullSafeHashCode(Object[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - int arraySize = array.length; - for (int i = 0; i < arraySize; i++) { - hash = MULTIPLIER * hash + nullSafeHashCode(array[i]); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If array is null, this method returns 0. - */ - public static int nullSafeHashCode(boolean[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - int arraySize = array.length; - for (int i = 0; i < arraySize; i++) { - hash = MULTIPLIER * hash + hashCode(array[i]); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If array is null, this method returns 0. - */ - public static int nullSafeHashCode(byte[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - int arraySize = array.length; - for (int i = 0; i < arraySize; i++) { - hash = MULTIPLIER * hash + array[i]; - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If array is null, this method returns 0. - */ - public static int nullSafeHashCode(char[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - int arraySize = array.length; - for (int i = 0; i < arraySize; i++) { - hash = MULTIPLIER * hash + array[i]; - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If array is null, this method returns 0. - */ - public static int nullSafeHashCode(double[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - int arraySize = array.length; - for (int i = 0; i < arraySize; i++) { - hash = MULTIPLIER * hash + hashCode(array[i]); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If array is null, this method returns 0. - */ - public static int nullSafeHashCode(float[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - int arraySize = array.length; - for (int i = 0; i < arraySize; i++) { - hash = MULTIPLIER * hash + hashCode(array[i]); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If array is null, this method returns 0. - */ - public static int nullSafeHashCode(int[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - int arraySize = array.length; - for (int i = 0; i < arraySize; i++) { - hash = MULTIPLIER * hash + array[i]; - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If array is null, this method returns 0. - */ - public static int nullSafeHashCode(long[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - int arraySize = array.length; - for (int i = 0; i < arraySize; i++) { - hash = MULTIPLIER * hash + hashCode(array[i]); - } - return hash; - } - - /** - * Return a hash code based on the contents of the specified array. - * If array is null, this method returns 0. - */ - public static int nullSafeHashCode(short[] array) { - if (array == null) { - return 0; - } - int hash = INITIAL_HASH; - int arraySize = array.length; - for (int i = 0; i < arraySize; i++) { - hash = MULTIPLIER * hash + array[i]; - } - return hash; - } - - /** - * Return the same value as {@link Boolean#hashCode()}. - * @see Boolean#hashCode() - */ - public static int hashCode(boolean bool) { - return bool ? 1231 : 1237; - } - - /** - * Return the same value as {@link Double#hashCode()}. - * @see Double#hashCode() - */ - public static int hashCode(double dbl) { - long bits = Double.doubleToLongBits(dbl); - return hashCode(bits); - } - - /** - * Return the same value as {@link Float#hashCode()}. - * @see Float#hashCode() - */ - public static int hashCode(float flt) { - return Float.floatToIntBits(flt); - } - - /** - * Return the same value as {@link Long#hashCode()}. - * @see Long#hashCode() - */ - public static int hashCode(long lng) { - return (int) (lng ^ (lng >>> 32)); - } - - - //--------------------------------------------------------------------- - // Convenience methods for toString output - //--------------------------------------------------------------------- - - /** - * Return a String representation of an object's overall identity. - * @param obj the object (may be null) - * @return the object's identity as String representation, - * or an empty String if the object was null - */ - public static String identityToString(Object obj) { - if (obj == null) { - return EMPTY_STRING; - } - return obj.getClass().getName() + "@" + getIdentityHexString(obj); - } - - /** - * Return a hex String form of an object's identity hash code. - * @param obj the object - * @return the object's identity code in hex notation - */ - public static String getIdentityHexString(Object obj) { - return Integer.toHexString(System.identityHashCode(obj)); - } - - /** - * Return a content-based String representation if obj is - * not null; otherwise returns an empty String. - *

Differs from {@link #nullSafeToString(Object)} in that it returns - * an empty String rather than "null" for a null value. - * @param obj the object to build a display String for - * @return a display String representation of obj - * @see #nullSafeToString(Object) - */ - public static String getDisplayString(Object obj) { - if (obj == null) { - return EMPTY_STRING; - } - return nullSafeToString(obj); - } - - /** - * Determine the class name for the given object. - *

Returns "null" if obj is null. - * @param obj the object to introspect (may be null) - * @return the corresponding class name - */ - public static String nullSafeClassName(Object obj) { - return (obj != null ? obj.getClass().getName() : NULL_STRING); - } - - /** - * Return a String representation of the specified Object. - *

Builds a String representation of the contents in case of an array. - * Returns "null" if obj is null. - * @param obj the object to build a String representation for - * @return a String representation of obj - */ - public static String nullSafeToString(Object obj) { - if (obj == null) { - return NULL_STRING; - } - if (obj instanceof String) { - return (String) obj; - } - if (obj instanceof Object[]) { - return nullSafeToString((Object[]) obj); - } - if (obj instanceof boolean[]) { - return nullSafeToString((boolean[]) obj); - } - if (obj instanceof byte[]) { - return nullSafeToString((byte[]) obj); - } - if (obj instanceof char[]) { - return nullSafeToString((char[]) obj); - } - if (obj instanceof double[]) { - return nullSafeToString((double[]) obj); - } - if (obj instanceof float[]) { - return nullSafeToString((float[]) obj); - } - if (obj instanceof int[]) { - return nullSafeToString((int[]) obj); - } - if (obj instanceof long[]) { - return nullSafeToString((long[]) obj); - } - if (obj instanceof short[]) { - return nullSafeToString((short[]) obj); - } - String str = obj.toString(); - return (str != null ? str : EMPTY_STRING); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ("{}"). Adjacent elements are separated - * by the characters ", " (a comma followed by a space). Returns - * "null" if array is null. - * @param array the array to build a String representation for - * @return a String representation of array - */ - public static String nullSafeToString(Object[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < length; i++) { - if (i == 0) { - buffer.append(ARRAY_START); - } - else { - buffer.append(ARRAY_ELEMENT_SEPARATOR); - } - buffer.append(String.valueOf(array[i])); - } - buffer.append(ARRAY_END); - return buffer.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ("{}"). Adjacent elements are separated - * by the characters ", " (a comma followed by a space). Returns - * "null" if array is null. - * @param array the array to build a String representation for - * @return a String representation of array - */ - public static String nullSafeToString(boolean[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < length; i++) { - if (i == 0) { - buffer.append(ARRAY_START); - } - else { - buffer.append(ARRAY_ELEMENT_SEPARATOR); - } - - buffer.append(array[i]); - } - buffer.append(ARRAY_END); - return buffer.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ("{}"). Adjacent elements are separated - * by the characters ", " (a comma followed by a space). Returns - * "null" if array is null. - * @param array the array to build a String representation for - * @return a String representation of array - */ - public static String nullSafeToString(byte[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < length; i++) { - if (i == 0) { - buffer.append(ARRAY_START); - } - else { - buffer.append(ARRAY_ELEMENT_SEPARATOR); - } - buffer.append(array[i]); - } - buffer.append(ARRAY_END); - return buffer.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ("{}"). Adjacent elements are separated - * by the characters ", " (a comma followed by a space). Returns - * "null" if array is null. - * @param array the array to build a String representation for - * @return a String representation of array - */ - public static String nullSafeToString(char[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < length; i++) { - if (i == 0) { - buffer.append(ARRAY_START); - } - else { - buffer.append(ARRAY_ELEMENT_SEPARATOR); - } - buffer.append("'").append(array[i]).append("'"); - } - buffer.append(ARRAY_END); - return buffer.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ("{}"). Adjacent elements are separated - * by the characters ", " (a comma followed by a space). Returns - * "null" if array is null. - * @param array the array to build a String representation for - * @return a String representation of array - */ - public static String nullSafeToString(double[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < length; i++) { - if (i == 0) { - buffer.append(ARRAY_START); - } - else { - buffer.append(ARRAY_ELEMENT_SEPARATOR); - } - - buffer.append(array[i]); - } - buffer.append(ARRAY_END); - return buffer.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ("{}"). Adjacent elements are separated - * by the characters ", " (a comma followed by a space). Returns - * "null" if array is null. - * @param array the array to build a String representation for - * @return a String representation of array - */ - public static String nullSafeToString(float[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < length; i++) { - if (i == 0) { - buffer.append(ARRAY_START); - } - else { - buffer.append(ARRAY_ELEMENT_SEPARATOR); - } - - buffer.append(array[i]); - } - buffer.append(ARRAY_END); - return buffer.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ("{}"). Adjacent elements are separated - * by the characters ", " (a comma followed by a space). Returns - * "null" if array is null. - * @param array the array to build a String representation for - * @return a String representation of array - */ - public static String nullSafeToString(int[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < length; i++) { - if (i == 0) { - buffer.append(ARRAY_START); - } - else { - buffer.append(ARRAY_ELEMENT_SEPARATOR); - } - buffer.append(array[i]); - } - buffer.append(ARRAY_END); - return buffer.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ("{}"). Adjacent elements are separated - * by the characters ", " (a comma followed by a space). Returns - * "null" if array is null. - * @param array the array to build a String representation for - * @return a String representation of array - */ - public static String nullSafeToString(long[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < length; i++) { - if (i == 0) { - buffer.append(ARRAY_START); - } - else { - buffer.append(ARRAY_ELEMENT_SEPARATOR); - } - buffer.append(array[i]); - } - buffer.append(ARRAY_END); - return buffer.toString(); - } - - /** - * Return a String representation of the contents of the specified array. - *

The String representation consists of a list of the array's elements, - * enclosed in curly braces ("{}"). Adjacent elements are separated - * by the characters ", " (a comma followed by a space). Returns - * "null" if array is null. - * @param array the array to build a String representation for - * @return a String representation of array - */ - public static String nullSafeToString(short[] array) { - if (array == null) { - return NULL_STRING; - } - int length = array.length; - if (length == 0) { - return EMPTY_ARRAY; - } - StringBuffer buffer = new StringBuffer(); - for (int i = 0; i < length; i++) { - if (i == 0) { - buffer.append(ARRAY_START); - } - else { - buffer.append(ARRAY_ELEMENT_SEPARATOR); - } - buffer.append(array[i]); - } - buffer.append(ARRAY_END); - return buffer.toString(); - } - -} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/PathMatcher.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/PathMatcher.java deleted file mode 100644 index 1d8d31bfa..000000000 --- a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/PathMatcher.java +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2002-2007 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.argeo.slc.osgiboot.internal.springutil; - -/** - * Strategy interface for String-based path matching. - * - *

Used by {@link org.springframework.core.io.support.PathMatchingResourcePatternResolver}, - * {@link org.springframework.web.servlet.handler.AbstractUrlHandlerMapping}, - * {@link org.springframework.web.servlet.mvc.multiaction.PropertiesMethodNameResolver}, - * and {@link org.springframework.web.servlet.mvc.WebContentInterceptor}. - * - *

The default implementation is {@link AntPathMatcher}, supporting the - * Ant-style pattern syntax. - * - * @author Juergen Hoeller - * @since 1.2 - * @see AntPathMatcher - */ -public interface PathMatcher { - - /** - * Does the given path represent a pattern that can be matched - * by an implementation of this interface? - *

If the return value is false, then the {@link #match} - * method does not have to be used because direct equality comparisons - * on the static path Strings will lead to the same result. - * @param path the path String to check - * @return true if the given path represents a pattern - */ - boolean isPattern(String path); - - /** - * Match the given path against the given pattern, - * according to this PathMatcher's matching strategy. - * @param pattern the pattern to match against - * @param path the path String to test - * @return true if the supplied path matched, - * false if it didn't - */ - boolean match(String pattern, String path); - - /** - * Match the given path against the corresponding part of the given - * pattern, according to this PathMatcher's matching strategy. - *

Determines whether the pattern at least matches as far as the given base - * path goes, assuming that a full path may then match as well. - * @param pattern the pattern to match against - * @param path the path String to test - * @return true if the supplied path matched, - * false if it didn't - */ - boolean matchStart(String pattern, String path); - - /** - * Given a pattern and a full path, determine the pattern-mapped part. - *

This method is supposed to find out which part of the path is matched - * dynamically through an actual pattern, that is, it strips off a statically - * defined leading path from the given full path, returning only the actually - * pattern-matched part of the path. - *

For example: For "myroot/*.html" as pattern and "myroot/myfile.html" - * as full path, this method should return "myfile.html". The detailed - * determination rules are specified to this PathMatcher's matching strategy. - *

A simple implementation may return the given full path as-is in case - * of an actual pattern, and the empty String in case of the pattern not - * containing any dynamic parts (i.e. the pattern parameter being - * a static path that wouldn't qualify as an actual {@link #isPattern pattern}). - * A sophisticated implementation will differentiate between the static parts - * and the dynamic parts of the given path pattern. - * @param pattern the path pattern - * @param path the full path to introspect - * @return the pattern-mapped part of the given path - * (never null) - */ - String extractPathWithinPattern(String pattern, String path); - -} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/StringUtils.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/StringUtils.java deleted file mode 100644 index 39b033ff1..000000000 --- a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/StringUtils.java +++ /dev/null @@ -1,1113 +0,0 @@ -/* - * Copyright 2002-2008 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.argeo.slc.osgiboot.internal.springutil; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.Enumeration; -import java.util.Iterator; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Properties; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.TreeSet; - -/** - * Miscellaneous {@link String} utility methods. - * - *

Mainly for internal use within the framework; consider - * Jakarta's Commons Lang - * for a more comprehensive suite of String utilities. - * - *

This class delivers some simple functionality that should really - * be provided by the core Java String and {@link StringBuffer} - * classes, such as the ability to {@link #replace} all occurrences of a given - * substring in a target string. It also provides easy-to-use methods to convert - * between delimited strings, such as CSV strings, and collections and arrays. - * - * @author Rod Johnson - * @author Juergen Hoeller - * @author Keith Donald - * @author Rob Harrop - * @author Rick Evans - * @since 16 April 2001 - * @see org.apache.commons.lang.StringUtils - */ -public abstract class StringUtils { - - private static final String FOLDER_SEPARATOR = "/"; - - private static final String WINDOWS_FOLDER_SEPARATOR = "\\"; - - private static final String TOP_PATH = ".."; - - private static final String CURRENT_PATH = "."; - - private static final char EXTENSION_SEPARATOR = '.'; - - - //--------------------------------------------------------------------- - // General convenience methods for working with Strings - //--------------------------------------------------------------------- - - /** - * Check that the given CharSequence is neither null nor of length 0. - * Note: Will return true for a CharSequence that purely consists of whitespace. - *

-	 * StringUtils.hasLength(null) = false
-	 * StringUtils.hasLength("") = false
-	 * StringUtils.hasLength(" ") = true
-	 * StringUtils.hasLength("Hello") = true
-	 * 
- * @param str the CharSequence to check (may be null) - * @return true if the CharSequence is not null and has length - * @see #hasText(String) - */ - public static boolean hasLength(CharSequence str) { - return (str != null && str.length() > 0); - } - - /** - * Check that the given String is neither null nor of length 0. - * Note: Will return true for a String that purely consists of whitespace. - * @param str the String to check (may be null) - * @return true if the String is not null and has length - * @see #hasLength(CharSequence) - */ - public static boolean hasLength(String str) { - return hasLength((CharSequence) str); - } - - /** - * Check whether the given CharSequence has actual text. - * More specifically, returns true if the string not null, - * its length is greater than 0, and it contains at least one non-whitespace character. - *

-	 * StringUtils.hasText(null) = false
-	 * StringUtils.hasText("") = false
-	 * StringUtils.hasText(" ") = false
-	 * StringUtils.hasText("12345") = true
-	 * StringUtils.hasText(" 12345 ") = true
-	 * 
- * @param str the CharSequence to check (may be null) - * @return true if the CharSequence is not null, - * its length is greater than 0, and it does not contain whitespace only - * @see java.lang.Character#isWhitespace - */ - public static boolean hasText(CharSequence str) { - if (!hasLength(str)) { - return false; - } - int strLen = str.length(); - for (int i = 0; i < strLen; i++) { - if (!Character.isWhitespace(str.charAt(i))) { - return true; - } - } - return false; - } - - /** - * Check whether the given String has actual text. - * More specifically, returns true if the string not null, - * its length is greater than 0, and it contains at least one non-whitespace character. - * @param str the String to check (may be null) - * @return true if the String is not null, its length is - * greater than 0, and it does not contain whitespace only - * @see #hasText(CharSequence) - */ - public static boolean hasText(String str) { - return hasText((CharSequence) str); - } - - /** - * Check whether the given CharSequence contains any whitespace characters. - * @param str the CharSequence to check (may be null) - * @return true if the CharSequence is not empty and - * contains at least 1 whitespace character - * @see java.lang.Character#isWhitespace - */ - public static boolean containsWhitespace(CharSequence str) { - if (!hasLength(str)) { - return false; - } - int strLen = str.length(); - for (int i = 0; i < strLen; i++) { - if (Character.isWhitespace(str.charAt(i))) { - return true; - } - } - return false; - } - - /** - * Check whether the given String contains any whitespace characters. - * @param str the String to check (may be null) - * @return true if the String is not empty and - * contains at least 1 whitespace character - * @see #containsWhitespace(CharSequence) - */ - public static boolean containsWhitespace(String str) { - return containsWhitespace((CharSequence) str); - } - - /** - * Trim leading and trailing whitespace from the given String. - * @param str the String to check - * @return the trimmed String - * @see java.lang.Character#isWhitespace - */ - public static String trimWhitespace(String str) { - if (!hasLength(str)) { - return str; - } - StringBuffer buf = new StringBuffer(str); - while (buf.length() > 0 && Character.isWhitespace(buf.charAt(0))) { - buf.deleteCharAt(0); - } - while (buf.length() > 0 && Character.isWhitespace(buf.charAt(buf.length() - 1))) { - buf.deleteCharAt(buf.length() - 1); - } - return buf.toString(); - } - - /** - * Trim all whitespace from the given String: - * leading, trailing, and inbetween characters. - * @param str the String to check - * @return the trimmed String - * @see java.lang.Character#isWhitespace - */ - public static String trimAllWhitespace(String str) { - if (!hasLength(str)) { - return str; - } - StringBuffer buf = new StringBuffer(str); - int index = 0; - while (buf.length() > index) { - if (Character.isWhitespace(buf.charAt(index))) { - buf.deleteCharAt(index); - } - else { - index++; - } - } - return buf.toString(); - } - - /** - * Trim leading whitespace from the given String. - * @param str the String to check - * @return the trimmed String - * @see java.lang.Character#isWhitespace - */ - public static String trimLeadingWhitespace(String str) { - if (!hasLength(str)) { - return str; - } - StringBuffer buf = new StringBuffer(str); - while (buf.length() > 0 && Character.isWhitespace(buf.charAt(0))) { - buf.deleteCharAt(0); - } - return buf.toString(); - } - - /** - * Trim trailing whitespace from the given String. - * @param str the String to check - * @return the trimmed String - * @see java.lang.Character#isWhitespace - */ - public static String trimTrailingWhitespace(String str) { - if (!hasLength(str)) { - return str; - } - StringBuffer buf = new StringBuffer(str); - while (buf.length() > 0 && Character.isWhitespace(buf.charAt(buf.length() - 1))) { - buf.deleteCharAt(buf.length() - 1); - } - return buf.toString(); - } - - /** - * Trim all occurences of the supplied leading character from the given String. - * @param str the String to check - * @param leadingCharacter the leading character to be trimmed - * @return the trimmed String - */ - public static String trimLeadingCharacter(String str, char leadingCharacter) { - if (!hasLength(str)) { - return str; - } - StringBuffer buf = new StringBuffer(str); - while (buf.length() > 0 && buf.charAt(0) == leadingCharacter) { - buf.deleteCharAt(0); - } - return buf.toString(); - } - - /** - * Trim all occurences of the supplied trailing character from the given String. - * @param str the String to check - * @param trailingCharacter the trailing character to be trimmed - * @return the trimmed String - */ - public static String trimTrailingCharacter(String str, char trailingCharacter) { - if (!hasLength(str)) { - return str; - } - StringBuffer buf = new StringBuffer(str); - while (buf.length() > 0 && buf.charAt(buf.length() - 1) == trailingCharacter) { - buf.deleteCharAt(buf.length() - 1); - } - return buf.toString(); - } - - - /** - * Test if the given String starts with the specified prefix, - * ignoring upper/lower case. - * @param str the String to check - * @param prefix the prefix to look for - * @see java.lang.String#startsWith - */ - public static boolean startsWithIgnoreCase(String str, String prefix) { - if (str == null || prefix == null) { - return false; - } - if (str.startsWith(prefix)) { - return true; - } - if (str.length() < prefix.length()) { - return false; - } - String lcStr = str.substring(0, prefix.length()).toLowerCase(); - String lcPrefix = prefix.toLowerCase(); - return lcStr.equals(lcPrefix); - } - - /** - * Test if the given String ends with the specified suffix, - * ignoring upper/lower case. - * @param str the String to check - * @param suffix the suffix to look for - * @see java.lang.String#endsWith - */ - public static boolean endsWithIgnoreCase(String str, String suffix) { - if (str == null || suffix == null) { - return false; - } - if (str.endsWith(suffix)) { - return true; - } - if (str.length() < suffix.length()) { - return false; - } - - String lcStr = str.substring(str.length() - suffix.length()).toLowerCase(); - String lcSuffix = suffix.toLowerCase(); - return lcStr.equals(lcSuffix); - } - - /** - * Test whether the given string matches the given substring - * at the given index. - * @param str the original string (or StringBuffer) - * @param index the index in the original string to start matching against - * @param substring the substring to match at the given index - */ - public static boolean substringMatch(CharSequence str, int index, CharSequence substring) { - for (int j = 0; j < substring.length(); j++) { - int i = index + j; - if (i >= str.length() || str.charAt(i) != substring.charAt(j)) { - return false; - } - } - return true; - } - - /** - * Count the occurrences of the substring in string s. - * @param str string to search in. Return 0 if this is null. - * @param sub string to search for. Return 0 if this is null. - */ - public static int countOccurrencesOf(String str, String sub) { - if (str == null || sub == null || str.length() == 0 || sub.length() == 0) { - return 0; - } - int count = 0, pos = 0, idx = 0; - while ((idx = str.indexOf(sub, pos)) != -1) { - ++count; - pos = idx + sub.length(); - } - return count; - } - - /** - * Replace all occurences of a substring within a string with - * another string. - * @param inString String to examine - * @param oldPattern String to replace - * @param newPattern String to insert - * @return a String with the replacements - */ - public static String replace(String inString, String oldPattern, String newPattern) { - if (!hasLength(inString) || !hasLength(oldPattern) || newPattern == null) { - return inString; - } - StringBuffer sbuf = new StringBuffer(); - // output StringBuffer we'll build up - int pos = 0; // our position in the old string - int index = inString.indexOf(oldPattern); - // the index of an occurrence we've found, or -1 - int patLen = oldPattern.length(); - while (index >= 0) { - sbuf.append(inString.substring(pos, index)); - sbuf.append(newPattern); - pos = index + patLen; - index = inString.indexOf(oldPattern, pos); - } - sbuf.append(inString.substring(pos)); - // remember to append any characters to the right of a match - return sbuf.toString(); - } - - /** - * Delete all occurrences of the given substring. - * @param inString the original String - * @param pattern the pattern to delete all occurrences of - * @return the resulting String - */ - public static String delete(String inString, String pattern) { - return replace(inString, pattern, ""); - } - - /** - * Delete any character in a given String. - * @param inString the original String - * @param charsToDelete a set of characters to delete. - * E.g. "az\n" will delete 'a's, 'z's and new lines. - * @return the resulting String - */ - public static String deleteAny(String inString, String charsToDelete) { - if (!hasLength(inString) || !hasLength(charsToDelete)) { - return inString; - } - StringBuffer out = new StringBuffer(); - for (int i = 0; i < inString.length(); i++) { - char c = inString.charAt(i); - if (charsToDelete.indexOf(c) == -1) { - out.append(c); - } - } - return out.toString(); - } - - - //--------------------------------------------------------------------- - // Convenience methods for working with formatted Strings - //--------------------------------------------------------------------- - - /** - * Quote the given String with single quotes. - * @param str the input String (e.g. "myString") - * @return the quoted String (e.g. "'myString'"), - * or null if the input was null - */ - public static String quote(String str) { - return (str != null ? "'" + str + "'" : null); - } - - /** - * Turn the given Object into a String with single quotes - * if it is a String; keeping the Object as-is else. - * @param obj the input Object (e.g. "myString") - * @return the quoted String (e.g. "'myString'"), - * or the input object as-is if not a String - */ - public static Object quoteIfString(Object obj) { - return (obj instanceof String ? quote((String) obj) : obj); - } - - /** - * Unqualify a string qualified by a '.' dot character. For example, - * "this.name.is.qualified", returns "qualified". - * @param qualifiedName the qualified name - */ - public static String unqualify(String qualifiedName) { - return unqualify(qualifiedName, '.'); - } - - /** - * Unqualify a string qualified by a separator character. For example, - * "this:name:is:qualified" returns "qualified" if using a ':' separator. - * @param qualifiedName the qualified name - * @param separator the separator - */ - public static String unqualify(String qualifiedName, char separator) { - return qualifiedName.substring(qualifiedName.lastIndexOf(separator) + 1); - } - - /** - * Capitalize a String, changing the first letter to - * upper case as per {@link Character#toUpperCase(char)}. - * No other letters are changed. - * @param str the String to capitalize, may be null - * @return the capitalized String, null if null - */ - public static String capitalize(String str) { - return changeFirstCharacterCase(str, true); - } - - /** - * Uncapitalize a String, changing the first letter to - * lower case as per {@link Character#toLowerCase(char)}. - * No other letters are changed. - * @param str the String to uncapitalize, may be null - * @return the uncapitalized String, null if null - */ - public static String uncapitalize(String str) { - return changeFirstCharacterCase(str, false); - } - - private static String changeFirstCharacterCase(String str, boolean capitalize) { - if (str == null || str.length() == 0) { - return str; - } - StringBuffer buf = new StringBuffer(str.length()); - if (capitalize) { - buf.append(Character.toUpperCase(str.charAt(0))); - } - else { - buf.append(Character.toLowerCase(str.charAt(0))); - } - buf.append(str.substring(1)); - return buf.toString(); - } - - /** - * Extract the filename from the given path, - * e.g. "mypath/myfile.txt" -> "myfile.txt". - * @param path the file path (may be null) - * @return the extracted filename, or null if none - */ - public static String getFilename(String path) { - if (path == null) { - return null; - } - int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); - return (separatorIndex != -1 ? path.substring(separatorIndex + 1) : path); - } - - /** - * Extract the filename extension from the given path, - * e.g. "mypath/myfile.txt" -> "txt". - * @param path the file path (may be null) - * @return the extracted filename extension, or null if none - */ - public static String getFilenameExtension(String path) { - if (path == null) { - return null; - } - int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR); - return (sepIndex != -1 ? path.substring(sepIndex + 1) : null); - } - - /** - * Strip the filename extension from the given path, - * e.g. "mypath/myfile.txt" -> "mypath/myfile". - * @param path the file path (may be null) - * @return the path with stripped filename extension, - * or null if none - */ - public static String stripFilenameExtension(String path) { - if (path == null) { - return null; - } - int sepIndex = path.lastIndexOf(EXTENSION_SEPARATOR); - return (sepIndex != -1 ? path.substring(0, sepIndex) : path); - } - - /** - * Apply the given relative path to the given path, - * assuming standard Java folder separation (i.e. "/" separators); - * @param path the path to start from (usually a full file path) - * @param relativePath the relative path to apply - * (relative to the full file path above) - * @return the full file path that results from applying the relative path - */ - public static String applyRelativePath(String path, String relativePath) { - int separatorIndex = path.lastIndexOf(FOLDER_SEPARATOR); - if (separatorIndex != -1) { - String newPath = path.substring(0, separatorIndex); - if (!relativePath.startsWith(FOLDER_SEPARATOR)) { - newPath += FOLDER_SEPARATOR; - } - return newPath + relativePath; - } - else { - return relativePath; - } - } - - /** - * Normalize the path by suppressing sequences like "path/.." and - * inner simple dots. - *

The result is convenient for path comparison. For other uses, - * notice that Windows separators ("\") are replaced by simple slashes. - * @param path the original path - * @return the normalized path - */ - public static String cleanPath(String path) { - if (path == null) { - return null; - } - String pathToUse = replace(path, WINDOWS_FOLDER_SEPARATOR, FOLDER_SEPARATOR); - - // Strip prefix from path to analyze, to not treat it as part of the - // first path element. This is necessary to correctly parse paths like - // "file:core/../core/io/Resource.class", where the ".." should just - // strip the first "core" directory while keeping the "file:" prefix. - int prefixIndex = pathToUse.indexOf(":"); - String prefix = ""; - if (prefixIndex != -1) { - prefix = pathToUse.substring(0, prefixIndex + 1); - pathToUse = pathToUse.substring(prefixIndex + 1); - } - if (pathToUse.startsWith(FOLDER_SEPARATOR)) { - prefix = prefix + FOLDER_SEPARATOR; - pathToUse = pathToUse.substring(1); - } - - String[] pathArray = delimitedListToStringArray(pathToUse, FOLDER_SEPARATOR); - List pathElements = new LinkedList(); - int tops = 0; - - for (int i = pathArray.length - 1; i >= 0; i--) { - String element = pathArray[i]; - if (CURRENT_PATH.equals(element)) { - // Points to current directory - drop it. - } - else if (TOP_PATH.equals(element)) { - // Registering top path found. - tops++; - } - else { - if (tops > 0) { - // Merging path element with element corresponding to top path. - tops--; - } - else { - // Normal path element found. - pathElements.add(0, element); - } - } - } - - // Remaining top paths need to be retained. - for (int i = 0; i < tops; i++) { - pathElements.add(0, TOP_PATH); - } - - return prefix + collectionToDelimitedString(pathElements, FOLDER_SEPARATOR); - } - - /** - * Compare two paths after normalization of them. - * @param path1 first path for comparison - * @param path2 second path for comparison - * @return whether the two paths are equivalent after normalization - */ - public static boolean pathEquals(String path1, String path2) { - return cleanPath(path1).equals(cleanPath(path2)); - } - - /** - * Parse the given localeString into a {@link Locale}. - *

This is the inverse operation of {@link Locale#toString Locale's toString}. - * @param localeString the locale string, following Locale's - * toString() format ("en", "en_UK", etc); - * also accepts spaces as separators, as an alternative to underscores - * @return a corresponding Locale instance - */ - public static Locale parseLocaleString(String localeString) { - String[] parts = tokenizeToStringArray(localeString, "_ ", false, false); - String language = (parts.length > 0 ? parts[0] : ""); - String country = (parts.length > 1 ? parts[1] : ""); - String variant = ""; - if (parts.length >= 2) { - // There is definitely a variant, and it is everything after the country - // code sans the separator between the country code and the variant. - int endIndexOfCountryCode = localeString.indexOf(country) + country.length(); - // Strip off any leading '_' and whitespace, what's left is the variant. - variant = trimLeadingWhitespace(localeString.substring(endIndexOfCountryCode)); - if (variant.startsWith("_")) { - variant = trimLeadingCharacter(variant, '_'); - } - } - return (language.length() > 0 ? new Locale(language, country, variant) : null); - } - - /** - * Determine the RFC 3066 compliant language tag, - * as used for the HTTP "Accept-Language" header. - * @param locale the Locale to transform to a language tag - * @return the RFC 3066 compliant language tag as String - */ - public static String toLanguageTag(Locale locale) { - return locale.getLanguage() + (hasText(locale.getCountry()) ? "-" + locale.getCountry() : ""); - } - - - //--------------------------------------------------------------------- - // Convenience methods for working with String arrays - //--------------------------------------------------------------------- - - /** - * Append the given String to the given String array, returning a new array - * consisting of the input array contents plus the given String. - * @param array the array to append to (can be null) - * @param str the String to append - * @return the new array (never null) - */ - public static String[] addStringToArray(String[] array, String str) { - if (ObjectUtils.isEmpty(array)) { - return new String[] {str}; - } - String[] newArr = new String[array.length + 1]; - System.arraycopy(array, 0, newArr, 0, array.length); - newArr[array.length] = str; - return newArr; - } - - /** - * Concatenate the given String arrays into one, - * with overlapping array elements included twice. - *

The order of elements in the original arrays is preserved. - * @param array1 the first array (can be null) - * @param array2 the second array (can be null) - * @return the new array (null if both given arrays were null) - */ - public static String[] concatenateStringArrays(String[] array1, String[] array2) { - if (ObjectUtils.isEmpty(array1)) { - return array2; - } - if (ObjectUtils.isEmpty(array2)) { - return array1; - } - String[] newArr = new String[array1.length + array2.length]; - System.arraycopy(array1, 0, newArr, 0, array1.length); - System.arraycopy(array2, 0, newArr, array1.length, array2.length); - return newArr; - } - - /** - * Merge the given String arrays into one, with overlapping - * array elements only included once. - *

The order of elements in the original arrays is preserved - * (with the exception of overlapping elements, which are only - * included on their first occurence). - * @param array1 the first array (can be null) - * @param array2 the second array (can be null) - * @return the new array (null if both given arrays were null) - */ - public static String[] mergeStringArrays(String[] array1, String[] array2) { - if (ObjectUtils.isEmpty(array1)) { - return array2; - } - if (ObjectUtils.isEmpty(array2)) { - return array1; - } - List result = new ArrayList(); - result.addAll(Arrays.asList(array1)); - for (int i = 0; i < array2.length; i++) { - String str = array2[i]; - if (!result.contains(str)) { - result.add(str); - } - } - return toStringArray(result); - } - - /** - * Turn given source String array into sorted array. - * @param array the source array - * @return the sorted array (never null) - */ - public static String[] sortStringArray(String[] array) { - if (ObjectUtils.isEmpty(array)) { - return new String[0]; - } - Arrays.sort(array); - return array; - } - - /** - * Copy the given Collection into a String array. - * The Collection must contain String elements only. - * @param collection the Collection to copy - * @return the String array (null if the passed-in - * Collection was null) - */ - public static String[] toStringArray(Collection collection) { - if (collection == null) { - return null; - } - return (String[]) collection.toArray(new String[collection.size()]); - } - - /** - * Copy the given Enumeration into a String array. - * The Enumeration must contain String elements only. - * @param enumeration the Enumeration to copy - * @return the String array (null if the passed-in - * Enumeration was null) - */ - public static String[] toStringArray(Enumeration enumeration) { - if (enumeration == null) { - return null; - } - List list = Collections.list(enumeration); - return (String[]) list.toArray(new String[list.size()]); - } - - /** - * Trim the elements of the given String array, - * calling String.trim() on each of them. - * @param array the original String array - * @return the resulting array (of the same size) with trimmed elements - */ - public static String[] trimArrayElements(String[] array) { - if (ObjectUtils.isEmpty(array)) { - return new String[0]; - } - String[] result = new String[array.length]; - for (int i = 0; i < array.length; i++) { - String element = array[i]; - result[i] = (element != null ? element.trim() : null); - } - return result; - } - - /** - * Remove duplicate Strings from the given array. - * Also sorts the array, as it uses a TreeSet. - * @param array the String array - * @return an array without duplicates, in natural sort order - */ - public static String[] removeDuplicateStrings(String[] array) { - if (ObjectUtils.isEmpty(array)) { - return array; - } - Set set = new TreeSet(); - for (int i = 0; i < array.length; i++) { - set.add(array[i]); - } - return toStringArray(set); - } - - /** - * Split a String at the first occurrence of the delimiter. - * Does not include the delimiter in the result. - * @param toSplit the string to split - * @param delimiter to split the string up with - * @return a two element array with index 0 being before the delimiter, and - * index 1 being after the delimiter (neither element includes the delimiter); - * or null if the delimiter wasn't found in the given input String - */ - public static String[] split(String toSplit, String delimiter) { - if (!hasLength(toSplit) || !hasLength(delimiter)) { - return null; - } - int offset = toSplit.indexOf(delimiter); - if (offset < 0) { - return null; - } - String beforeDelimiter = toSplit.substring(0, offset); - String afterDelimiter = toSplit.substring(offset + delimiter.length()); - return new String[] {beforeDelimiter, afterDelimiter}; - } - - /** - * Take an array Strings and split each element based on the given delimiter. - * A Properties instance is then generated, with the left of the - * delimiter providing the key, and the right of the delimiter providing the value. - *

Will trim both the key and value before adding them to the - * Properties instance. - * @param array the array to process - * @param delimiter to split each element using (typically the equals symbol) - * @return a Properties instance representing the array contents, - * or null if the array to process was null or empty - */ - public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter) { - return splitArrayElementsIntoProperties(array, delimiter, null); - } - - /** - * Take an array Strings and split each element based on the given delimiter. - * A Properties instance is then generated, with the left of the - * delimiter providing the key, and the right of the delimiter providing the value. - *

Will trim both the key and value before adding them to the - * Properties instance. - * @param array the array to process - * @param delimiter to split each element using (typically the equals symbol) - * @param charsToDelete one or more characters to remove from each element - * prior to attempting the split operation (typically the quotation mark - * symbol), or null if no removal should occur - * @return a Properties instance representing the array contents, - * or null if the array to process was null or empty - */ - public static Properties splitArrayElementsIntoProperties( - String[] array, String delimiter, String charsToDelete) { - - if (ObjectUtils.isEmpty(array)) { - return null; - } - Properties result = new Properties(); - for (int i = 0; i < array.length; i++) { - String element = array[i]; - if (charsToDelete != null) { - element = deleteAny(array[i], charsToDelete); - } - String[] splittedElement = split(element, delimiter); - if (splittedElement == null) { - continue; - } - result.setProperty(splittedElement[0].trim(), splittedElement[1].trim()); - } - return result; - } - - /** - * Tokenize the given String into a String array via a StringTokenizer. - * Trims tokens and omits empty tokens. - *

The given delimiters string is supposed to consist of any number of - * delimiter characters. Each of those characters can be used to separate - * tokens. A delimiter is always a single character; for multi-character - * delimiters, consider using delimitedListToStringArray - * @param str the String to tokenize - * @param delimiters the delimiter characters, assembled as String - * (each of those characters is individually considered as delimiter). - * @return an array of the tokens - * @see java.util.StringTokenizer - * @see java.lang.String#trim() - * @see #delimitedListToStringArray - */ - public static String[] tokenizeToStringArray(String str, String delimiters) { - return tokenizeToStringArray(str, delimiters, true, true); - } - - /** - * Tokenize the given String into a String array via a StringTokenizer. - *

The given delimiters string is supposed to consist of any number of - * delimiter characters. Each of those characters can be used to separate - * tokens. A delimiter is always a single character; for multi-character - * delimiters, consider using delimitedListToStringArray - * @param str the String to tokenize - * @param delimiters the delimiter characters, assembled as String - * (each of those characters is individually considered as delimiter) - * @param trimTokens trim the tokens via String's trim - * @param ignoreEmptyTokens omit empty tokens from the result array - * (only applies to tokens that are empty after trimming; StringTokenizer - * will not consider subsequent delimiters as token in the first place). - * @return an array of the tokens (null if the input String - * was null) - * @see java.util.StringTokenizer - * @see java.lang.String#trim() - * @see #delimitedListToStringArray - */ - public static String[] tokenizeToStringArray( - String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) { - - if (str == null) { - return null; - } - StringTokenizer st = new StringTokenizer(str, delimiters); - List tokens = new ArrayList(); - while (st.hasMoreTokens()) { - String token = st.nextToken(); - if (trimTokens) { - token = token.trim(); - } - if (!ignoreEmptyTokens || token.length() > 0) { - tokens.add(token); - } - } - return toStringArray(tokens); - } - - /** - * Take a String which is a delimited list and convert it to a String array. - *

A single delimiter can consists of more than one character: It will still - * be considered as single delimiter string, rather than as bunch of potential - * delimiter characters - in contrast to tokenizeToStringArray. - * @param str the input String - * @param delimiter the delimiter between elements (this is a single delimiter, - * rather than a bunch individual delimiter characters) - * @return an array of the tokens in the list - * @see #tokenizeToStringArray - */ - public static String[] delimitedListToStringArray(String str, String delimiter) { - return delimitedListToStringArray(str, delimiter, null); - } - - /** - * Take a String which is a delimited list and convert it to a String array. - *

A single delimiter can consists of more than one character: It will still - * be considered as single delimiter string, rather than as bunch of potential - * delimiter characters - in contrast to tokenizeToStringArray. - * @param str the input String - * @param delimiter the delimiter between elements (this is a single delimiter, - * rather than a bunch individual delimiter characters) - * @param charsToDelete a set of characters to delete. Useful for deleting unwanted - * line breaks: e.g. "\r\n\f" will delete all new lines and line feeds in a String. - * @return an array of the tokens in the list - * @see #tokenizeToStringArray - */ - public static String[] delimitedListToStringArray(String str, String delimiter, String charsToDelete) { - if (str == null) { - return new String[0]; - } - if (delimiter == null) { - return new String[] {str}; - } - List result = new ArrayList(); - if ("".equals(delimiter)) { - for (int i = 0; i < str.length(); i++) { - result.add(deleteAny(str.substring(i, i + 1), charsToDelete)); - } - } - else { - int pos = 0; - int delPos = 0; - while ((delPos = str.indexOf(delimiter, pos)) != -1) { - result.add(deleteAny(str.substring(pos, delPos), charsToDelete)); - pos = delPos + delimiter.length(); - } - if (str.length() > 0 && pos <= str.length()) { - // Add rest of String, but not in case of empty input. - result.add(deleteAny(str.substring(pos), charsToDelete)); - } - } - return toStringArray(result); - } - - /** - * Convert a CSV list into an array of Strings. - * @param str the input String - * @return an array of Strings, or the empty array in case of empty input - */ - public static String[] commaDelimitedListToStringArray(String str) { - return delimitedListToStringArray(str, ","); - } - - /** - * Convenience method to convert a CSV string list to a set. - * Note that this will suppress duplicates. - * @param str the input String - * @return a Set of String entries in the list - */ - public static Set commaDelimitedListToSet(String str) { - Set set = new TreeSet(); - String[] tokens = commaDelimitedListToStringArray(str); - for (int i = 0; i < tokens.length; i++) { - set.add(tokens[i]); - } - return set; - } - - /** - * Convenience method to return a Collection as a delimited (e.g. CSV) - * String. E.g. useful for toString() implementations. - * @param coll the Collection to display - * @param delim the delimiter to use (probably a ",") - * @param prefix the String to start each element with - * @param suffix the String to end each element with - * @return the delimited String - */ - public static String collectionToDelimitedString(Collection coll, String delim, String prefix, String suffix) { - if (CollectionUtils.isEmpty(coll)) { - return ""; - } - StringBuffer sb = new StringBuffer(); - Iterator it = coll.iterator(); - while (it.hasNext()) { - sb.append(prefix).append(it.next()).append(suffix); - if (it.hasNext()) { - sb.append(delim); - } - } - return sb.toString(); - } - - /** - * Convenience method to return a Collection as a delimited (e.g. CSV) - * String. E.g. useful for toString() implementations. - * @param coll the Collection to display - * @param delim the delimiter to use (probably a ",") - * @return the delimited String - */ - public static String collectionToDelimitedString(Collection coll, String delim) { - return collectionToDelimitedString(coll, delim, "", ""); - } - - /** - * Convenience method to return a Collection as a CSV String. - * E.g. useful for toString() implementations. - * @param coll the Collection to display - * @return the delimited String - */ - public static String collectionToCommaDelimitedString(Collection coll) { - return collectionToDelimitedString(coll, ","); - } - - /** - * Convenience method to return a String array as a delimited (e.g. CSV) - * String. E.g. useful for toString() implementations. - * @param arr the array to display - * @param delim the delimiter to use (probably a ",") - * @return the delimited String - */ - public static String arrayToDelimitedString(Object[] arr, String delim) { - if (ObjectUtils.isEmpty(arr)) { - return ""; - } - StringBuffer sb = new StringBuffer(); - for (int i = 0; i < arr.length; i++) { - if (i > 0) { - sb.append(delim); - } - sb.append(arr[i]); - } - return sb.toString(); - } - - /** - * Convenience method to return a String array as a CSV String. - * E.g. useful for toString() implementations. - * @param arr the array to display - * @return the delimited String - */ - public static String arrayToCommaDelimitedString(Object[] arr) { - return arrayToDelimitedString(arr, ","); - } - -} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/SystemPropertyUtils.java b/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/SystemPropertyUtils.java deleted file mode 100644 index 8b1113c2e..000000000 --- a/osgi/runtime/org.argeo.osgi.boot/src/main/java/org/argeo/slc/osgiboot/internal/springutil/SystemPropertyUtils.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright 2002-2008 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.argeo.slc.osgiboot.internal.springutil; - -/** - * Helper class for resolving placeholders in texts. Usually applied to file paths. - * - *

A text may contain ${...} placeholders, to be resolved as - * system properties: e.g. ${user.dir}. - * - * @author Juergen Hoeller - * @since 1.2.5 - * @see #PLACEHOLDER_PREFIX - * @see #PLACEHOLDER_SUFFIX - * @see System#getProperty(String) - */ -public abstract class SystemPropertyUtils { - - /** Prefix for system property placeholders: "${" */ - public static final String PLACEHOLDER_PREFIX = "${"; - - /** Suffix for system property placeholders: "}" */ - public static final String PLACEHOLDER_SUFFIX = "}"; - - - /** - * Resolve ${...} placeholders in the given text, - * replacing them with corresponding system property values. - * @param text the String to resolve - * @return the resolved String - * @see #PLACEHOLDER_PREFIX - * @see #PLACEHOLDER_SUFFIX - */ - public static String resolvePlaceholders(String text) { - StringBuffer buf = new StringBuffer(text); - - int startIndex = buf.indexOf(PLACEHOLDER_PREFIX); - while (startIndex != -1) { - int endIndex = buf.indexOf(PLACEHOLDER_SUFFIX, startIndex + PLACEHOLDER_PREFIX.length()); - if (endIndex != -1) { - String placeholder = buf.substring(startIndex + PLACEHOLDER_PREFIX.length(), endIndex); - int nextIndex = endIndex + PLACEHOLDER_SUFFIX.length(); - try { - String propVal = System.getProperty(placeholder); - if (propVal == null) { - // Fall back to searching the system environment. - //propVal = System.getenv(placeholder);// mbaudier - 2009-07-26 - throw new Error("getenv no longer supported, use properties and -D instead: " + placeholder); - } - if (propVal != null) { - buf.replace(startIndex, endIndex + PLACEHOLDER_SUFFIX.length(), propVal); - nextIndex = startIndex + propVal.length(); - } - else { - System.err.println("Could not resolve placeholder '" + placeholder + "' in [" + text + - "] as system property: neither system property nor environment variable found"); - } - } - catch (Throwable ex) { - System.err.println("Could not resolve placeholder '" + placeholder + "' in [" + text + - "] as system property: " + ex); - } - startIndex = buf.indexOf(PLACEHOLDER_PREFIX, nextIndex); - } - else { - startIndex = -1; - } - } - - return buf.toString(); - } - -} diff --git a/osgi/runtime/org.argeo.osgi.boot/src/test/java/org/argeo/slc/osgiboot/OsgiBootNoRuntimeTest.java b/osgi/runtime/org.argeo.osgi.boot/src/test/java/org/argeo/slc/osgiboot/OsgiBootNoRuntimeTest.java index fd2678b29..77f74d346 100644 --- a/osgi/runtime/org.argeo.osgi.boot/src/test/java/org/argeo/slc/osgiboot/OsgiBootNoRuntimeTest.java +++ b/osgi/runtime/org.argeo.osgi.boot/src/test/java/org/argeo/slc/osgiboot/OsgiBootNoRuntimeTest.java @@ -21,7 +21,7 @@ import java.util.List; import junit.framework.TestCase; -import org.argeo.slc.osgiboot.OsgiBoot; +import org.argeo.osgi.boot.OsgiBoot; public class OsgiBootNoRuntimeTest extends TestCase { public final static String BUNDLES = "src/test/bundles/some;in=*;ex=excluded," diff --git a/osgi/runtime/org.argeo.osgi.boot/src/test/java/org/argeo/slc/osgiboot/OsgiBootRuntimeTest.java b/osgi/runtime/org.argeo.osgi.boot/src/test/java/org/argeo/slc/osgiboot/OsgiBootRuntimeTest.java index d7386cb91..b717c3ac4 100644 --- a/osgi/runtime/org.argeo.osgi.boot/src/test/java/org/argeo/slc/osgiboot/OsgiBootRuntimeTest.java +++ b/osgi/runtime/org.argeo.osgi.boot/src/test/java/org/argeo/slc/osgiboot/OsgiBootRuntimeTest.java @@ -22,6 +22,7 @@ import java.util.TreeMap; import junit.framework.TestCase; +import org.argeo.osgi.boot.OsgiBoot; import org.eclipse.core.runtime.adaptor.EclipseStarter; import org.osgi.framework.Bundle; import org.osgi.framework.BundleContext;