/******************************************************************************* * Copyright (c) 2003, 2015 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 * Sergey Prigogin (Google) - use parameterized types (bug 442021) *******************************************************************************/ package org.eclipse.core.internal.runtime; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.ArrayList; import java.util.Map; import org.eclipse.core.runtime.*; import org.osgi.framework.Bundle; // This class provides implements the find* methods exposed on Platform. // It does the lookup in bundles and fragments and does the variable replacement. // Can only be used if OSGi is available. public class FindSupport { // OSGI system properties public static final String PROP_NL = "osgi.nl"; //$NON-NLS-1$ public static final String PROP_OS = "osgi.os"; //$NON-NLS-1$ public static final String PROP_WS = "osgi.ws"; //$NON-NLS-1$ public static final String PROP_ARCH = "osgi.arch"; //$NON-NLS-1$ private static String[] NL_JAR_VARIANTS = buildNLVariants(Activator.getContext() == null ? System.getProperty(PROP_NL) : Activator.getContext().getProperty(PROP_NL)); private static String[] buildNLVariants(String nl) { ArrayList<String> result = new ArrayList<>(); IPath base = new Path("nl"); //$NON-NLS-1$ IPath path = new Path(nl.replace('_', '/')); while (path.segmentCount() > 0) { result.add(base.append(path).toString()); // for backwards compatibility only, don't replace the slashes if (path.segmentCount() > 1) result.add(base.append(path.toString().replace('/', '_')).toString()); path = path.removeLastSegments(1); } return result.toArray(new String[result.size()]); } /** * See doc on {@link FileLocator#find(Bundle, IPath, Map)} */ public static URL find(Bundle bundle, IPath path) { return find(bundle, path, null); } /** * See doc on {@link FileLocator#find(Bundle, IPath, Map)} */ public static URL find(Bundle b, IPath path, Map<String, String> override) { return find(b, path, override, null); } /** * See doc on {@link FileLocator#findEntries(Bundle, IPath)} */ public static URL[] findEntries(Bundle bundle, IPath path) { return findEntries(bundle, path, null); } /** * See doc on {@link FileLocator#findEntries(Bundle, IPath, Map)} */ public static URL[] findEntries(Bundle bundle, IPath path, Map<String, String> override) { ArrayList<URL> results = new ArrayList<>(1); find(bundle, path, override, results); return results.toArray(new URL[results.size()]); } private static URL find(Bundle b, IPath path, Map<String, String> override, ArrayList<URL> multiple) { if (path == null) return null; URL result = null; // Check for the empty or root case first if (path.isEmpty() || path.isRoot()) { // Watch for the root case. It will produce a new // URL which is only the root directory (and not the // root of this plugin). result = findInPlugin(b, Path.EMPTY, multiple); if (result == null || multiple != null) result = findInFragments(b, Path.EMPTY, multiple); return result; } // Now check for paths without variable substitution String first = path.segment(0); if (first.charAt(0) != '$') { result = findInPlugin(b, path, multiple); if (result == null || multiple != null) result = findInFragments(b, path, multiple); return result; } // Worry about variable substitution IPath rest = path.removeFirstSegments(1); if (first.equalsIgnoreCase("$nl$")) //$NON-NLS-1$ return findNL(b, rest, override, multiple); if (first.equalsIgnoreCase("$os$")) //$NON-NLS-1$ return findOS(b, rest, override, multiple); if (first.equalsIgnoreCase("$ws$")) //$NON-NLS-1$ return findWS(b, rest, override, multiple); if (first.equalsIgnoreCase("$files$")) //$NON-NLS-1$ return null; return null; } private static URL findOS(Bundle b, IPath path, Map<String, String> override, ArrayList<URL> multiple) { String os = null; if (override != null) try { // check for override os = override.get("$os$"); //$NON-NLS-1$ } catch (ClassCastException e) { // just in case } if (os == null) // use default os = Activator.getContext().getProperty(PROP_OS); if (os.length() == 0) return null; // Now do the same for osarch String osArch = null; if (override != null) try { // check for override osArch = override.get("$arch$"); //$NON-NLS-1$ } catch (ClassCastException e) { // just in case } if (osArch == null) // use default osArch = Activator.getContext().getProperty(PROP_ARCH); if (osArch.length() == 0) return null; URL result = null; IPath base = new Path("os").append(os).append(osArch); //$NON-NLS-1$ // Keep doing this until all you have left is "os" as a path while (base.segmentCount() != 1) { IPath filePath = base.append(path); result = findInPlugin(b, filePath, multiple); if (result != null && multiple == null) return result; result = findInFragments(b, filePath, multiple); if (result != null && multiple == null) return result; base = base.removeLastSegments(1); } // If we get to this point, we haven't found it yet. // Look in the plugin and fragment root directories result = findInPlugin(b, path, multiple); if (result != null && multiple == null) return result; return findInFragments(b, path, multiple); } private static URL findWS(Bundle b, IPath path, Map<String, String> override, ArrayList<URL> multiple) { String ws = null; if (override != null) try { // check for override ws = override.get("$ws$"); //$NON-NLS-1$ } catch (ClassCastException e) { // just in case } if (ws == null) // use default ws = Activator.getContext().getProperty(PROP_WS); IPath filePath = new Path("ws").append(ws).append(path); //$NON-NLS-1$ // We know that there is only one segment to the ws path // e.g. ws/win32 URL result = findInPlugin(b, filePath, multiple); if (result != null && multiple == null) return result; result = findInFragments(b, filePath, multiple); if (result != null && multiple == null) return result; // If we get to this point, we haven't found it yet. // Look in the plugin and fragment root directories result = findInPlugin(b, path, multiple); if (result != null && multiple == null) return result; return findInFragments(b, path, multiple); } private static URL findNL(Bundle b, IPath path, Map<String, String> override, ArrayList<URL> multiple) { String nl = null; String[] nlVariants = null; if (override != null) try { // check for override nl = override.get("$nl$"); //$NON-NLS-1$ } catch (ClassCastException e) { // just in case } nlVariants = nl == null ? NL_JAR_VARIANTS : buildNLVariants(nl); if (nl != null && nl.length() == 0) return null; URL result = null; for (int i = 0; i < nlVariants.length; i++) { IPath filePath = new Path(nlVariants[i]).append(path); result = findInPlugin(b, filePath, multiple); if (result != null && multiple == null) return result; result = findInFragments(b, filePath, multiple); if (result != null && multiple == null) return result; } // If we get to this point, we haven't found it yet. // Look in the plugin and fragment root directories result = findInPlugin(b, path, multiple); if (result != null && multiple == null) return result; return findInFragments(b, path, multiple); } private static URL findInPlugin(Bundle b, IPath filePath, ArrayList<URL> multiple) { URL result = b.getEntry(filePath.toString()); if (result != null && multiple != null) multiple.add(result); return result; } private static URL findInFragments(Bundle b, IPath filePath, ArrayList<URL> multiple) { Activator activator = Activator.getDefault(); if (activator == null) return null; Bundle[] fragments = activator.getFragments(b); if (fragments == null) return null; if (multiple != null) multiple.ensureCapacity(fragments.length + 1); for (int i = 0; i < fragments.length; i++) { URL fileURL = fragments[i].getEntry(filePath.toString()); if (fileURL != null) { if (multiple == null) return fileURL; multiple.add(fileURL); } } return null; } /** * See doc on {@link FileLocator#openStream(Bundle, IPath, boolean)} */ public static final InputStream openStream(Bundle bundle, IPath file, boolean substituteArgs) throws IOException { URL url = null; if (!substituteArgs) { url = findInPlugin(bundle, file, null); if (url == null) url = findInFragments(bundle, file, null); } else { url = FindSupport.find(bundle, file); } if (url != null) return url.openStream(); throw new IOException("Cannot find " + file.toString()); //$NON-NLS-1$ } /** * See doc on {@link FileLocator#find(URL)} */ public static URL find(URL url) { // if !platform/plugin | fragment URL return if (!"platform".equalsIgnoreCase(url.getProtocol())) //$NON-NLS-1$ return null; // call a helper method to get the bundle object and rest of the path String spec = url.getFile().trim(); Object[] obj = null; try { obj = PlatformURLPluginConnection.parse(spec, url); } catch (IOException e) { RuntimeLog.log(new Status(IStatus.ERROR, IRuntimeConstants.PI_RUNTIME, "Invalid input url:" + url, e)); //$NON-NLS-1$ return null; } Bundle bundle = (Bundle) obj[0]; String path = (String) obj[1]; // use FileLocator.find(bundle, path, null) to look for the file if ("/".equals(path)) //$NON-NLS-1$ return bundle.getEntry(path); return find(bundle, new Path(path), null); } }