| /******************************************************************************* |
| * Copyright (c) 2004, 2006 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.update.internal.configurator; |
| |
| import java.io.File; |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.util.Locale; |
| import java.util.MissingResourceException; |
| import java.util.ResourceBundle; |
| import java.util.StringTokenizer; |
| |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.FileLocator; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.MultiStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.osgi.framework.log.FrameworkLog; |
| import org.eclipse.osgi.framework.log.FrameworkLogEntry; |
| import org.eclipse.osgi.service.datalocation.Location; |
| import org.eclipse.osgi.service.resolver.PlatformAdmin; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.Filter; |
| import org.osgi.framework.InvalidSyntaxException; |
| import org.osgi.framework.ServiceReference; |
| import org.osgi.service.packageadmin.PackageAdmin; |
| import org.osgi.util.tracker.ServiceTracker; |
| |
| public class Utils { |
| private static final String PROP_ARCH = "osgi.arch"; //$NON-NLS-1$ |
| private static final String PROP_NL = "osgi.nl"; //$NON-NLS-1$ |
| private static final String PROP_OS = "osgi.os"; //$NON-NLS-1$ |
| private static final String PROP_WS = "osgi.ws"; //$NON-NLS-1$ |
| private static final String PI_OSGI = "org.eclipse.osgi"; //$NON-NLS-1$ |
| private static final String KEY_PREFIX = "%"; //$NON-NLS-1$ |
| private static final String KEY_DOUBLE_PREFIX = "%%"; //$NON-NLS-1$ |
| // os |
| public static boolean isWindows = System.getProperty("os.name").startsWith("Win"); //$NON-NLS-1$ //$NON-NLS-2$ |
| static FrameworkLog log; |
| private static ServiceTracker bundleTracker; |
| private static ServiceTracker instanceLocation; |
| private static ServiceTracker configurationLocation; |
| |
| public static void debug(String s) { |
| if (ConfigurationActivator.DEBUG) |
| System.out.println("PlatformConfig: " + s); //$NON-NLS-1$ |
| } |
| |
| /** |
| * Creates a CoreException from some other exception. |
| * The type of the CoreException is <code>IStatus.ERROR</code> |
| * If the exception passed as a parameter is also a CoreException, |
| * the new CoreException will contain all the status of the passed |
| * CoreException. |
| * |
| * @see IStatus#ERROR |
| * @param s exception string |
| * @param e actual exception being reported |
| * @return a CoreException |
| * @since 2.0 |
| */ |
| public static CoreException newCoreException(String s, Throwable e) { |
| |
| // check the case of a multistatus |
| IStatus status; |
| if (e instanceof CoreException) { |
| if (s == null) |
| s = ""; //$NON-NLS-1$ |
| status = new MultiStatus("org.eclipse.update.configurator", 0, s, e); //$NON-NLS-1$ |
| IStatus childrenStatus = ((CoreException) e).getStatus(); |
| ((MultiStatus) status).add(childrenStatus); |
| ((MultiStatus) status).addAll(childrenStatus); |
| } else { |
| StringBuffer completeString = new StringBuffer(""); //$NON-NLS-1$ |
| if (s != null) |
| completeString.append(s); |
| if (e != null) { |
| completeString.append(" ["); //$NON-NLS-1$ |
| String msg = e.getLocalizedMessage(); |
| completeString.append(msg!=null?msg:e.toString()); |
| completeString.append("]"); //$NON-NLS-1$ |
| } |
| status = newStatus(completeString.toString(), e); |
| } |
| return new CoreException(status); |
| } |
| |
| public static IStatus newStatus(String message, Throwable e) { |
| return new Status(IStatus.ERROR, "org.eclipse.update.configurator", IStatus.OK, message, e); //$NON-NLS-1$ |
| } |
| |
| public static void log(String message) { |
| log(newStatus(message, null)); |
| } |
| |
| public static void log(IStatus status) { |
| if (log != null) { |
| log.log(new FrameworkLogEntry(ConfigurationActivator.PI_CONFIGURATOR, status.getMessage(), 0, status.getException(), null)); |
| } else { |
| System.out.println(status.getMessage()); |
| if (status.getException() != null) |
| status.getException().printStackTrace(); |
| } |
| } |
| |
| /** |
| * Returns the url as a platform:/ url, if possible, else leaves it unchanged |
| * @param url |
| * @return |
| */ |
| public static URL asPlatformURL(URL url) { |
| try { |
| URL platformURL = new URL("platform:/base/"); //$NON-NLS-1$ // try using platform-relative URL |
| URL resolvedPlatformURL = FileLocator.toFileURL(platformURL); |
| // TODO workaround bug in platform url resolution |
| if (resolvedPlatformURL.getProtocol().equals("file")) //$NON-NLS-1$ |
| resolvedPlatformURL = new File(resolvedPlatformURL.getFile()).toURL(); |
| String platformURLAsString = resolvedPlatformURL.toExternalForm(); |
| String urlAsString = url.toExternalForm(); |
| if (urlAsString.startsWith(platformURLAsString)) |
| return new URL(platformURL.toExternalForm() + urlAsString.substring(platformURLAsString.length()) ); |
| return url; |
| } catch (Exception e) { |
| return url; |
| } |
| } |
| |
| /** |
| * Close the services that we were listening to. |
| */ |
| /*package*/ static synchronized void shutdown() { |
| if (bundleTracker != null) { |
| bundleTracker.close(); |
| bundleTracker = null; |
| } |
| if (instanceLocation != null) { |
| instanceLocation.close(); |
| instanceLocation = null; |
| } |
| if (configurationLocation != null) { |
| configurationLocation.close(); |
| configurationLocation = null; |
| } |
| } |
| |
| /** |
| * Return a boolean value indicating whether or not we consider the |
| * platform to be running. |
| */ |
| public static boolean isRunning() { |
| Bundle bundle = getBundle(PI_OSGI); |
| return bundle == null ? false : bundle.getState() == Bundle.ACTIVE; |
| } |
| |
| /** |
| * |
| */ |
| public static boolean isValidEnvironment(String os, String ws, String arch, String nl) { |
| if (os!=null && !isMatching(os, getOS())) return false; |
| if (ws!=null && !isMatching(ws, getWS())) return false; |
| if (arch!=null && !isMatching(arch, getArch())) return false; |
| if (nl!=null && !isMatchingLocale(nl, getNL())) return false; |
| return true; |
| } |
| |
| /** |
| * Return the current operating system value. |
| * |
| * @see EnvironmentInfo#getOS() |
| */ |
| public static String getOS() { |
| return getContext().getProperty(PROP_OS); |
| } |
| |
| /** |
| * Return the current windowing system value. |
| * |
| * @see EnvironmentInfo#getWS() |
| */ |
| public static String getWS() { |
| return getContext().getProperty(PROP_WS); |
| } |
| |
| /** |
| * Return the current system architecture value. |
| * |
| * @see EnvironmentInfo#getOSArch() |
| */ |
| public static String getArch() { |
| return getContext().getProperty(PROP_ARCH); |
| } |
| |
| /** |
| * Return the current NL value. |
| * |
| * @see EnvironmentInfo#getNL() |
| */ |
| public static String getNL() { |
| return getContext().getProperty(PROP_NL); |
| } |
| |
| /** |
| * Returns a number that changes whenever the set of installed plug-ins |
| * changes. This can be used for invalidating caches that are based on |
| * the set of currently installed plug-ins. (e.g. extensions) |
| * |
| * @see PlatformAdmin#getState() |
| * @see State#getTimeStamp() |
| */ |
| public static long getStateStamp() { |
| ServiceReference platformAdminReference = getContext().getServiceReference(PlatformAdmin.class.getName()); |
| if (platformAdminReference == null) |
| return -1; |
| PlatformAdmin admin = (PlatformAdmin) getContext().getService(platformAdminReference); |
| return admin == null ? -1 : admin.getState(false).getTimeStamp(); |
| } |
| |
| /** |
| * Return the resolved bundle with the specified symbolic name. |
| * |
| * @see PackageAdmin#getBundles(String, String) |
| */ |
| public static synchronized Bundle getBundle(String symbolicName) { |
| if (bundleTracker == null) { |
| bundleTracker = new ServiceTracker(getContext(), PackageAdmin.class.getName(), null); |
| bundleTracker.open(); |
| } |
| PackageAdmin admin = (PackageAdmin) bundleTracker.getService(); |
| if (admin == null) |
| return null; |
| Bundle[] bundles = admin.getBundles(symbolicName, null); |
| if (bundles == null) |
| return null; |
| //Return the first bundle that is not installed or uninstalled |
| for (int i = 0; i < bundles.length; i++) { |
| if ((bundles[i].getState() & (Bundle.INSTALLED | Bundle.UNINSTALLED)) == 0) { |
| return bundles[i]; |
| } |
| } |
| return null; |
| } |
| |
| /* |
| * Return the bundle context for this bundle. |
| */ |
| private static BundleContext getContext() { |
| return ConfigurationActivator.getBundleContext(); |
| } |
| |
| /** |
| * Return the configuration location. |
| * |
| * @see Location |
| */ |
| public static synchronized Location getConfigurationLocation() { |
| if (configurationLocation == null) { |
| Filter filter = null; |
| try { |
| filter = getContext().createFilter(Location.CONFIGURATION_FILTER); |
| } catch (InvalidSyntaxException e) { |
| // ignore this. It should never happen as we have tested the above format. |
| } |
| configurationLocation = new ServiceTracker(getContext(), filter, null); |
| configurationLocation.open(); |
| } |
| return (Location) configurationLocation.getService(); |
| } |
| |
| /** |
| * |
| */ |
| private static boolean isMatching(String candidateValues, String siteValues) { |
| if (siteValues==null) return false; |
| if ("*".equalsIgnoreCase(candidateValues)) return true; //$NON-NLS-1$ |
| siteValues = siteValues.toUpperCase(); |
| StringTokenizer stok = new StringTokenizer(candidateValues, ","); //$NON-NLS-1$ |
| while (stok.hasMoreTokens()) { |
| String token = stok.nextToken().toUpperCase(); |
| if (siteValues.indexOf(token)!=-1) return true; |
| } |
| return false; |
| } |
| |
| /** |
| * |
| */ |
| private static boolean isMatchingLocale(String candidateValues, String locale) { |
| if (locale==null) return false; |
| if ("*".equalsIgnoreCase(candidateValues)) return true; //$NON-NLS-1$ |
| |
| locale = locale.toUpperCase(); |
| candidateValues = candidateValues.toUpperCase(); |
| StringTokenizer stok = new StringTokenizer(candidateValues, ","); //$NON-NLS-1$ |
| while (stok.hasMoreTokens()) { |
| String candidate = stok.nextToken(); |
| if (locale.indexOf(candidate) == 0) |
| return true; |
| if (candidate.indexOf(locale) == 0) |
| return true; |
| } |
| return false; |
| } |
| |
| public static Locale getDefaultLocale() { |
| String nl = getNL(); |
| // sanity test |
| if (nl == null) |
| return Locale.getDefault(); |
| |
| // break the string into tokens to get the Locale object |
| StringTokenizer locales = new StringTokenizer(nl,"_"); //$NON-NLS-1$ |
| if (locales.countTokens() == 1) |
| return new Locale(locales.nextToken(), ""); //$NON-NLS-1$ |
| else if (locales.countTokens() == 2) |
| return new Locale(locales.nextToken(), locales.nextToken()); |
| else if (locales.countTokens() == 3) |
| return new Locale(locales.nextToken(), locales.nextToken(), locales.nextToken()); |
| else |
| return Locale.getDefault(); |
| } |
| |
| |
| /** |
| * Returns a resource string corresponding to the given argument |
| * value and bundle. |
| * If the argument value specifies a resource key, the string |
| * is looked up in the given resource bundle. If the argument does not |
| * specify a valid key, the argument itself is returned as the |
| * resource string. The key lookup is performed against the |
| * specified resource bundle. If a resource string |
| * corresponding to the key is not found in the resource bundle |
| * the key value, or any default text following the key in the |
| * argument value is returned as the resource string. |
| * A key is identified as a string begining with the "%" character. |
| * Note that the "%" character is stripped off prior to lookup |
| * in the resource bundle. |
| * <p> |
| * For example, assume resource bundle plugin.properties contains |
| * name = Project Name |
| * <pre> |
| * resolveNLString(b,"Hello World") returns "Hello World"</li> |
| * resolveNLString(b,"%name") returns "Project Name"</li> |
| * resolveNLString(b,"%name Hello World") returns "Project Name"</li> |
| * resolveNLString(b,"%abcd Hello World") returns "Hello World"</li> |
| * resolveNLString(b,"%abcd") returns "%abcd"</li> |
| * resolveNLString(b,"%%name") returns "%name"</li> |
| * </pre> |
| * </p> |
| * |
| * @param resourceBundle resource bundle. |
| * @param string translatable string from model |
| * @return string, or <code>null</code> |
| * @since 2.0 |
| */ |
| public static String getResourceString(ResourceBundle resourceBundle, String string) { |
| |
| if (string == null) |
| return null; |
| |
| String s = string.trim(); |
| |
| if (s.equals("")) //$NON-NLS-1$ |
| return string; |
| |
| if (!s.startsWith(KEY_PREFIX)) |
| return string; |
| |
| if (s.startsWith(KEY_DOUBLE_PREFIX)) |
| return s.substring(1); |
| |
| int ix = s.indexOf(" "); //$NON-NLS-1$ |
| String key = ix == -1 ? s : s.substring(0, ix); |
| String dflt = ix == -1 ? s : s.substring(ix + 1); |
| |
| if (resourceBundle == null) |
| return dflt; |
| |
| try { |
| return resourceBundle.getString(key.substring(1)); |
| } catch (MissingResourceException e) { |
| return dflt; |
| } |
| } |
| |
| public static boolean isAutomaticallyStartedBundle(String bundleURL) { |
| if (bundleURL.indexOf("org.eclipse.osgi") != -1) //$NON-NLS-1$ |
| return true; |
| |
| String osgiBundles = ConfigurationActivator.getBundleContext().getProperty("osgi.bundles"); //$NON-NLS-1$ |
| StringTokenizer st = new StringTokenizer(osgiBundles, ","); //$NON-NLS-1$ |
| while (st.hasMoreTokens()) { |
| String token = st.nextToken().trim(); |
| int index = token.indexOf('@'); |
| if (index != -1) |
| token = token.substring(0,index); |
| if (token.startsWith("reference:file:")) { //$NON-NLS-1$ |
| File f = new File(token.substring(15)); |
| if (bundleURL.indexOf(f.getName()) != -1) |
| return true; |
| } |
| if (bundleURL.indexOf(token) != -1) |
| return true; |
| } |
| return false; |
| } |
| |
| /** |
| * Returns an absolute URL by combining a base absolute URL and another URL relative to the first one. |
| * If the relative URL protocol does not match the base URL protocol, or if the relative URL path is not relative, |
| * return it as is. |
| */ |
| public static URL makeAbsolute(URL base, URL relativeLocation) { |
| if (!"file".equals(base.getProtocol())) //$NON-NLS-1$ |
| // we only deal with file: URLs |
| return relativeLocation; |
| if (relativeLocation.getProtocol() != null && !relativeLocation.getProtocol().equals(base.getProtocol())) |
| // it is not relative, return as is (avoid creating garbage) |
| return relativeLocation; |
| IPath relativePath = new Path(relativeLocation.getPath()); |
| if (relativePath.isAbsolute()) |
| return relativeLocation; |
| try { |
| IPath absolutePath = new Path(base.getPath()).append(relativeLocation.getPath()); |
| // File.toURL() is the best way to create a file: URL |
| return absolutePath.toFile().toURL(); |
| } catch (MalformedURLException e) { |
| // cannot happen since we are building from two existing valid URLs |
| Utils.log(e.getLocalizedMessage()); |
| return relativeLocation; |
| } |
| } |
| |
| /** |
| * Returns a URL which is equivalent to the given URL relative to the |
| * specified base URL. Works only for file: URLs |
| */ |
| public static URL makeRelative(URL base, URL location) { |
| if (base == null) |
| return location; |
| if (!"file".equals(base.getProtocol())) //$NON-NLS-1$ |
| return location; |
| if (!base.getProtocol().equals(location.getProtocol())) |
| return location; |
| IPath locationPath = new Path(location.getPath()); |
| if (!locationPath.isAbsolute()) |
| return location; |
| IPath relativePath = makeRelative(new Path(base.getPath()), locationPath); |
| try { |
| return new URL(base.getProtocol(), base.getHost(), base.getPort(), relativePath.toString()); |
| } catch (MalformedURLException e) { |
| String message = e.getMessage(); |
| if (message == null) |
| message = ""; //$NON-NLS-1$ |
| Utils.log(Utils.newStatus(message, e)); |
| } |
| return location; |
| } |
| |
| /** |
| * Returns a path which is equivalent to the given location relative to the |
| * specified base path. |
| */ |
| public static IPath makeRelative(IPath base, IPath location) { |
| if (location.getDevice() != null && !location.getDevice().equalsIgnoreCase(base.getDevice())) |
| return location; |
| int baseCount = base.segmentCount(); |
| int count = base.matchingFirstSegments(location); |
| String temp = ""; //$NON-NLS-1$ |
| for (int j = 0; j < baseCount - count; j++) |
| temp += "../"; //$NON-NLS-1$ |
| return new Path(temp).append(location.removeFirstSegments(count)); |
| } |
| |
| /** |
| * Returns a string URL which is equivalent to the given absolute location |
| * made relative to the specified base path. |
| */ |
| public static String makeRelative(URL base, String absolute) { |
| try { |
| return makeRelative(base, new URL(absolute)).toExternalForm(); |
| } catch (MalformedURLException e) { |
| // returns the original string if is invalid |
| return absolute; |
| } |
| } |
| |
| /** |
| * Ensures file: URLs on Windows have the right form (i.e. '/' as segment separator, drive letter in lower case, etc) |
| */ |
| public static String canonicalizeURL(String url) { |
| if (!(isWindows && url.startsWith("file:"))) //$NON-NLS-1$ |
| return url; |
| try { |
| String path = new URL(url).getPath(); |
| // normalize to not have leading / so we can check the form |
| File file = new File(path); |
| path = file.toString().replace('\\', '/'); |
| if (Character.isUpperCase(path.charAt(0))) { |
| char[] chars = path.toCharArray(); |
| chars[0] = Character.toLowerCase(chars[0]); |
| path = new String(chars); |
| return new File(path).toURL().toExternalForm(); |
| } |
| } catch (MalformedURLException e) { |
| // default to original url |
| } |
| return url; |
| } |
| |
| /** |
| * Return the install location. |
| * |
| * @see Location |
| */ |
| public static synchronized URL getInstallURL() { |
| if (instanceLocation == null) { |
| Filter filter = null; |
| try { |
| filter = getContext().createFilter(Location.INSTALL_FILTER); |
| } catch (InvalidSyntaxException e) { |
| // ignore this. It should never happen as we have tested the |
| // above format. |
| } |
| instanceLocation = new ServiceTracker(getContext(), filter, null); |
| instanceLocation.open(); |
| } |
| |
| Location location = (Location) instanceLocation.getService(); |
| |
| // it is pretty much impossible for the install location to be null. If it is, the |
| // system is in a bad way so throw and exception and get the heck outta here. |
| if (location == null) |
| throw new IllegalStateException("The installation location must not be null"); //$NON-NLS-1$ |
| |
| return location.getURL(); |
| } |
| |
| } |