| /********************************************************************** |
| * Copyright (c) 2000,2002 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Common Public License v0.5 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/cpl-v05.html |
| * |
| * Contributors: |
| * IBM - Initial API and implementation |
| **********************************************************************/ |
| package org.eclipse.core.internal.boot; |
| |
| import java.io.*; |
| import java.net.*; |
| import java.util.*; |
| import org.eclipse.core.boot.BootLoader; |
| import org.eclipse.core.boot.IPlatformConfiguration; |
| |
| public class PlatformConfiguration implements IPlatformConfiguration { |
| |
| private static PlatformConfiguration currentPlatformConfiguration = null; |
| |
| private URL configLocation; |
| private URL rootLocation; |
| private HashMap sites; |
| private HashMap externalLinkSites; // used to restore prior link site state |
| private HashMap cfgdFeatures; |
| private HashMap bootPlugins; |
| private String defaultFeature; |
| private long lastChangeStamp; |
| private long changeStamp; |
| private boolean changeStampIsValid = false; |
| private long lastFeaturesChangeStamp; |
| private long featuresChangeStamp; |
| private boolean featuresChangeStampIsValid = false; |
| private long lastPluginsChangeStamp; |
| private long pluginsChangeStamp; |
| private boolean pluginsChangeStampIsValid = false; |
| private boolean featureChangesConfigured = false; |
| private boolean transientConfig = false; |
| private File cfgLockFile; |
| private RandomAccessFile cfgLockFileRAF; |
| private BootDescriptor runtimeDescriptor; |
| private BootDescriptor xmlDescriptor; |
| |
| private static String cmdConfiguration = null; |
| private static String cmdFeature = null; |
| private static String cmdApplication = null; |
| private static URL cmdPlugins = null; |
| private static boolean cmdInitialize = false; |
| private static boolean cmdFirstUse = false; |
| private static boolean cmdUpdate = false; |
| private static boolean cmdNoUpdate = false; |
| private static boolean cmdDev = false; |
| |
| static boolean DEBUG = false; |
| |
| private static final String BOOT_XML = "boot.xml"; //$NON-NLS-1$ |
| private static final String BOOT_PLUGIN_ID = "org.eclipse.core.boot"; //$NON-NLS-1$ |
| private static final String RUNTIME_PLUGIN_ID = "org.eclipse.core.runtime"; //$NON-NLS-1$ |
| private static final String XML_PLUGIN_ID = "org.apache.xerces"; //$NON-NLS-1$ |
| |
| private static final String ECLIPSE = "eclipse"; //$NON-NLS-1$ |
| private static final String PLUGINS = "plugins"; //$NON-NLS-1$ |
| private static final String FEATURES = "features"; //$NON-NLS-1$ |
| private static final String CONFIG_DIR = ".config"; //$NON-NLS-1$ |
| private static final String CONFIG_FILE = CONFIG_DIR + "/platform.cfg"; //$NON-NLS-1$ |
| private static final String CONFIG_FILE_INIT = "install.ini"; //$NON-NLS-1$ |
| private static final String CONFIG_FILE_LOCK_SUFFIX = ".lock"; //$NON-NLS-1$ |
| private static final String CONFIG_FILE_TEMP_SUFFIX = ".tmp"; //$NON-NLS-1$ |
| private static final String CONFIG_FILE_BAK_SUFFIX = ".bak"; //$NON-NLS-1$ |
| private static final String CHANGES_MARKER = ".newupdates"; //$NON-NLS-1$ |
| private static final String LINKS = "links"; //$NON-NLS-1$ |
| private static final String PLUGIN_XML = "plugin.xml"; //$NON-NLS-1$ |
| private static final String FRAGMENT_XML = "fragment.xml"; //$NON-NLS-1$ |
| private static final String FEATURE_XML = "feature.xml"; //$NON-NLS-1$ |
| |
| private static final String[] BOOTSTRAP_PLUGINS = {"org.eclipse.core.boot"}; //$NON-NLS-1$ |
| private static final String CFG_BOOT_PLUGIN = "bootstrap"; //$NON-NLS-1$ |
| private static final String CFG_SITE = "site"; //$NON-NLS-1$ |
| private static final String CFG_URL = "url"; //$NON-NLS-1$ |
| private static final String CFG_POLICY = "policy"; //$NON-NLS-1$ |
| private static final String[] CFG_POLICY_TYPE = {"USER-INCLUDE", "USER-EXCLUDE"}; //$NON-NLS-1$ //$NON-NLS-2$ |
| private static final String CFG_POLICY_TYPE_UNKNOWN = "UNKNOWN"; //$NON-NLS-1$ |
| private static final String CFG_LIST = "list"; //$NON-NLS-1$ |
| private static final String CFG_STAMP = "stamp"; //$NON-NLS-1$ |
| private static final String CFG_FEATURE_STAMP = "stamp.features"; //$NON-NLS-1$ |
| private static final String CFG_PLUGIN_STAMP = "stamp.plugins"; //$NON-NLS-1$ |
| private static final String CFG_UPDATEABLE = "updateable"; //$NON-NLS-1$ |
| private static final String CFG_LINK_FILE = "linkfile"; //$NON-NLS-1$ |
| private static final String CFG_FEATURE_ENTRY = "feature"; //$NON-NLS-1$ |
| private static final String CFG_FEATURE_ENTRY_DEFAULT = "feature.default.id"; //$NON-NLS-1$ |
| private static final String CFG_FEATURE_ENTRY_ID = "id"; //$NON-NLS-1$ |
| private static final String CFG_FEATURE_ENTRY_PRIMARY = "primary"; //$NON-NLS-1$ |
| private static final String CFG_FEATURE_ENTRY_VERSION = "version"; //$NON-NLS-1$ |
| private static final String CFG_FEATURE_ENTRY_PLUGIN_VERSION = "plugin-version"; //$NON-NLS-1$ |
| private static final String CFG_FEATURE_ENTRY_APPLICATION = "application"; //$NON-NLS-1$ |
| private static final String CFG_FEATURE_ENTRY_ROOT = "root"; //$NON-NLS-1$ |
| |
| private static final String INIT_DEFAULT_FEATURE_ID = "feature.default.id"; //$NON-NLS-1$ |
| private static final String INIT_DEFAULT_FEATURE_APPLICATION = "feature.default.application"; //$NON-NLS-1$ |
| private static final String DEFAULT_FEATURE_ID = "org.eclipse.platform"; //$NON-NLS-1$ |
| private static final String DEFAULT_FEATURE_APPLICATION = "org.eclipse.ui.workbench"; //$NON-NLS-1$ |
| |
| private static final String CFG_VERSION = "version"; //$NON-NLS-1$ |
| private static final String CFG_TRANSIENT = "transient"; //$NON-NLS-1$ |
| private static final String VERSION = "2.1"; //$NON-NLS-1$ |
| private static final String EOF = "eof"; //$NON-NLS-1$ |
| private static final int CFG_LIST_LENGTH = 10; |
| |
| private static final int DEFAULT_POLICY_TYPE = ISitePolicy.USER_EXCLUDE; |
| private static final String[] DEFAULT_POLICY_LIST = new String[0]; |
| |
| private static final String LINK_PATH = "path"; //$NON-NLS-1$ |
| private static final String LINK_READ = "r"; //$NON-NLS-1$ |
| private static final String LINK_READ_WRITE = "rw"; //$NON-NLS-1$ |
| |
| private static final String CMD_CONFIGURATION = "-configuration"; //$NON-NLS-1$ |
| private static final String CMD_FEATURE = "-feature"; //$NON-NLS-1$ |
| private static final String CMD_APPLICATION = "-application"; //$NON-NLS-1$ |
| private static final String CMD_PLUGINS = "-plugins"; //$NON-NLS-1$ |
| private static final String CMD_UPDATE = "-update"; //$NON-NLS-1$ |
| private static final String CMD_INITIALIZE = "-initialize"; //$NON-NLS-1$ |
| private static final String CMD_FIRSTUSE = "-firstuse"; //$NON-NLS-1$ |
| private static final String CMD_NO_UPDATE = "-noupdate"; //$NON-NLS-1$ |
| private static final String CMD_NEW_UPDATES = "-newUpdates"; //$NON-NLS-1$ |
| private static final String CMD_DEV = "-dev"; // triggers -noupdate //$NON-NLS-1$ |
| |
| private static final String RECONCILER_APP = "org.eclipse.update.core.reconciler"; //$NON-NLS-1$ |
| |
| private static final char[] HEX = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; |
| |
| public class SiteEntry implements IPlatformConfiguration.ISiteEntry { |
| |
| private URL url; // this is the external URL for the site |
| private URL resolvedURL; // this is the resolved URL used internally |
| private ISitePolicy policy; |
| private boolean updateable = true; |
| private ArrayList features; |
| private ArrayList plugins; |
| private PlatformConfiguration parent; |
| private long lastChangeStamp; |
| private long changeStamp; |
| private boolean changeStampIsValid = false; |
| private long lastFeaturesChangeStamp; |
| private long featuresChangeStamp; |
| private boolean featuresChangeStampIsValid = false; |
| private long lastPluginsChangeStamp; |
| private long pluginsChangeStamp; |
| private boolean pluginsChangeStampIsValid = false; |
| private String linkFileName = null; |
| |
| private SiteEntry() { |
| } |
| private SiteEntry(URL url, ISitePolicy policy, PlatformConfiguration parent) { |
| if (url==null) |
| throw new IllegalArgumentException(); |
| |
| if (policy==null) |
| throw new IllegalArgumentException(); |
| |
| if (parent==null) |
| throw new IllegalArgumentException(); |
| |
| this.url = url; |
| this.policy = policy; |
| this.parent = parent; |
| this.features = null; |
| this.plugins = null; |
| this.resolvedURL = this.url; |
| if (url.getProtocol().equals(PlatformURLHandler.PROTOCOL)) { |
| try { |
| resolvedURL = resolvePlatformURL(url); // 19536 |
| } catch(IOException e) { |
| // will use the baseline URL ... |
| } |
| } |
| } |
| |
| /* |
| * @see ISiteEntry#getURL() |
| */ |
| public URL getURL() { |
| return url; |
| } |
| |
| /* |
| * @see ISiteEntry#getSitePolicy() |
| */ |
| public ISitePolicy getSitePolicy() { |
| return policy; |
| } |
| |
| /* |
| * @see ISiteEntry#setSitePolicy(ISitePolicy) |
| */ |
| public synchronized void setSitePolicy(ISitePolicy policy) { |
| if (policy==null) |
| throw new IllegalArgumentException(); |
| this.policy = policy; |
| } |
| |
| /* |
| * @see ISiteEntry#getFeatures() |
| */ |
| public String[] getFeatures() { |
| return getDetectedFeatures(); |
| } |
| |
| /* |
| * @see ISiteEntry#getPlugins() |
| */ |
| public String[] getPlugins() { |
| |
| ISitePolicy policy = getSitePolicy(); |
| |
| if (policy.getType()==ISitePolicy.USER_INCLUDE) |
| return policy.getList(); |
| |
| if (policy.getType()==ISitePolicy.USER_EXCLUDE) { |
| ArrayList detectedPlugins = new ArrayList(Arrays.asList(getDetectedPlugins())); |
| String[] excludedPlugins = policy.getList(); |
| for (int i=0; i<excludedPlugins.length; i++) { |
| if (detectedPlugins.contains(excludedPlugins[i])) |
| detectedPlugins.remove(excludedPlugins[i]); |
| } |
| return (String[])detectedPlugins.toArray(new String[0]); |
| } |
| |
| // bad policy type |
| return new String[0]; |
| } |
| |
| /* |
| * @see ISiteEntry#getChangeStamp() |
| */ |
| public long getChangeStamp() { |
| if (!changeStampIsValid) |
| computeChangeStamp(); |
| return changeStamp; |
| } |
| |
| /* |
| * @see ISiteEntry#getFeaturesChangeStamp() |
| */ |
| public long getFeaturesChangeStamp() { |
| if (!featuresChangeStampIsValid) |
| computeFeaturesChangeStamp(); |
| return featuresChangeStamp; |
| } |
| |
| /* |
| * @see ISiteEntry#getPluginsChangeStamp() |
| */ |
| public long getPluginsChangeStamp() { |
| if (!pluginsChangeStampIsValid) |
| computePluginsChangeStamp(); |
| return pluginsChangeStamp; |
| } |
| |
| /* |
| * @see ISiteEntry#isUpdateable() |
| */ |
| public boolean isUpdateable() { |
| return updateable; |
| } |
| |
| /* |
| * @see ISiteEntry#isNativelyLinked() |
| */ |
| public boolean isNativelyLinked() { |
| return isExternallyLinkedSite(); |
| } |
| |
| private String[] detectFeatures() { |
| |
| // invalidate stamps ... we are doing discovery |
| changeStampIsValid = false; |
| featuresChangeStampIsValid = false; |
| parent.changeStampIsValid = false; |
| parent.featuresChangeStampIsValid = false; |
| |
| features = new ArrayList(); |
| |
| if (!supportsDetection(resolvedURL)) |
| return new String[0]; |
| |
| // locate feature entries on site |
| File siteRoot = new File(resolvedURL.getFile().replace('/', File.separatorChar)); |
| File root = new File(siteRoot, FEATURES); |
| |
| String[] list = root.list(); |
| String path; |
| File plugin; |
| for (int i = 0; list != null && i < list.length; i++) { |
| path = list[i] + File.separator + FEATURE_XML; |
| plugin = new File(root, path); |
| if (!plugin.exists()) { |
| continue; |
| } |
| features.add(FEATURES + "/" + path.replace(File.separatorChar, '/')); //$NON-NLS-1$ |
| } |
| if (DEBUG) { |
| debug(resolvedURL.toString()+" located "+features.size()+" feature(s)"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| return (String[])features.toArray(new String[0]); |
| } |
| |
| private String[] detectPlugins() { |
| |
| // invalidate stamps ... we are doing discovery |
| changeStampIsValid = false; |
| pluginsChangeStampIsValid = false; |
| parent.changeStampIsValid = false; |
| parent.pluginsChangeStampIsValid = false; |
| |
| plugins = new ArrayList(); |
| |
| if (!supportsDetection(resolvedURL)) |
| return new String[0]; |
| |
| // locate plugin entries on site |
| File root = |
| new File(resolvedURL.getFile().replace('/', File.separatorChar) + PLUGINS); |
| String[] list = root.list(); |
| String path; |
| File plugin; |
| for (int i = 0; list != null && i < list.length; i++) { |
| path = list[i] + File.separator + PLUGIN_XML; |
| plugin = new File(root, path); |
| if (!plugin.exists()) { |
| path = list[i] + File.separator + FRAGMENT_XML; |
| plugin = new File(root, path); |
| if (!plugin.exists()) |
| continue; |
| } |
| plugins.add(PLUGINS + "/" + path.replace(File.separatorChar, '/')); //$NON-NLS-1$ |
| } |
| if (DEBUG) { |
| debug(resolvedURL.toString()+" located "+plugins.size()+" plugin(s)"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| |
| return (String[])plugins.toArray(new String[0]); |
| } |
| |
| private synchronized String[] getDetectedFeatures() { |
| if (features == null) |
| return detectFeatures(); |
| else |
| return (String[])features.toArray(new String[0]); |
| } |
| |
| private synchronized String[] getDetectedPlugins() { |
| if (plugins == null) |
| return detectPlugins(); |
| else |
| return (String[])plugins.toArray(new String[0]); |
| } |
| |
| private URL getResolvedURL() { |
| return resolvedURL; |
| } |
| |
| private void computeChangeStamp() { |
| computeFeaturesChangeStamp(); |
| computePluginsChangeStamp(); |
| changeStamp = resolvedURL.hashCode() ^ featuresChangeStamp ^ pluginsChangeStamp; |
| changeStampIsValid = true; |
| } |
| |
| private synchronized void computeFeaturesChangeStamp() { |
| if (featuresChangeStampIsValid) |
| return; |
| |
| long start = 0; |
| if (DEBUG) |
| start = (new Date()).getTime(); |
| String[] features = getFeatures(); |
| featuresChangeStamp = computeStamp(features); |
| featuresChangeStampIsValid = true; |
| if (DEBUG) { |
| long end = (new Date()).getTime(); |
| debug(resolvedURL.toString()+" feature stamp: "+featuresChangeStamp+((featuresChangeStamp==lastFeaturesChangeStamp)?" [no changes]":" [was "+lastFeaturesChangeStamp+"]") + " in "+(end-start)+"ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ |
| } |
| } |
| |
| private synchronized void computePluginsChangeStamp() { |
| if (pluginsChangeStampIsValid) |
| return; |
| |
| long start = 0; |
| if (DEBUG) |
| start = (new Date()).getTime(); |
| String[] plugins = getPlugins(); |
| pluginsChangeStamp = computeStamp(plugins); |
| pluginsChangeStampIsValid = true; |
| if (DEBUG) { |
| long end = (new Date()).getTime(); |
| debug(resolvedURL.toString()+" plugin stamp: "+pluginsChangeStamp+((pluginsChangeStamp==lastPluginsChangeStamp)?" [no changes]":" [was "+lastPluginsChangeStamp+"]") + " in "+(end-start)+"ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ |
| } |
| } |
| |
| private long computeStamp(String[] targets) { |
| |
| long result = 0; |
| if (!supportsDetection(resolvedURL)) { |
| // NOTE: this path should not be executed until we support running |
| // from an arbitrary URL (in particular from http server). For |
| // now just compute stamp across the list of names. Eventually |
| // when general URLs are supported we need to do better (factor |
| // in at least the existence of the target). However, given this |
| // code executes early on the startup sequence we need to be |
| // extremely mindful of performance issues. |
| for (int i=0; i<targets.length; i++) |
| result ^= targets[i].hashCode(); |
| if (DEBUG) |
| debug("*WARNING* computing stamp using URL hashcodes only"); //$NON-NLS-1$ |
| } else { |
| // compute stamp across local targets |
| String rootPath = resolvedURL.getFile().replace('/',File.separatorChar); |
| if (!rootPath.endsWith(File.separator)) |
| rootPath += File.separator; |
| File rootFile = new File(rootPath); |
| if (rootFile.exists()) { |
| File f = null; |
| for (int i=0; i<targets.length; i++) { |
| f = new File(rootFile,targets[i]); |
| if (f.exists()) |
| result ^= f.getAbsolutePath().hashCode() ^ f.lastModified() ^ f.length(); |
| } |
| } |
| } |
| |
| return result; |
| } |
| |
| private boolean isExternallyLinkedSite() { |
| return (linkFileName!=null && !linkFileName.trim().equals("")); //$NON-NLS-1$ |
| } |
| |
| private synchronized void refresh() { |
| // reset computed values. Will be updated on next access. |
| lastChangeStamp = changeStamp; |
| lastFeaturesChangeStamp = featuresChangeStamp; |
| lastPluginsChangeStamp = pluginsChangeStamp; |
| changeStampIsValid = false; |
| featuresChangeStampIsValid = false; |
| pluginsChangeStampIsValid = false; |
| features = null; |
| plugins = null; |
| } |
| |
| } |
| |
| public class SitePolicy implements IPlatformConfiguration.ISitePolicy { |
| |
| private int type; |
| private String[] list; |
| |
| private SitePolicy() { |
| } |
| private SitePolicy(int type, String[] list) { |
| if (type != ISitePolicy.USER_INCLUDE |
| && type != ISitePolicy.USER_EXCLUDE) |
| throw new IllegalArgumentException(); |
| this.type = type; |
| |
| if (list == null) |
| this.list = new String[0]; |
| else |
| this.list = list; |
| } |
| |
| /* |
| * @see ISitePolicy#getType() |
| */ |
| public int getType() { |
| return type; |
| } |
| |
| /* |
| * @see ISitePolicy#getList() |
| */ |
| public String[] getList() { |
| return list; |
| } |
| |
| /* |
| * @see ISitePolicy#setList(String[]) |
| */ |
| public synchronized void setList(String[] list) { |
| if (list == null) |
| this.list = new String[0]; |
| else |
| this.list = list; |
| } |
| |
| } |
| |
| private class FeatureEntry implements IPlatformConfiguration.IFeatureEntry { |
| private String id; |
| private String version; |
| private String pluginVersion; |
| private String application; |
| private URL[] root; |
| private boolean primary; |
| |
| private FeatureEntry(String id, String version, String pluginVersion, boolean primary, String application, URL[] root) { |
| if (id == null) |
| throw new IllegalArgumentException(); |
| this.id = id; |
| this.version = version; |
| this.pluginVersion = pluginVersion; |
| this.primary = primary; |
| this.application = application; |
| this.root = (root==null ? new URL[0] : root); |
| } |
| |
| /* |
| * @see IFeatureEntry#getFeatureIdentifier() |
| */ |
| public String getFeatureIdentifier() { |
| return id; |
| } |
| |
| /* |
| * @see IFeatureEntry#getFeatureVersion() |
| */ |
| public String getFeatureVersion() { |
| return version; |
| } |
| |
| /* |
| * @see IFeatureEntry#getFeaturePluginVersion() |
| */ |
| public String getFeaturePluginVersion() { |
| return pluginVersion; |
| } |
| |
| /* |
| * @see IFeatureEntry#getFeatureApplication() |
| */ |
| public String getFeatureApplication() { |
| return application; |
| } |
| |
| /* |
| * @see IFeatureEntry#getFeatureRootURLs() |
| */ |
| public URL[] getFeatureRootURLs() { |
| return root; |
| } |
| |
| /* |
| * @see IFeatureEntry#canBePrimary() |
| */ |
| public boolean canBePrimary() { |
| return primary; |
| } |
| } |
| |
| private class VersionedIdentifier { |
| private String identifier = ""; //$NON-NLS-1$ |
| private int major = 0; |
| private int minor = 0; |
| private int service = 0; |
| private String qualifier = ""; //$NON-NLS-1$ |
| |
| private static final String VER_SEPARATOR = "."; //$NON-NLS-1$ |
| private static final String ID_SEPARATOR = "_"; //$NON-NLS-1$ |
| |
| public static final int LESS_THAN = -1; |
| public static final int EQUAL = 0; |
| public static final int EQUIVALENT = 1; |
| public static final int COMPATIBLE = 2; |
| public static final int GREATER_THAN = 3; |
| |
| public VersionedIdentifier(String s) { |
| if (s==null || (s=s.trim()).equals("")) //$NON-NLS-1$ |
| return; |
| |
| int loc = s.lastIndexOf(ID_SEPARATOR); |
| if (loc != -1) { |
| this.identifier = s.substring(0, loc); |
| String version = s.substring(loc+1); |
| parseVersion(version); |
| } else |
| this.identifier = s; |
| } |
| |
| public boolean equalIdentifiers(VersionedIdentifier id) { |
| if (id == null) |
| return identifier == null; |
| else |
| return id.identifier.equals(identifier); |
| } |
| |
| public int compareVersion(VersionedIdentifier id) { |
| |
| if (id == null) { |
| if (major==0 && minor==0 && service==0) return -1; |
| else return 1; |
| } |
| |
| if (major > id.major) return GREATER_THAN; |
| if (major < id.major) return LESS_THAN; |
| if (minor > id.minor) return COMPATIBLE; |
| if (minor < id.minor) return LESS_THAN; |
| if (service > id.service) return EQUIVALENT; |
| if (service < id.service) return LESS_THAN; |
| return compareQualifiers(qualifier, id.qualifier); |
| } |
| |
| private int compareQualifiers(String q1, String q2) { |
| int result = q1.compareTo(q2); |
| if (result<0) |
| return LESS_THAN; |
| else if (result>0) |
| return EQUIVALENT; |
| else |
| return EQUAL; |
| } |
| |
| private void parseVersion(String v) { |
| if( v == null || (v=v.trim()).equals("")) //$NON-NLS-1$ |
| return; |
| |
| try{ |
| StringTokenizer st = new StringTokenizer(v, VER_SEPARATOR); |
| ArrayList elements = new ArrayList(4); |
| |
| while(st.hasMoreTokens()) { |
| elements.add(st.nextToken()); |
| } |
| |
| if (elements.size()>=1) this.major = (new Integer((String)elements.get(0))).intValue(); |
| if (elements.size()>=2) this.minor = (new Integer((String)elements.get(1))).intValue(); |
| if (elements.size()>=3) this.service = (new Integer((String)elements.get(2))).intValue(); |
| if (elements.size()>=4) this.qualifier = removeWhiteSpace((String)elements.get(3)); |
| |
| } catch (Exception e) { |
| // use what we got so far ... |
| } |
| } |
| |
| private String removeWhiteSpace(String s) { |
| char[] chars = s.trim().toCharArray(); |
| boolean whitespace = false; |
| for(int i=0; i<chars.length; i++) { |
| if (Character.isWhitespace(chars[i])) { |
| chars[i] = '_'; |
| whitespace = true; |
| } |
| } |
| return whitespace ? new String(chars) : s; |
| } |
| } |
| |
| /* |
| * Element selector for use with "tiny" parser. Parser callers supply |
| * concrete selectors |
| */ |
| public interface Selector { |
| |
| /* |
| * Method is called to pre-select a specific xml type. Pre-selected |
| * elements are then fully parsed and result in calls to full |
| * select method. |
| * @return <code>true</code> is the element should be considered, |
| * <code>false</code> otherwise |
| */ |
| public boolean select(String entry); |
| |
| /* |
| * Method is called with a fully parsed element. |
| * @return <code>true</code> to select this element and terminate the parse, |
| * <code>false</code> otherwise |
| */ |
| public boolean select(String element, HashMap attributes); |
| } |
| |
| /* |
| * "Tiny" xml parser. Performs a rudimentary parse of a well-formed xml file. |
| * Is specifically geared to parsing plugin.xml files of "bootstrap" plug-ins |
| * during the platform startup sequence before full xml plugin is available. |
| */ |
| public static class Parser { |
| |
| private ArrayList elements = new ArrayList(); |
| |
| /* |
| * Construct parser for the specified file |
| */ |
| public Parser(File file) { |
| try { |
| load(new FileInputStream(file)); |
| } catch (Exception e) { |
| // continue ... actual parsing will report errors |
| } |
| } |
| |
| /* |
| * Construct parser for the specified URL |
| */ |
| public Parser(URL url) { |
| try { |
| load(url.openStream()); |
| } catch (Exception e) { |
| // continue ... actual parsing will report errors |
| } |
| } |
| |
| /* |
| * Return selected elements as an (attribute-name, attribute-value) map. |
| * The name of the selected element is returned as the value of entry with |
| * name "<element>". |
| * @return attribute map for selected element, or <code>null</code> |
| */ |
| public HashMap getElement(Selector selector) { |
| if (selector == null) |
| return null; |
| |
| String element; |
| for (int i=0; i<elements.size(); i++) { |
| // make pre-parse selector call |
| element = (String)elements.get(i); |
| if (selector.select(element)) { |
| // parse selected entry |
| HashMap attributes = new HashMap(); |
| String elementName; |
| int j; |
| // parse out element name |
| for (j = 0; j<element.length(); j++) { |
| if (Character.isWhitespace(element.charAt(j))) |
| break; |
| } |
| if (j>=element.length()) { |
| elementName = element; |
| } else { |
| elementName = element.substring(0,j); |
| element = element.substring(j); |
| // parse out attributes |
| StringTokenizer t = new StringTokenizer(element,"=\""); //$NON-NLS-1$ |
| boolean isKey = true; |
| String key = ""; //$NON-NLS-1$ |
| while(t.hasMoreTokens()) { |
| String token = t.nextToken().trim(); |
| if (!token.equals("")) { //$NON-NLS-1$ |
| // collect (key, value) pairs |
| if (isKey) { |
| key = token; |
| isKey = false; |
| } else { |
| attributes.put(key, token); |
| isKey = true; |
| } |
| } |
| } |
| } |
| // make post-parse selector call |
| if (selector.select(elementName, attributes)) { |
| attributes.put("<element>", elementName); //$NON-NLS-1$ |
| return attributes; |
| } |
| } |
| } |
| return null; |
| } |
| |
| private void load(InputStream is) { |
| if (is == null) |
| return; |
| |
| // read file |
| StringBuffer xml = new StringBuffer(4096); |
| char[] iobuf = new char[4096]; |
| InputStreamReader r = null; |
| try { |
| r = new InputStreamReader(is); |
| int len = r.read(iobuf, 0, iobuf.length); |
| while (len != -1) { |
| xml.append(iobuf, 0, len); |
| len = r.read(iobuf, 0, iobuf.length); |
| } |
| } catch (Exception e) { |
| return; |
| } finally { |
| if (r != null) try { |
| r.close(); |
| } catch (IOException e) { |
| // ignore |
| } |
| } |
| |
| // parse out element tokens |
| String xmlString = xml.toString(); |
| StringTokenizer t = new StringTokenizer(xmlString,"<>"); //$NON-NLS-1$ |
| while(t.hasMoreTokens()) { |
| String token = t.nextToken().trim(); |
| if (!token.equals("")) //$NON-NLS-1$ |
| elements.add(token); |
| } |
| } |
| } |
| |
| public static class BootDescriptor { |
| private String id; |
| private String version; |
| private String[] libs; |
| private URL dir; |
| |
| public BootDescriptor(String id, String version, String[] libs, URL dir) { |
| this.id = id; |
| this.version = version; |
| this.libs = libs; |
| this.dir = dir; |
| } |
| |
| public String getId() { |
| return id; |
| } |
| |
| public String getVersion() { |
| return version; |
| } |
| |
| public String[] getLibraries() { |
| return libs; |
| } |
| |
| public URL getPluginDirectoryURL() { |
| return dir; |
| } |
| } |
| |
| private PlatformConfiguration(String configArg, String metaPath, URL pluginPath) throws IOException { |
| this.sites = new HashMap(); |
| this.externalLinkSites = new HashMap(); |
| this.cfgdFeatures = new HashMap(); |
| this.bootPlugins = new HashMap(); |
| |
| // Determine configuration URL to use (based on command line argument) |
| URL configURL = null; |
| if (configArg != null && !configArg.trim().equals("")) { //$NON-NLS-1$ |
| configURL = new URL(configArg); |
| } |
| |
| // initialize configuration |
| boolean createRootSite = (pluginPath == null); |
| initializeCurrent(configURL, metaPath, createRootSite); |
| |
| // merge in any plugin-path entries (converted to site(s)) |
| if (pluginPath != null) { |
| updateConfigurationFromPlugins(pluginPath); |
| } |
| |
| // pick up any first-time default settings (relative to install location) |
| loadInitializationAttributes(); |
| |
| // Detect external links. These are "soft link" to additional sites. The link |
| // files are usually provided by external installation programs. They are located |
| // relative to this configuration URL. |
| configureExternalLinks(); |
| |
| // Validate sites in the configuration. Causes any sites that do not exist to |
| // be removed from the configuration |
| validateSites(); |
| |
| // compute differences between configuration and actual content of the sites |
| // (base sites and link sites) |
| computeChangeStamp(); |
| |
| // determine which plugins we will use to start the rest of the "kernel" |
| // (need to get core.runtime matching the executing core.boot and |
| // xerces matching the selected core.runtime) |
| locateDefaultPlugins(); |
| } |
| |
| PlatformConfiguration(URL url) throws IOException { |
| this.sites = new HashMap(); |
| this.externalLinkSites = new HashMap(); |
| this.cfgdFeatures = new HashMap(); |
| this.bootPlugins = new HashMap(); |
| initialize(url); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#createSiteEntry(URL, ISitePolicy) |
| */ |
| public ISiteEntry createSiteEntry(URL url, ISitePolicy policy) { |
| return new PlatformConfiguration.SiteEntry(url, policy, this); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#createSitePolicy(int, String[]) |
| */ |
| public ISitePolicy createSitePolicy(int type, String[] list) { |
| return new PlatformConfiguration.SitePolicy(type, list); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#createFeatureEntry(String, String, String, boolean, String, URL) |
| */ |
| public IFeatureEntry createFeatureEntry( |
| String id, |
| String version, |
| String pluginVersion, |
| boolean primary, |
| String application, |
| URL[] root) { |
| return new PlatformConfiguration.FeatureEntry(id, version, pluginVersion, primary, application, root); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#configureSite(ISiteEntry) |
| */ |
| public void configureSite(ISiteEntry entry) { |
| configureSite(entry, false); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#configureSite(ISiteEntry, boolean) |
| */ |
| public synchronized void configureSite(ISiteEntry entry, boolean replace) { |
| |
| if (entry == null) |
| return; |
| |
| URL url = entry.getURL(); |
| if (url == null) |
| return; |
| String key = url.toExternalForm(); |
| |
| if (sites.containsKey(key) && !replace) |
| return; |
| |
| sites.put(key, entry); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#unconfigureSite(ISiteEntry) |
| */ |
| public synchronized void unconfigureSite(ISiteEntry entry) { |
| if (entry == null) |
| return; |
| |
| URL url = entry.getURL(); |
| if (url == null) |
| return; |
| String key = url.toExternalForm(); |
| |
| sites.remove(key); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#getConfiguredSites() |
| */ |
| public ISiteEntry[] getConfiguredSites() { |
| if (sites.size() == 0) |
| return new ISiteEntry[0]; |
| |
| return (ISiteEntry[]) sites.values().toArray(new ISiteEntry[0]); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#findConfiguredSite(URL) |
| */ |
| public ISiteEntry findConfiguredSite(URL url) { |
| if (url == null) |
| return null; |
| String key = url.toExternalForm(); |
| |
| ISiteEntry result = (ISiteEntry) sites.get(key); |
| if (result == null) // retry with decoded URL string |
| result = (ISiteEntry) sites.get(URLDecoder.decode(key)); |
| return result; |
| } |
| |
| /* |
| * @see IPlatformConfiguration#configureFeatureEntry(IFeatureEntry) |
| */ |
| public synchronized void configureFeatureEntry(IFeatureEntry entry) { |
| if (entry == null) |
| return; |
| |
| String key = entry.getFeatureIdentifier(); |
| if (key == null) |
| return; |
| |
| cfgdFeatures.put(key, entry); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#unconfigureFeatureEntry(IFeatureEntry) |
| */ |
| public synchronized void unconfigureFeatureEntry(IFeatureEntry entry) { |
| if (entry == null) |
| return; |
| |
| String key = entry.getFeatureIdentifier(); |
| if (key == null) |
| return; |
| |
| cfgdFeatures.remove(key); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#getConfiguredFeatureEntries() |
| */ |
| public IFeatureEntry[] getConfiguredFeatureEntries() { |
| if (cfgdFeatures.size() == 0) |
| return new IFeatureEntry[0]; |
| |
| return (IFeatureEntry[]) cfgdFeatures.values().toArray(new IFeatureEntry[0]); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#findConfiguredFeatureEntry(String) |
| */ |
| public IFeatureEntry findConfiguredFeatureEntry(String id) { |
| if (id == null) |
| return null; |
| |
| return (IFeatureEntry) cfgdFeatures.get(id); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#getConfigurationLocation() |
| */ |
| public URL getConfigurationLocation() { |
| return configLocation; |
| } |
| |
| /* |
| * @see IPlatformConfiguration#getChangeStamp() |
| */ |
| public long getChangeStamp() { |
| if (!changeStampIsValid) |
| computeChangeStamp(); |
| return changeStamp; |
| } |
| |
| /* |
| * @see IPlatformConfiguration#getFeaturesChangeStamp() |
| */ |
| public long getFeaturesChangeStamp() { |
| if (!featuresChangeStampIsValid) |
| computeFeaturesChangeStamp(); |
| return featuresChangeStamp; |
| } |
| |
| /* |
| * @see IPlatformConfiguration#getPluginsChangeStamp() |
| */ |
| public long getPluginsChangeStamp() { |
| if (!pluginsChangeStampIsValid) |
| computePluginsChangeStamp(); |
| return pluginsChangeStamp; |
| } |
| |
| /* |
| * @see IPlatformConfiguration#getApplicationIdentifier() |
| */ |
| public String getApplicationIdentifier() { |
| |
| if (cmdInitialize) { |
| // we are running post-install initialization. Force |
| // running of the reconciler |
| return RECONCILER_APP; |
| } |
| |
| if (featuresChangeStamp != lastFeaturesChangeStamp) { |
| // we have detected feature changes ... see if we need to reconcile |
| boolean update = !cmdNoUpdate || cmdUpdate; |
| if (update) |
| return RECONCILER_APP; |
| } |
| |
| // "normal" startup ... run specified application |
| return getApplicationIdentifierInternal(); |
| } |
| |
| private String getApplicationIdentifierInternal() { |
| |
| if (cmdApplication != null) // application was specified |
| return cmdApplication; |
| else { |
| // if -feature was not specified use the default feature |
| String feature = cmdFeature; |
| if (feature == null) |
| feature = defaultFeature; |
| |
| // lookup application for feature (specified or defaulted) |
| if (feature != null) { |
| IFeatureEntry fe = findConfiguredFeatureEntry(feature); |
| if (fe != null) { |
| if (fe.getFeatureApplication() != null) |
| return fe.getFeatureApplication(); |
| } |
| } |
| } |
| |
| // return hardcoded default if we failed |
| return DEFAULT_FEATURE_APPLICATION; |
| } |
| |
| /* |
| * @see IPlatformConfiguration#getPrimaryFeatureIdentifier() |
| */ |
| public String getPrimaryFeatureIdentifier() { |
| |
| if (cmdFeature != null) // -feature was specified on command line |
| return cmdFeature; |
| |
| // feature was not specified on command line |
| if (defaultFeature != null) |
| return defaultFeature; // return customized default if set |
| else |
| return DEFAULT_FEATURE_ID; // return hardcoded default |
| } |
| |
| /* |
| * @see IPlatformConfiguration#getPluginPath() |
| */ |
| public URL[] getPluginPath() { |
| ArrayList path = new ArrayList(); |
| if (DEBUG) |
| debug("computed plug-in path:"); //$NON-NLS-1$ |
| |
| ISiteEntry[] sites = getConfiguredSites(); |
| URL pathURL; |
| for (int i=0; i<sites.length; i++) { |
| String[] plugins = sites[i].getPlugins(); |
| for (int j=0; j<plugins.length; j++) { |
| try { |
| pathURL = new URL(((SiteEntry)sites[i]).getResolvedURL(),plugins[j]); |
| path.add(pathURL); |
| if (DEBUG) |
| debug(" "+pathURL.toString()); //$NON-NLS-1$ |
| } catch(MalformedURLException e) { |
| // skip entry ... |
| if (DEBUG) |
| debug(" bad URL: "+e); //$NON-NLS-1$ |
| } |
| } |
| } |
| return (URL[])path.toArray(new URL[0]); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#getBootstrapPluginIdentifiers() |
| */ |
| public String[] getBootstrapPluginIdentifiers() { |
| return BOOTSTRAP_PLUGINS; |
| } |
| |
| /* |
| * @see IPlatformConfiguration#setBootstrapPluginLocation(String, URL) |
| */ |
| public void setBootstrapPluginLocation(String id, URL location) { |
| String[] ids = getBootstrapPluginIdentifiers(); |
| for (int i=0; i<ids.length; i++) { |
| if (ids[i].equals(id)) { |
| bootPlugins.put(id, location.toExternalForm()); |
| break; |
| } |
| } |
| } |
| |
| /* |
| * @see IPlatformConfiguration#isUpdateable() |
| */ |
| public boolean isUpdateable() { |
| return true; |
| } |
| |
| /* |
| * @see IPlatformConfiguration#isTransient() |
| */ |
| public boolean isTransient() { |
| return transientConfig; |
| } |
| |
| /* |
| * @see IPlatformConfiguration#isTransient(boolean) |
| */ |
| public void isTransient(boolean value) { |
| if (this != BootLoader.getCurrentPlatformConfiguration()) |
| transientConfig = value; |
| } |
| |
| /* |
| * @see IPlatformConfiguration#refresh() |
| */ |
| public synchronized void refresh() { |
| // Reset computed values. Will be lazily refreshed |
| // on next access |
| ISiteEntry[] sites = getConfiguredSites(); |
| for (int i = 0; i < sites.length; i++) { |
| // reset site entry |
| ((SiteEntry)sites[i]).refresh(); |
| } |
| // reset configuration entry. |
| lastChangeStamp = changeStamp; |
| lastFeaturesChangeStamp = featuresChangeStamp; |
| lastPluginsChangeStamp = pluginsChangeStamp; |
| changeStampIsValid = false; |
| featuresChangeStampIsValid = false; |
| pluginsChangeStampIsValid = false; |
| } |
| |
| /* |
| * @see IPlatformConfiguration#save() |
| */ |
| public void save() throws IOException { |
| if (isUpdateable()) |
| save(configLocation); |
| } |
| |
| /* |
| * @see IPlatformConfiguration#save(URL) |
| */ |
| public synchronized void save(URL url) throws IOException { |
| if (url == null) |
| throw new IOException(Policy.bind("cfig.unableToSave.noURL")); //$NON-NLS-1$ |
| |
| PrintWriter w = null; |
| OutputStream os = null; |
| if (!url.getProtocol().equals("file")) { //$NON-NLS-1$ |
| // not a file protocol - attempt to save to the URL |
| URLConnection uc = url.openConnection(); |
| uc.setDoOutput(true); |
| os = uc.getOutputStream(); |
| w = new PrintWriter(os); |
| try { |
| write(w); |
| } finally { |
| w.close(); |
| } |
| } else { |
| // file protocol - do safe i/o |
| File cfigFile = new File(url.getFile().replace('/',File.separatorChar)); |
| File cfigDir = cfigFile.getParentFile(); |
| if (cfigDir!=null) |
| cfigDir.mkdirs(); |
| |
| // first save the file as temp |
| File cfigTmp = new File(cfigFile.getAbsolutePath()+CONFIG_FILE_TEMP_SUFFIX); |
| os = new FileOutputStream(cfigTmp); |
| w = new PrintWriter(os); |
| try { |
| write(w); |
| } finally { |
| w.close(); |
| } |
| |
| // make sure we actually succeeded saving the whole configuration. |
| InputStream is = new FileInputStream(cfigTmp); |
| Properties tmpProps = new Properties(); |
| try { |
| tmpProps.load(is); |
| if (!EOF.equals(tmpProps.getProperty(EOF))) { |
| throw new IOException(Policy.bind("cfig.unableToSave",cfigTmp.getAbsolutePath())); //$NON-NLS-1$ |
| } |
| } finally { |
| is.close(); |
| } |
| |
| // make the saved config the "active" one |
| File cfigBak = new File(cfigFile.getAbsolutePath()+CONFIG_FILE_BAK_SUFFIX); |
| cfigBak.delete(); // may have old .bak due to prior failure |
| |
| if (cfigFile.exists()) |
| cfigFile.renameTo(cfigBak); |
| |
| // at this point we have old config (if existed) as "bak" and the |
| // new config as "tmp". |
| boolean ok = cfigTmp.renameTo(cfigFile); |
| if (ok) { |
| // at this point we have the new config "activated", and the old |
| // config (if it existed) as "bak" |
| cfigBak.delete(); // clean up |
| } else { |
| // this codepath represents a tiny failure window. The load processing |
| // on startup will detect missing config and will attempt to start |
| // with "tmp" (latest), then "bak" (the previous). We can also end up |
| // here if we failed to rename the current config to "bak". In that |
| // case we will restart with the previous state. |
| throw new IOException(Policy.bind("cfig.unableToSave",cfigTmp.getAbsolutePath())); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| public BootDescriptor getPluginBootDescriptor(String id) { |
| // return the plugin descriptor for the specified plugin. This method |
| // is used during boot processing to obtain information about "kernel" plugins |
| // whose class loaders must be created prior to the plugin registry being |
| // available (ie. loaders needed to create the plugin registry). |
| |
| if (RUNTIME_PLUGIN_ID.equals(id)) |
| return runtimeDescriptor; |
| else if (XML_PLUGIN_ID.equals(id)) |
| return xmlDescriptor; |
| else |
| return null; |
| } |
| |
| |
| static PlatformConfiguration getCurrent() { |
| return currentPlatformConfiguration; |
| } |
| |
| /** |
| * Create and initialize the current platform configuration |
| * @param cmdArgs command line arguments (startup and boot arguments are |
| * already consumed) |
| * @param r10plugins plugin-path URL as passed on the BootLoader.run(...) |
| * or BootLoader.startup(...) method. Supported for R1.0 compatibility |
| * @param r10apps application identifies as passed on the BootLoader.run(...) |
| * method. Supported for R1.0 compatibility. |
| * @param metaPath path to the platform metadata area |
| */ |
| static synchronized String[] startup(String[] cmdArgs, URL r10plugins, String r10app, String metaPath) throws Exception { |
| |
| // if BootLoader was invoked directly (rather than via Main), it is possible |
| // to have the plugin-path and application set in 2 ways: (1) via an explicit |
| // argument on the invocation method, or (2) via a command line argument (passed |
| // into this method as the argument String[]). If specified, the explicit |
| // values are used even if the command line arguments were specified as well. |
| cmdPlugins = r10plugins; // R1.0 compatibility |
| cmdApplication = r10app; // R1.0 compatibility |
| |
| // process command line arguments |
| String[] passthruArgs = processCommandLine(cmdArgs); |
| if (cmdDev) |
| cmdNoUpdate = true; // force -noupdate when in dev mode (eg. PDE) |
| |
| // create current configuration |
| if (currentPlatformConfiguration == null) |
| currentPlatformConfiguration = new PlatformConfiguration(cmdConfiguration, metaPath, cmdPlugins); |
| |
| // check if we will be forcing reconciliation |
| passthruArgs = checkForFeatureChanges(passthruArgs, currentPlatformConfiguration); |
| |
| // check if we should indicate new changes |
| passthruArgs = checkForNewUpdates(currentPlatformConfiguration, passthruArgs); |
| |
| return passthruArgs; |
| } |
| |
| static synchronized void shutdown() throws IOException { |
| |
| // save platform configuration |
| PlatformConfiguration config = getCurrent(); |
| if (config != null) { |
| try { |
| config.save(); |
| } catch(IOException e) { |
| if (DEBUG) |
| debug("Unable to save configuration "+e.toString()); //$NON-NLS-1$ |
| // will recover on next startup |
| } |
| config.clearConfigurationLock(); |
| } |
| } |
| |
| private synchronized void initializeCurrent(URL url, String metaPath, boolean createRootSite) throws IOException { |
| |
| boolean concurrentUse = false; |
| |
| if (cmdInitialize) { |
| // we are running post-install initialization (-install command |
| // line argument). Ignore any configuration URL passed in. |
| // Force the configuration to be saved in the install location. |
| // Allow an existing configuration to be re-initialized. |
| url = new URL(BootLoader.getInstallURL(),CONFIG_FILE); // if we fail here, return exception |
| concurrentUse = getConfigurationLock(url); |
| resetInitializationConfiguration(url); // [20111] |
| if (createRootSite) |
| configureSite(getRootSite()); |
| if (DEBUG) |
| debug("Initializing configuration " + url.toString()); //$NON-NLS-1$ |
| configLocation = url; |
| verifyPath(configLocation); |
| return; |
| } |
| |
| if (url != null) { |
| // configuration URL was specified. Use it (if exists), or create one |
| // in specified location |
| |
| // check concurrent use lock |
| concurrentUse = getConfigurationLock(url); |
| |
| // try loading the configuration |
| try { |
| load(url); |
| if (DEBUG) |
| debug("Using configuration " + url.toString()); //$NON-NLS-1$ |
| } catch(IOException e) { |
| cmdFirstUse = true; |
| if (createRootSite) |
| configureSite(getRootSite()); |
| if (DEBUG) |
| debug("Creating configuration " + url.toString()); //$NON-NLS-1$ |
| } |
| configLocation = url; |
| verifyPath(configLocation); |
| return; |
| |
| } else { |
| // configuration URL was not specified. Default behavior is to look |
| // for configuration in the workspace meta area. If not found, look |
| // for pre-initialized configuration in the installation location. |
| // If it is found it is used as the initial configuration. Otherwise |
| // a new configuration is created. In either case the resulting |
| // configuration is written into the platform .metadata area |
| |
| // first determine configuration location in .metadata |
| metaPath = metaPath.replace(File.separatorChar, '/'); |
| if (!metaPath.endsWith("/")) //$NON-NLS-1$ |
| metaPath += "/"; //$NON-NLS-1$ |
| URL cfigURL = new URL("file",null,0,metaPath+CONFIG_FILE); // if we fail here, return exception //$NON-NLS-1$ |
| |
| // check concurrent use lock |
| concurrentUse = getConfigurationLock(cfigURL); |
| |
| // if we can load it, use it |
| try { |
| load(cfigURL); |
| configLocation = cfigURL; |
| verifyPath(configLocation); |
| if (DEBUG) |
| debug("Using configuration " + configLocation.toString()); //$NON-NLS-1$ |
| return; |
| } catch(IOException e) { |
| cmdFirstUse = true; // we are creating new configuration |
| } |
| |
| // failed to load, see if we can find pre-initialized configuration. |
| // Don't attempt this initialization when self-hosting (is unpredictable) |
| if (createRootSite) { |
| try { |
| url = new URL(BootLoader.getInstallURL(),CONFIG_FILE); |
| load(url); |
| // pre-initialized config loaded OK ... copy any remaining update metadata |
| copyInitializedState(BootLoader.getInstallURL(), metaPath, CONFIG_DIR); |
| configLocation = cfigURL; // config in .metadata is the right URL |
| verifyPath(configLocation); |
| if (DEBUG) { |
| debug("Using configuration " + configLocation.toString()); //$NON-NLS-1$ |
| debug("Initialized from " + url.toString()); //$NON-NLS-1$ |
| } |
| return; |
| } catch(IOException e) { |
| // continue ... |
| } |
| } |
| |
| // if load failed, initialize with default site info |
| if (createRootSite) |
| configureSite(getRootSite()); |
| configLocation = cfigURL; |
| verifyPath(configLocation); |
| if (DEBUG) |
| debug("Creating configuration " + configLocation.toString()); //$NON-NLS-1$ |
| return; |
| } |
| } |
| |
| private synchronized void initialize(URL url) throws IOException { |
| if (url == null) { |
| if (DEBUG) |
| debug("Creating empty configuration object"); //$NON-NLS-1$ |
| return; |
| } |
| |
| load(url); |
| configLocation = url; |
| if (DEBUG) |
| debug("Using configuration " + configLocation.toString()); //$NON-NLS-1$ |
| } |
| |
| private ISiteEntry getRootSite() { |
| // create default site entry for the root |
| ISitePolicy defaultPolicy = createSitePolicy(DEFAULT_POLICY_TYPE, DEFAULT_POLICY_LIST); |
| URL siteURL = null; |
| try { |
| siteURL = new URL(PlatformURLBaseConnection.PLATFORM_URL_STRING); // try using platform-relative URL |
| } catch (MalformedURLException e) { |
| siteURL = BootLoader.getInstallURL(); // ensure we come up ... use absolute file URL |
| } |
| ISiteEntry defaultSite = createSiteEntry(siteURL, defaultPolicy); |
| return defaultSite; |
| } |
| |
| private void resetInitializationConfiguration(URL url) throws IOException { |
| // [20111] |
| if (!supportsDetection(url)) |
| return; // can't do ... |
| |
| URL resolved = resolvePlatformURL(url); |
| File initCfg = new File(resolved.getFile().replace('/',File.separatorChar)); |
| File initDir = initCfg.getParentFile(); |
| resetInitializationLocation(initDir); |
| } |
| |
| private void resetUpdateManagerState(URL url) throws IOException { |
| // [20111] |
| if (!supportsDetection(url)) |
| return; // can't do ... |
| |
| // find directory where the platform configuration file is |
| URL resolved = resolvePlatformURL(url); |
| File initCfg = new File(resolved.getFile().replace('/',File.separatorChar)); |
| File initDir = initCfg.getParentFile(); |
| |
| // Find the Update Manager State directory |
| if (initDir == null || !initDir.exists() || !initDir.isDirectory()) |
| return; |
| String temp = initCfg.getName()+".metadata"; |
| File UMDir = new File(initDir,temp+'/'); |
| |
| // Attempt to rename it |
| if (UMDir == null || !UMDir.exists() || !UMDir.isDirectory()) |
| return; |
| Date now = new Date(); |
| boolean renamed = UMDir.renameTo(new File(initDir,temp+now.getTime()+'/')); |
| |
| if (!renamed) |
| resetInitializationLocation(UMDir); |
| } |
| |
| private void resetInitializationLocation(File dir) { |
| // [20111] |
| if (dir == null || !dir.exists() || !dir.isDirectory()) |
| return; |
| File[] list = dir.listFiles(); |
| for (int i=0; i<list.length; i++) { |
| if (list[i].isDirectory()) |
| resetInitializationLocation(list[i]); |
| list[i].delete(); |
| } |
| } |
| |
| private boolean getConfigurationLock(URL url) { |
| if (configurationInWorkspace(url)) |
| return false; |
| |
| if (!url.getProtocol().equals("file")) //$NON-NLS-1$ |
| return false; |
| |
| verifyPath(url); |
| String cfgName = url.getFile().replace('/',File.separatorChar); |
| String lockName = cfgName + CONFIG_FILE_LOCK_SUFFIX; |
| cfgLockFile = new File(lockName); |
| |
| //if the lock file already exists, try to delete, |
| //assume failure means another eclipse has it open |
| if (cfgLockFile.exists()) |
| cfgLockFile.delete(); |
| if (cfgLockFile.exists()) { |
| throw new RuntimeException(Policy.bind("cfig.inUse", cfgName, lockName)); //$NON-NLS-1$ |
| } |
| |
| // OK so far ... open the lock file so other instances will fail |
| try { |
| cfgLockFileRAF = new RandomAccessFile(cfgLockFile, "rw"); //$NON-NLS-1$ |
| cfgLockFileRAF.writeByte(0); |
| } catch (IOException e) { |
| throw new RuntimeException(Policy.bind("cfig.failCreateLock", cfgName)); //$NON-NLS-1$ |
| } |
| |
| return false; |
| } |
| |
| private void clearConfigurationLock() { |
| try { |
| if (cfgLockFileRAF != null) { |
| cfgLockFileRAF.close(); |
| cfgLockFileRAF = null; |
| } |
| } catch (IOException e) { |
| // ignore ... |
| } |
| if (cfgLockFile != null) { |
| cfgLockFile.delete(); |
| cfgLockFile = null; |
| } |
| } |
| |
| private boolean configurationInWorkspace(URL url) { |
| // the configuration file is now in the workspace, so return true |
| return true; |
| } |
| |
| private void computeChangeStamp() { |
| computeFeaturesChangeStamp(); |
| computePluginsChangeStamp(); |
| changeStamp = featuresChangeStamp ^ pluginsChangeStamp; |
| changeStampIsValid = true; |
| } |
| |
| private void computeFeaturesChangeStamp() { |
| if (featuresChangeStampIsValid) |
| return; |
| |
| long result = 0; |
| ISiteEntry[] sites = getConfiguredSites(); |
| for (int i=0; i<sites.length; i++) { |
| result ^= sites[i].getFeaturesChangeStamp(); |
| } |
| featuresChangeStamp = result; |
| featuresChangeStampIsValid = true; |
| } |
| |
| private void computePluginsChangeStamp() { |
| if (pluginsChangeStampIsValid) |
| return; |
| |
| long result = 0; |
| ISiteEntry[] sites = getConfiguredSites(); |
| for (int i=0; i<sites.length; i++) { |
| result ^= sites[i].getPluginsChangeStamp(); |
| } |
| pluginsChangeStamp = result; |
| pluginsChangeStampIsValid = true; |
| } |
| |
| private void configureExternalLinks() { |
| URL linkURL = BootLoader.getInstallURL(); |
| if (!supportsDetection(linkURL)) |
| return; |
| |
| try { |
| linkURL = new URL(linkURL, LINKS + "/"); //$NON-NLS-1$ |
| } catch (MalformedURLException e) { |
| // skip bad links ... |
| if (DEBUG) |
| debug("Unable to obtain link URL"); //$NON-NLS-1$ |
| return; |
| } |
| |
| File linkDir = new File(linkURL.getFile()); |
| File[] links = linkDir.listFiles(); |
| if (links==null || links.length==0) { |
| if (DEBUG) |
| debug("No links detected in "+linkURL.toExternalForm()); //$NON-NLS-1$ |
| return; |
| } |
| |
| for (int i=0; i<links.length; i++) { |
| if (links[i].isDirectory()) |
| continue; |
| if (DEBUG) |
| debug("Link file "+links[i].getAbsolutePath()); //$NON-NLS-1$ |
| Properties props = new Properties(); |
| FileInputStream is = null; |
| try { |
| is = new FileInputStream(links[i]); |
| props.load(is); |
| configureExternalLinkSites(links[i],props); |
| } catch(IOException e) { |
| // skip bad links ... |
| if (DEBUG) |
| debug(" unable to load link file "+e); //$NON-NLS-1$ |
| continue; |
| } finally { |
| if (is != null) { |
| try { |
| is.close(); |
| } catch(IOException e) { |
| // ignore ... |
| } |
| } |
| } |
| } |
| } |
| |
| private void configureExternalLinkSites(File linkFile, Properties props) { |
| String path = props.getProperty(LINK_PATH); |
| if (path==null) { |
| if (DEBUG) |
| debug(" no path definition"); //$NON-NLS-1$ |
| return; |
| } |
| |
| String link; |
| boolean updateable = true; |
| URL siteURL; |
| SiteEntry linkSite; |
| ISitePolicy linkSitePolicy = createSitePolicy(DEFAULT_POLICY_TYPE, DEFAULT_POLICY_LIST); |
| |
| // parse out link information |
| if (path.startsWith(LINK_READ+" ")) { //$NON-NLS-1$ |
| updateable = false; |
| link = path.substring(2).trim(); |
| } else if (path.startsWith(LINK_READ_WRITE+" ")) { //$NON-NLS-1$ |
| link = path.substring(3).trim(); |
| } else { |
| link = path; |
| } |
| |
| // make sure we have a valid link specification |
| try { |
| if (!link.endsWith(File.separator)) |
| link += File.separator; |
| File target = new File(link + ECLIPSE); |
| link = "file:" + target.getAbsolutePath().replace(File.separatorChar,'/'); //$NON-NLS-1$ |
| if (!link.endsWith("/")) //$NON-NLS-1$ |
| link += "/"; // sites must be directories //$NON-NLS-1$ |
| siteURL = new URL(link); |
| } catch(MalformedURLException e) { |
| // ignore bad links ... |
| if (DEBUG) |
| debug(" bad URL "+e); //$NON-NLS-1$ |
| return; |
| } |
| |
| // process the link |
| linkSite = (SiteEntry) externalLinkSites.get(siteURL); |
| if (linkSite != null) { |
| // we already have a site for this link target, update it if needed |
| linkSite.updateable = updateable; |
| linkSite.linkFileName = linkFile.getAbsolutePath(); |
| } else { |
| // this is a link to a new target so create site for it |
| linkSite = (SiteEntry) createSiteEntry(siteURL, linkSitePolicy); |
| linkSite.updateable = updateable; |
| linkSite.linkFileName = linkFile.getAbsolutePath(); |
| } |
| |
| // configure the new site |
| // NOTE: duplicates are not replaced (first one in wins) |
| configureSite(linkSite); |
| if (DEBUG) |
| debug(" "+(updateable?"R/W -> ":"R/O -> ")+siteURL.toString()); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| } |
| |
| /* |
| * compute site(s) from plugin-path and merge into specified configuration |
| */ |
| private void updateConfigurationFromPlugins(URL file) throws IOException { |
| |
| // get the actual plugin path |
| URL[] pluginPath = BootLoader.getPluginPath(file); |
| if (pluginPath == null || pluginPath.length == 0) |
| return; |
| |
| // create a temp configuration and populate it based on plugin path |
| PlatformConfiguration tempConfig = new PlatformConfiguration((URL)null); |
| for (int i=0; i<pluginPath.length; i++) { |
| String entry = pluginPath[i].toExternalForm(); |
| String sitePortion; |
| String pluginPortion; |
| int ix; |
| if (entry.endsWith("/")) { //$NON-NLS-1$ |
| // assume directory path in the form <site>/plugins/ |
| // look for -------------------------------^ |
| ix = findEntrySeparator(entry,2); // second from end |
| sitePortion = entry.substring(0,ix+1); |
| pluginPortion = entry.substring(ix+1); |
| if (!pluginPortion.equals("plugins/")) //$NON-NLS-1$ |
| continue; // unsupported entry ... skip it ("fragments/" are handled) |
| pluginPortion = null; |
| } else { |
| // assume full path in the form <site>/<pluginsDir>/<some.plugin>/plugin.xml |
| // look for --------------------------^ |
| ix = findEntrySeparator(entry, 3); // third from end |
| sitePortion = entry.substring(0,ix+1); |
| pluginPortion = entry.substring(ix+1); |
| } |
| if (ix == -1) |
| continue; // bad entry ... skip it |
| |
| URL siteURL = null; |
| try { |
| siteURL = new URL(sitePortion); |
| if (siteURL.getProtocol().equals("file")) { //$NON-NLS-1$ |
| File sf = new File(siteURL.getFile()); |
| String sfn = sf.getAbsolutePath().replace(File.separatorChar,'/'); |
| if (!sfn.endsWith("/")) //$NON-NLS-1$ |
| sfn += "/"; //$NON-NLS-1$ |
| siteURL = new URL("file:"+sfn); //$NON-NLS-1$ |
| } |
| } catch (MalformedURLException e) { |
| continue; // bad entry ... skip it |
| } |
| |
| // configure existing site or create a new one for the entry |
| ISiteEntry site = tempConfig.findConfiguredSite(siteURL); |
| ISitePolicy policy; |
| if (site == null) { |
| // new site |
| if (pluginPortion == null) |
| policy = tempConfig.createSitePolicy(ISitePolicy.USER_EXCLUDE, null); |
| else |
| policy = tempConfig.createSitePolicy(ISitePolicy.USER_INCLUDE, new String[] { pluginPortion }); |
| site = tempConfig.createSiteEntry(siteURL,policy); |
| tempConfig.configureSite(site); |
| } else { |
| // existing site |
| policy = site.getSitePolicy(); |
| if (policy.getType() == ISitePolicy.USER_EXCLUDE) |
| continue; // redundant entry ... skip it |
| if (pluginPortion == null) { |
| // directory entry ... change policy to exclusion (with empty list) |
| policy = tempConfig.createSitePolicy(ISitePolicy.USER_EXCLUDE, null); |
| } else { |
| // explicit entry ... add it to the inclusion list |
| ArrayList list = new ArrayList(Arrays.asList(policy.getList())); |
| list.add(pluginPortion); |
| policy = tempConfig.createSitePolicy(ISitePolicy.USER_INCLUDE,(String[])list.toArray(new String[0])); |
| } |
| site.setSitePolicy(policy); |
| } |
| } |
| |
| // merge resulting site(s) into the specified configuration |
| ISiteEntry[] tempSites = tempConfig.getConfiguredSites(); |
| for (int i=0; i<tempSites.length; i++) { |
| configureSite(tempSites[i], true /*replace*/); |
| } |
| } |
| |
| private void validateSites() { |
| |
| // check to see if all sites are valid. Remove any sites that do not exist. |
| SiteEntry[] list = (SiteEntry[]) sites.values().toArray(new SiteEntry[0]); |
| for (int i = 0; i < list.length; i++) { |
| URL siteURL = list[i].getResolvedURL(); |
| if (!supportsDetection(siteURL)) |
| continue; |
| |
| File siteRoot = new File(siteURL.getFile().replace('/', File.separatorChar)); |
| if (!siteRoot.exists()) { |
| unconfigureSite(list[i]); |
| if (DEBUG) |
| debug("Site " + siteURL + " does not exist ... removing from configuration"); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| } |
| |
| private void copyInitializedState(URL source, String target, String dir) { |
| try { |
| if (!source.getProtocol().equals("file")) //$NON-NLS-1$ |
| return; // need to be able to do "dir" |
| |
| copy(new File(source.getFile()), new File(target), dir); |
| |
| } catch(IOException e) { |
| // this is an optimistic copy. If we fail, the state will be reconciled |
| // when the update manager is triggered. |
| } |
| } |
| |
| private void copy(File srcDir, File tgtDir, String extraPath) throws IOException { |
| File src = new File(srcDir, extraPath); |
| File tgt = new File(tgtDir, extraPath); |
| |
| if (src.isDirectory()) { |
| // copy content of directories |
| tgt.mkdir(); |
| String[] list = src.list(); |
| if (list==null) |
| return; |
| for (int i=0; i<list.length; i++) { |
| copy(srcDir, tgtDir, extraPath + File.separator + list[i]); |
| } |
| } else { |
| // copy individual files |
| FileInputStream is = null; |
| FileOutputStream os = null; |
| try { |
| is = new FileInputStream(src); |
| os = new FileOutputStream(tgt); |
| byte[] buff = new byte[1024]; |
| int count = is.read(buff); |
| while (count != -1) { |
| os.write(buff, 0, count); |
| count = is.read(buff); |
| } |
| } catch(IOException e) { |
| // continue ... update reconciler will have to reconstruct state |
| } finally { |
| if (is != null) try { is.close(); } catch(IOException e) { |
| // ignore ... |
| } |
| if (os != null) try { os.close(); } catch(IOException e) { |
| // ignore ... |
| } |
| } |
| } |
| } |
| |
| private void load(URL url) throws IOException { |
| |
| if (url == null) |
| throw new IOException(Policy.bind("cfig.unableToLoad.noURL")); //$NON-NLS-1$ |
| |
| // try to load saved configuration file (watch for failed prior save()) |
| Properties props = null; |
| IOException originalException = null; |
| try { |
| props = loadProperties(url, null); // try to load config file |
| } catch(IOException e1) { |
| originalException = e1; |
| try { |
| props = loadProperties(url, CONFIG_FILE_TEMP_SUFFIX); // check for failures on save |
| } catch(IOException e2) { |
| try { |
| props = loadProperties(url, CONFIG_FILE_BAK_SUFFIX); // check for failures on save |
| } catch(IOException e3) { |
| throw originalException; // we tried, but no config here ... |
| } |
| } |
| } |
| |
| // check version |
| String v = props.getProperty(CFG_VERSION); |
| if (!VERSION.equals(v)) { |
| // the state is invalid, delete any files under the directory |
| // bug 33493 |
| resetUpdateManagerState(url); |
| throw new IOException(Policy.bind("cfig.badVersion",v)); //$NON-NLS-1$ |
| } |
| |
| // load simple properties |
| defaultFeature = loadAttribute(props, CFG_FEATURE_ENTRY_DEFAULT, null); |
| |
| String flag = loadAttribute(props, CFG_TRANSIENT, null); |
| if (flag != null) { |
| if (flag.equals("true")) //$NON-NLS-1$ |
| transientConfig = true; |
| else |
| transientConfig = false; |
| } |
| |
| String stamp = loadAttribute(props, CFG_STAMP, null); |
| if (stamp != null) { |
| try { |
| lastChangeStamp = Long.parseLong(stamp); |
| } catch(NumberFormatException e) { |
| // ignore bad attribute ... |
| } |
| } |
| |
| stamp = loadAttribute(props, CFG_FEATURE_STAMP, null); |
| if (stamp != null) { |
| try { |
| lastFeaturesChangeStamp = Long.parseLong(stamp); |
| } catch(NumberFormatException e) { |
| // ignore bad attribute ... |
| } |
| } |
| |
| stamp = loadAttribute(props, CFG_PLUGIN_STAMP, null); |
| if (stamp != null) { |
| try { |
| lastPluginsChangeStamp = Long.parseLong(stamp); |
| } catch(NumberFormatException e) { |
| // ignore bad attribute ... |
| } |
| } |
| |
| // load bootstrap entries |
| String[] ids = getBootstrapPluginIdentifiers(); |
| for (int i=0; i<ids.length; i++) { |
| bootPlugins.put(ids[i], loadAttribute(props, CFG_BOOT_PLUGIN + "." + ids[i], null)); //$NON-NLS-1$ |
| } |
| |
| // load feature entries |
| IFeatureEntry fe = loadFeatureEntry(props, CFG_FEATURE_ENTRY+".0", null); //$NON-NLS-1$ |
| for (int i=1; fe != null; i++) { |
| configureFeatureEntry(fe); |
| fe = loadFeatureEntry(props, CFG_FEATURE_ENTRY+"."+i, null); //$NON-NLS-1$ |
| } |
| |
| // load site properties |
| SiteEntry root = (SiteEntry)getRootSite(); |
| String rootUrlString = root.getURL().toExternalForm(); |
| SiteEntry se = (SiteEntry) loadSite(props, CFG_SITE+".0", null); //$NON-NLS-1$ |
| for (int i=1; se != null; i++) { |
| |
| // check if we are forcing "first use" processing with an existing |
| // platform.cfg. In this case ignore site entry that represents |
| // the platform install, and use a root site entry in its place. |
| // This ensures we do not get messed up by an exclusion list that |
| // is read from the prior state. |
| if (cmdFirstUse && rootUrlString.equals(se.getURL().toExternalForm())) |
| se = root; |
| |
| if (!se.isExternallyLinkedSite()) |
| configureSite(se); |
| else |
| // remember external link site state, but do not configure at this point |
| externalLinkSites.put(se.getURL(),se); |
| se = (SiteEntry) loadSite(props, CFG_SITE+"."+i, null); //$NON-NLS-1$ |
| } |
| } |
| |
| private Properties loadProperties(URL url, String suffix) throws IOException { |
| |
| // figure out what we will be loading |
| if (suffix != null && !suffix.equals("")) //$NON-NLS-1$ |
| url = new URL(url.getProtocol(),url.getHost(),url.getPort(),url.getFile()+suffix); |
| |
| // try to load saved configuration file |
| Properties props = new Properties(); |
| InputStream is = null; |
| try { |
| is = url.openStream(); |
| props.load(is); |
| // check to see if we have complete config file |
| if (!EOF.equals(props.getProperty(EOF))) { |
| throw new IOException(Policy.bind("cfig.unableToLoad.incomplete",url.toString())); //$NON-NLS-1$ |
| } |
| } finally { |
| if (is!=null) { |
| try { |
| is.close(); |
| } catch(IOException e) { |
| // ignore ... |
| } |
| } |
| } |
| return props; |
| } |
| |
| private ISiteEntry loadSite(Properties props, String name, ISiteEntry dflt) { |
| |
| String urlString = loadAttribute(props, name+"."+CFG_URL, null); //$NON-NLS-1$ |
| if (urlString == null) |
| return dflt; |
| |
| URL url = null; |
| try { |
| url = new URL(urlString); |
| } catch(MalformedURLException e) { |
| return dflt; |
| } |
| |
| int policyType; |
| String[] policyList; |
| String typeString = loadAttribute(props, name+"."+CFG_POLICY, null); //$NON-NLS-1$ |
| if (typeString == null) { |
| policyType = DEFAULT_POLICY_TYPE; |
| policyList = DEFAULT_POLICY_LIST; |
| } else { |
| int i; |
| for (i=0; i<CFG_POLICY_TYPE.length; i++) { |
| if (typeString.equals(CFG_POLICY_TYPE[i])) { |
| break; |
| } |
| } |
| if (i>=CFG_POLICY_TYPE.length) { |
| policyType = DEFAULT_POLICY_TYPE; |
| policyList = DEFAULT_POLICY_LIST; |
| } else { |
| policyType = i; |
| policyList = loadListAttribute(props, name+"."+CFG_LIST, new String[0]); //$NON-NLS-1$ |
| } |
| } |
| |
| ISitePolicy sp = createSitePolicy(policyType, policyList); |
| SiteEntry site = (SiteEntry) createSiteEntry(url,sp); |
| |
| String stamp = loadAttribute(props, name+"."+CFG_STAMP, null); //$NON-NLS-1$ |
| if (stamp != null) { |
| try { |
| site.lastChangeStamp = Long.parseLong(stamp); |
| } catch(NumberFormatException e) { |
| // ignore bad attribute ... |
| } |
| } |
| |
| stamp = loadAttribute(props, name+"."+CFG_FEATURE_STAMP, null); //$NON-NLS-1$ |
| if (stamp != null) { |
| try { |
| site.lastFeaturesChangeStamp = Long.parseLong(stamp); |
| } catch(NumberFormatException e) { |
| // ignore bad attribute ... |
| } |
| } |
| |
| stamp = loadAttribute(props, name+"."+CFG_PLUGIN_STAMP, null); //$NON-NLS-1$ |
| if (stamp != null) { |
| try { |
| site.lastPluginsChangeStamp = Long.parseLong(stamp); |
| } catch(NumberFormatException e) { |
| // ignore bad attribute ... |
| } |
| } |
| |
| String flag = loadAttribute(props, name+"."+CFG_UPDATEABLE, null); //$NON-NLS-1$ |
| if (flag != null) { |
| if (flag.equals("true")) //$NON-NLS-1$ |
| site.updateable = true; |
| else |
| site.updateable = false; |
| } |
| |
| String linkname = loadAttribute(props, name+"."+CFG_LINK_FILE, null); //$NON-NLS-1$ |
| if (linkname != null && !linkname.equals("")) { //$NON-NLS-1$ |
| site.linkFileName = linkname.replace('/',File.separatorChar); |
| } |
| |
| return site; |
| } |
| |
| private IFeatureEntry loadFeatureEntry(Properties props, String name, IFeatureEntry dflt) { |
| String id = loadAttribute(props, name+"."+CFG_FEATURE_ENTRY_ID, null); //$NON-NLS-1$ |
| if (id == null) |
| return dflt; |
| String version = loadAttribute(props, name+"."+CFG_FEATURE_ENTRY_VERSION, null); //$NON-NLS-1$ |
| String pluginVersion = loadAttribute(props, name+"."+CFG_FEATURE_ENTRY_PLUGIN_VERSION, null); //$NON-NLS-1$ |
| if (pluginVersion == null) |
| pluginVersion = version; |
| String application = loadAttribute(props, name+"."+CFG_FEATURE_ENTRY_APPLICATION, null); //$NON-NLS-1$ |
| ArrayList rootList = new ArrayList(); |
| |
| // get install locations |
| String rootString = loadAttribute(props, name+"."+CFG_FEATURE_ENTRY_ROOT+".0", null); //$NON-NLS-1$ //$NON-NLS-2$ |
| for (int i=1; rootString != null; i++) { |
| try { |
| URL rootEntry = new URL(rootString); |
| rootList.add(rootEntry); |
| } catch(MalformedURLException e) { |
| // skip bad entries ... |
| } |
| rootString = loadAttribute(props, name+"."+CFG_FEATURE_ENTRY_ROOT+"."+i, null); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| URL[] roots = (URL[])rootList.toArray(new URL[0]); |
| |
| // get primary flag |
| boolean primary = false; |
| String flag = loadAttribute(props, name+"."+CFG_FEATURE_ENTRY_PRIMARY, null); //$NON-NLS-1$ |
| if (flag != null) { |
| if (flag.equals("true")) //$NON-NLS-1$ |
| primary = true; |
| } |
| return createFeatureEntry(id, version, pluginVersion, primary, application, roots); |
| } |
| |
| private String[] loadListAttribute(Properties props, String name, String[] dflt) { |
| ArrayList list = new ArrayList(); |
| String value = loadAttribute(props, name+".0",null); //$NON-NLS-1$ |
| if (value == null) |
| return dflt; |
| |
| for (int i=1; value != null; i++) { |
| loadListAttributeSegment(list, value); |
| value = loadAttribute(props, name+"."+i, null); //$NON-NLS-1$ |
| } |
| return (String[])list.toArray(new String[0]); |
| } |
| |
| private void loadListAttributeSegment(ArrayList list,String value) { |
| |
| if (value==null) return; |
| |
| StringTokenizer tokens = new StringTokenizer(value, ","); //$NON-NLS-1$ |
| String token; |
| while (tokens.hasMoreTokens()) { |
| token = tokens.nextToken().trim(); |
| if (!token.equals("")) //$NON-NLS-1$ |
| list.add(token); |
| } |
| return; |
| } |
| |
| private String loadAttribute(Properties props, String name, String dflt) { |
| String prop = props.getProperty(name); |
| if (prop == null) |
| return dflt; |
| else |
| return prop.trim(); |
| } |
| |
| private void loadInitializationAttributes() { |
| |
| // look for the product initialization file relative to the install location |
| URL url = BootLoader.getInstallURL(); |
| |
| // load any initialization attributes. These are the default settings for |
| // key attributes (eg. default primary feature) supplied by the packaging team. |
| // They are always reloaded on startup to pick up any changes due to |
| // "native" updates. |
| Properties initProps = new Properties(); |
| InputStream is = null; |
| try { |
| URL initURL = new URL(url, CONFIG_FILE_INIT); |
| is = initURL.openStream(); |
| initProps.load(is); |
| if (DEBUG) |
| debug("Defaults from "+initURL.toExternalForm()); //$NON-NLS-1$ |
| } catch(IOException e) { |
| return; // could not load default settings |
| } finally { |
| if (is!=null) { |
| try { |
| is.close(); |
| } catch(IOException e) { |
| // ignore ... |
| } |
| } |
| } |
| |
| // use default settings if supplied |
| String initId = loadAttribute(initProps, INIT_DEFAULT_FEATURE_ID, null); |
| if (initId != null) { |
| String application = loadAttribute(initProps, INIT_DEFAULT_FEATURE_APPLICATION, null); |
| IFeatureEntry fe = findConfiguredFeatureEntry(initId); |
| |
| if (fe == null){ |
| // bug 26896 : setup optimistic reconciliation if the primary feature has changed or is new |
| cmdFirstUse = true; |
| // create entry if not exists |
| fe = createFeatureEntry(initId, null, null, true, application, null); |
| } |
| else |
| // update existing entry with new info |
| fe = createFeatureEntry(initId, fe.getFeatureVersion(), fe.getFeaturePluginVersion(), fe.canBePrimary(), application, fe.getFeatureRootURLs()); |
| configureFeatureEntry(fe); |
| defaultFeature = initId; |
| if (DEBUG) { |
| debug(" Default primary feature: "+defaultFeature); //$NON-NLS-1$ |
| if (application != null) |
| debug(" Default application : "+application); //$NON-NLS-1$ |
| } |
| } |
| } |
| |
| private void locateDefaultPlugins() { |
| |
| // determine the runtime for the currently executing boot loader |
| HashMap runtimeImport = getRuntimeImport(); |
| |
| // locate runtime plugin matching the import from boot |
| URL runtimePluginPath = getPluginPath(runtimeImport); |
| if (runtimePluginPath == null) |
| throw new RuntimeException(Policy.bind("error.runtime")); //$NON-NLS-1$ |
| |
| // get boot descriptor for runtime plugin |
| runtimeDescriptor = createPluginBootDescriptor(runtimePluginPath); |
| |
| // determine the xml plugin for the selected runtime |
| HashMap xmlImport = getImport(runtimePluginPath, XML_PLUGIN_ID); |
| |
| // locate xml plugin matching the import from runtime plugin |
| URL xmlPluginPath = getPluginPath(xmlImport); |
| if (xmlPluginPath == null) |
| throw new RuntimeException(Policy.bind("error.xerces")); //$NON-NLS-1$ |
| |
| // get boot descriptor for xml plugin |
| xmlDescriptor = createPluginBootDescriptor(xmlPluginPath); |
| } |
| |
| private HashMap getRuntimeImport() { |
| // determine the load directory location of the boot loader |
| URL url = InternalBootLoader.class.getProtectionDomain().getCodeSource().getLocation(); |
| String path = InternalBootLoader.decode(url.getFile()); |
| File base = new File(path); |
| if (!base.isDirectory()) |
| base = base.getParentFile(); // was loaded from jar |
| |
| // find the plugin.xml (need to search because in dev mode |
| // we can have some extra directory entries) |
| File xml = null; |
| while(base != null) { |
| xml = new File(base, BOOT_XML); |
| if (xml.exists()) |
| break; |
| base = base.getParentFile(); |
| } |
| if (xml == null) |
| throw new RuntimeException(Policy.bind("error.boot")); //$NON-NLS-1$ |
| |
| try { |
| return getImport(xml.toURL(), RUNTIME_PLUGIN_ID); |
| } catch(MalformedURLException e) { |
| return null; |
| } |
| } |
| |
| |
| private HashMap getImport(URL entry, String id) { |
| if (id == null) |
| return null; |
| final String fId = id; |
| |
| // parse out the import element attributes |
| Selector importSel = new Selector() { |
| // parse out import attributes |
| public boolean select(String element){ |
| if (element.startsWith("import")) //$NON-NLS-1$ |
| return true; |
| else |
| return false; |
| } |
| public boolean select(String element, HashMap attributes) { |
| if (attributes == null) |
| return false; |
| String plugin = (String) attributes.get("plugin"); //$NON-NLS-1$ |
| return fId.equals(plugin); |
| } |
| }; |
| Parser p = new Parser(entry); |
| return p.getElement(importSel); |
| } |
| |
| private BootDescriptor createPluginBootDescriptor(URL entry) { |
| if (entry == null) |
| return null; |
| |
| // selector for plugin element |
| Selector pluginSel = new Selector() { |
| public boolean select(String element){ |
| if (element.startsWith("plugin")) //$NON-NLS-1$ |
| return true; |
| else |
| return false; |
| } |
| public boolean select(String element, HashMap attributes) { |
| return true; |
| } |
| }; |
| |
| // selector for library elements |
| final ArrayList libs = new ArrayList(); |
| Selector librarySel = new Selector() { |
| public boolean select(String element){ |
| if (element.startsWith("library")) //$NON-NLS-1$ |
| return true; |
| else |
| return false; |
| } |
| public boolean select(String element, HashMap attributes) { |
| if (attributes == null) |
| return false; |
| String lib = (String) attributes.get("name"); //$NON-NLS-1$ |
| if (lib != null) |
| libs.add(lib); |
| return false; // accumulate all library elements |
| } |
| }; |
| |
| // parse out descriptor information |
| Parser p = new Parser(entry); |
| String id = null; |
| String version = null; |
| HashMap attributes = p.getElement(pluginSel); |
| if (attributes != null) { |
| id = (String)attributes.get("id"); //$NON-NLS-1$ |
| version = (String)attributes.get("version"); //$NON-NLS-1$ |
| } |
| if (id == null) |
| id = ""; //$NON-NLS-1$ |
| if (version == null) |
| version = "0.0.0"; //$NON-NLS-1$ |
| |
| p.getElement(librarySel); |
| String[] libraries = (String[])libs.toArray(new String[0]); |
| |
| String dir = entry.getFile(); |
| int ix = dir.lastIndexOf("/"); //$NON-NLS-1$ |
| dir = dir.substring(0,ix+1); |
| URL dirURL = null; |
| try { |
| dirURL = new URL(entry.getProtocol(), entry.getHost(), entry.getPort(), dir); |
| } catch(MalformedURLException e) { |
| // continue ... |
| } |
| |
| // return boot descriptor for the plugin |
| return new BootDescriptor(id, version, libraries, dirURL); |
| } |
| |
| private URL getPluginPath(HashMap importElement) { |
| // return the plugin path element for the specified import element |
| |
| if (importElement == null) |
| return null; |
| |
| // determine which plugin we are looking for |
| VersionedIdentifier id; |
| String pid = (String) importElement.get("plugin"); //$NON-NLS-1$ |
| String version = (String) importElement.get("version"); //$NON-NLS-1$ |
| String match = (String) importElement.get("match"); //$NON-NLS-1$ |
| if (pid == null) |
| return null; // bad <import> element |
| if (version == null) |
| id = new VersionedIdentifier(pid); |
| else { |
| id = new VersionedIdentifier(pid+"_"+version); //$NON-NLS-1$ |
| if (match == null) |
| match = "compatible"; //$NON-NLS-1$ |
| } |
| |
| // search plugins on all configured sites |
| ISiteEntry[] sites = getConfiguredSites(); |
| if (sites == null || sites.length == 0) |
| return null; |
| |
| VersionedIdentifier savedVid = id; // initialize with baseline we are looking for |
| String savedEntry = null; |
| URL savedURL = null; |
| for (int j=0; j<sites.length; j++) { |
| String[] plugins = sites[j].getPlugins(); |
| for (int i=0; plugins!=null && i<plugins.length; i++) { |
| // look for best match. |
| // The entries are in the form <path>/<pluginDir>/plugin.xml |
| // look for -------------------------^ |
| int ix = findEntrySeparator(plugins[i],2); // second from end |
| if (ix == -1) |
| continue; // bad entry ... skip |
| String pluginDir = plugins[i].substring(ix+1); |
| ix = pluginDir.indexOf("/"); //$NON-NLS-1$ |
| if (ix != -1) |
| pluginDir = pluginDir.substring(0,ix); |
| if (pluginDir.equals("")) //$NON-NLS-1$ |
| continue; // bad entry ... skip |
| |
| // compare the candidate plugin using the matching rule |
| VersionedIdentifier vid = new VersionedIdentifier(pluginDir); |
| if (vid.equalIdentifiers(id)) { |
| |
| // check if we have suffixed directory. If not (eg. self-hosting) |
| // we need to actually parse the plugin.xml to get its version |
| if (pluginDir.indexOf("_") == -1) { //$NON-NLS-1$ |
| URL xmlURL = null; |
| try { |
| xmlURL = new URL(((SiteEntry)sites[j]).getResolvedURL(), plugins[i]); |
| } catch (MalformedURLException e) { |
| continue; // bad URL ... skip |
| } |
| |
| // parse out the plugin element attributes |
| final String fpid = pid; |
| Selector versionSel = new Selector() { |
| // parse out plugin attributes |
| public boolean select(String element){ |
| if (element.startsWith("plugin")) //$NON-NLS-1$ |
| return true; |
| else |
| return false; |
| } |
| public boolean select(String element, HashMap attributes) { |
| if (attributes == null) |
| return false; |
| String plugin = (String) attributes.get("id"); //$NON-NLS-1$ |
| return fpid.equals(plugin); |
| } |
| }; |
| Parser p = new Parser(xmlURL); |
| HashMap attributes = p.getElement(versionSel); |
| if (attributes == null) |
| continue; // bad xml ... skip |
| String pluginVersion; |
| if ((pluginVersion = (String)attributes.get("version")) == null) //$NON-NLS-1$ |
| continue; // bad xml ... skip |
| pluginDir += "_" + pluginVersion; //$NON-NLS-1$ |
| vid = new VersionedIdentifier(pluginDir); |
| } |
| |
| // do the comparison |
| int result; |
| if ((result = vid.compareVersion(savedVid)) >= 0) { |
| if ("greaterOrEqual".equals(match)) { //$NON-NLS-1$ |
| if (result > VersionedIdentifier.GREATER_THAN) |
| continue; |
| } else if ("compatible".equals(match)) { //$NON-NLS-1$ |
| if (result > VersionedIdentifier.COMPATIBLE) |
| continue; |
| } else if ("equivalent".equals(match)) { //$NON-NLS-1$ |
| if (result > VersionedIdentifier.EQUIVALENT) |
| continue; |
| } else if ("perfect".equals(match)) { //$NON-NLS-1$ |
| if (result > VersionedIdentifier.EQUAL) |
| continue; |
| } else if (result > VersionedIdentifier.GREATER_THAN) |
| continue; // use the latest |
| savedVid = vid; |
| savedEntry = plugins[i]; |
| savedURL = ((SiteEntry)sites[j]).getResolvedURL(); |
| } |
| } |
| } |
| } |
| |
| if (savedEntry == null) |
| return null; |
| |
| try { |
| return new URL(savedURL,savedEntry); |
| } catch(MalformedURLException e) { |
| return null; |
| } |
| } |
| |
| private void write(PrintWriter w) { |
| // write header |
| w.println("# "+(new Date()).toString()); //$NON-NLS-1$ |
| writeAttribute(w, CFG_VERSION, VERSION); |
| if (transientConfig) |
| writeAttribute(w,CFG_TRANSIENT,"true"); //$NON-NLS-1$ |
| w.println(""); //$NON-NLS-1$ |
| |
| // write global attributes |
| writeAttribute(w,CFG_STAMP,Long.toString(getChangeStamp())); |
| writeAttribute(w,CFG_FEATURE_STAMP,Long.toString(getFeaturesChangeStamp())); |
| writeAttribute(w,CFG_PLUGIN_STAMP,Long.toString(getPluginsChangeStamp())); |
| |
| // write out bootstrap entries |
| String[] ids = getBootstrapPluginIdentifiers(); |
| for (int i=0; i<ids.length; i++) { |
| String location = (String) bootPlugins.get(ids[i]); |
| if (location != null) |
| writeAttribute(w, CFG_BOOT_PLUGIN + "." + ids[i], location); //$NON-NLS-1$ |
| } |
| |
| // write out feature entries |
| w.println(""); //$NON-NLS-1$ |
| writeAttribute(w,CFG_FEATURE_ENTRY_DEFAULT,defaultFeature); |
| IFeatureEntry[] feats = getConfiguredFeatureEntries(); |
| for (int i=0; i<feats.length; i++) { |
| writeFeatureEntry(w, CFG_FEATURE_ENTRY + "." + Integer.toString(i), feats[i]); //$NON-NLS-1$ |
| } |
| |
| // write out site entries |
| SiteEntry[] list = (SiteEntry[]) sites.values().toArray(new SiteEntry[0]); |
| for (int i = 0; i < list.length; i++) { |
| writeSite(w, CFG_SITE + "." + Integer.toString(i), list[i]); //$NON-NLS-1$ |
| } |
| |
| // write end-of-file marker |
| writeAttribute(w, EOF, EOF); |
| } |
| |
| private void writeSite(PrintWriter w, String id, SiteEntry entry) { |
| |
| // write site separator |
| w.println(""); //$NON-NLS-1$ |
| |
| // write out site settings |
| writeAttribute(w, id + "." + CFG_URL, entry.getURL().toString()); //$NON-NLS-1$ |
| writeAttribute(w, id + "." + CFG_STAMP,Long.toString(entry.getChangeStamp())); //$NON-NLS-1$ |
| writeAttribute(w, id + "." + CFG_FEATURE_STAMP,Long.toString(entry.getFeaturesChangeStamp())); //$NON-NLS-1$ |
| writeAttribute(w, id + "." + CFG_PLUGIN_STAMP,Long.toString(entry.getPluginsChangeStamp())); //$NON-NLS-1$ |
| writeAttribute(w, id + "." + CFG_UPDATEABLE, entry.updateable?"true":"false"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| if (entry.linkFileName != null && !entry.linkFileName.trim().equals("")) //$NON-NLS-1$ |
| writeAttribute(w, id + "." + CFG_LINK_FILE, entry.linkFileName.trim().replace(File.separatorChar,'/')); //$NON-NLS-1$ |
| |
| // write out site policy |
| int type = entry.getSitePolicy().getType(); |
| String typeString = CFG_POLICY_TYPE_UNKNOWN; |
| try { |
| typeString = CFG_POLICY_TYPE[type]; |
| } catch (IndexOutOfBoundsException e) { |
| // ignore bad attribute ... |
| } |
| writeAttribute(w, id + "." + CFG_POLICY, typeString); //$NON-NLS-1$ |
| writeListAttribute(w, id + "." + CFG_LIST, entry.getSitePolicy().getList()); //$NON-NLS-1$ |
| } |
| |
| private void writeFeatureEntry(PrintWriter w, String id, IFeatureEntry entry) { |
| |
| // write feature entry separator |
| w.println(""); //$NON-NLS-1$ |
| |
| // write out feature entry settings |
| writeAttribute(w, id + "." + CFG_FEATURE_ENTRY_ID, entry.getFeatureIdentifier()); //$NON-NLS-1$ |
| if (entry.canBePrimary()) |
| writeAttribute(w, id + "." + CFG_FEATURE_ENTRY_PRIMARY, "true"); //$NON-NLS-1$ //$NON-NLS-2$ |
| writeAttribute(w, id + "." + CFG_FEATURE_ENTRY_VERSION, entry.getFeatureVersion()); //$NON-NLS-1$ |
| if (entry.getFeatureVersion()!=null && !entry.getFeatureVersion().equals(entry.getFeaturePluginVersion())) |
| writeAttribute(w, id + "." + CFG_FEATURE_ENTRY_PLUGIN_VERSION, entry.getFeaturePluginVersion()); //$NON-NLS-1$ |
| writeAttribute(w, id + "." + CFG_FEATURE_ENTRY_APPLICATION, entry.getFeatureApplication()); //$NON-NLS-1$ |
| URL[] roots = entry.getFeatureRootURLs(); |
| for (int i=0; i<roots.length; i++) { |
| // write our as individual attributes (is easier for Main.java to read) |
| writeAttribute(w, id + "." + CFG_FEATURE_ENTRY_ROOT + "." + i, roots[i].toExternalForm()); //$NON-NLS-1$ //$NON-NLS-2$ |
| } |
| } |
| |
| private void writeListAttribute(PrintWriter w, String id, String[] list) { |
| if (list == null || list.length == 0) |
| return; |
| |
| String value = ""; //$NON-NLS-1$ |
| int listLen = 0; |
| int listIndex = 0; |
| for (int i = 0; i < list.length; i++) { |
| if (listLen != 0) |
| value += ","; //$NON-NLS-1$ |
| else |
| value = ""; //$NON-NLS-1$ |
| value += list[i]; |
| |
| if (++listLen >= CFG_LIST_LENGTH) { |
| writeAttribute(w, id + "." + Integer.toString(listIndex++), value); //$NON-NLS-1$ |
| listLen = 0; |
| } |
| } |
| if (listLen != 0) |
| writeAttribute(w, id + "." + Integer.toString(listIndex), value); //$NON-NLS-1$ |
| } |
| |
| private void writeAttribute(PrintWriter w, String id, String value) { |
| if (value==null || value.trim().equals("")) //$NON-NLS-1$ |
| return; |
| w.println(id + "=" + escapedValue(value)); //$NON-NLS-1$ |
| } |
| |
| private String escapedValue(String value) { |
| // if required, escape property values as \\uXXXX |
| StringBuffer buf = new StringBuffer(value.length()*2); // assume expansion by less than factor of 2 |
| for (int i=0; i<value.length(); i++) { |
| char character = value.charAt(i); |
| if (character == '\\' |
| || character == '\t' |
| || character == '\r' |
| || character == '\n' |
| || character == '\f') { |
| // handle characters requiring leading \ |
| buf.append('\\'); |
| buf.append(character); |
| } else if ((character < 0x0020) || (character > 0x007e)) { |
| // handle characters outside base range (encoded) |
| buf.append('\\'); |
| buf.append('u'); |
| buf.append(HEX[(character >> 12) & 0xF]); // first nibble |
| buf.append(HEX[(character >> 8) & 0xF]); // second nibble |
| buf.append(HEX[(character >> 4) & 0xF]); // third nibble |
| buf.append(HEX[character & 0xF]); // fourth nibble |
| } else { |
| // handle base characters |
| buf.append(character); |
| } |
| } |
| return buf.toString(); |
| } |
| |
| private static String[] checkForFeatureChanges(String[] args, PlatformConfiguration cfg) { |
| String original = cfg.getApplicationIdentifierInternal(); |
| String actual = cfg.getApplicationIdentifier(); |
| |
| if (original.equals(actual)) |
| // base startup of specified application |
| return args; |
| else { |
| // Will run reconciler. |
| // Re-insert -application argument with original app and optionally |
| // force "first use" processing |
| int newArgCnt = cmdFirstUse ? 3 : 2; |
| String[] newArgs = new String[args.length+newArgCnt]; |
| newArgs[0] = CMD_APPLICATION; |
| newArgs[1] = original; |
| if (cmdFirstUse) |
| newArgs[2] = CMD_FIRSTUSE; |
| System.arraycopy(args,0,newArgs,newArgCnt,args.length); |
| if (DEBUG) |
| debug("triggering reconciliation ..."); //$NON-NLS-1$ |
| return newArgs; |
| } |
| } |
| |
| private static String[] checkForNewUpdates(IPlatformConfiguration cfg, String[] args) { |
| try { |
| URL markerURL = new URL(cfg.getConfigurationLocation(), CHANGES_MARKER); |
| File marker = new File(markerURL.getFile()); |
| if (!marker.exists()) |
| return args; |
| |
| // indicate -newUpdates |
| marker.delete(); |
| String[] newArgs = new String[args.length+1]; |
| newArgs[0] = CMD_NEW_UPDATES; |
| System.arraycopy(args,0,newArgs,1,args.length); |
| return newArgs; |
| } catch(MalformedURLException e) { |
| return args; |
| } |
| } |
| |
| private static String[] processCommandLine(String[] args) throws Exception { |
| int[] configArgs = new int[100]; |
| configArgs[0] = -1; // need to initialize the first element to something that could not be an index. |
| int configArgIndex = 0; |
| for (int i = 0; i < args.length; i++) { |
| boolean found = false; |
| |
| // check for args without parameters (i.e., a flag arg) |
| |
| // look for forced "first use" processing (triggered by stale |
| // bootstrap information) |
| if (args[i].equalsIgnoreCase(CMD_FIRSTUSE)) { |
| cmdFirstUse = true; |
| found = true; |
| } |
| |
| // look for the update flag |
| if (args[i].equalsIgnoreCase(CMD_UPDATE)) { |
| cmdUpdate = true; |
| found = true; |
| } |
| |
| // look for the no-update flag |
| if (args[i].equalsIgnoreCase(CMD_NO_UPDATE)) { |
| cmdNoUpdate = true; |
| found = true; |
| } |
| |
| // look for the initialization flag |
| if (args[i].equalsIgnoreCase(CMD_INITIALIZE)) { |
| cmdInitialize = true; |
| continue; // do not remove from command line |
| } |
| |
| // look for the development mode flag ... triggers no-update |
| if (args[i].equalsIgnoreCase(CMD_DEV)) { |
| cmdDev = true; |
| continue; // do not remove from command line |
| } |
| |
| if (found) { |
| configArgs[configArgIndex++] = i; |
| continue; |
| } |
| |
| // check for args with parameters. If we are at the last argument or if the next one |
| // has a '-' as the first character, then we can't have an arg with a parm so continue. |
| |
| if (i == args.length - 1 || args[i + 1].startsWith("-")) { //$NON-NLS-1$ |
| continue; |
| } |
| |
| String arg = args[++i]; |
| |
| // look for the platform configuration to use. |
| if (args[i - 1].equalsIgnoreCase(CMD_CONFIGURATION)) { |
| found = true; |
| cmdConfiguration = arg; |
| } |
| |
| // look for the feature to use for customization. |
| if (args[i - 1].equalsIgnoreCase(CMD_FEATURE)) { |
| found = true; |
| cmdFeature = arg; |
| } |
| |
| // look for the application to run. Only use the value from the |
| // command line if the application identifier was not explicitly |
| // passed on BootLoader.run(...) invocation. |
| if (args[i - 1].equalsIgnoreCase(CMD_APPLICATION)) { |
| found = true; |
| if (cmdApplication == null) |
| cmdApplication = arg; |
| } |
| |
| // R1.0 compatibility |
| // look for the plugins location to use. Only use the value from the |
| // command line if the plugins location was not explicitly passed on |
| // BootLoader.run(...) or BootLoader.startup(...) invocation. |
| if (args[i - 1].equalsIgnoreCase(CMD_PLUGINS)) { |
| found = true; |
| // if the arg can be made into a URL use it. Otherwise assume that |
| // it is a file path so make a file URL. |
| try { |
| if (cmdPlugins == null) |
| cmdPlugins = new URL(arg); |
| } catch (MalformedURLException e) { |
| try { |
| cmdPlugins = new URL("file:" + arg.replace(File.separatorChar, '/')); //$NON-NLS-1$ |
| } catch (MalformedURLException e2) { |
| throw e; // rethrow original exception |
| } |
| } |
| } |
| |
| // done checking for args. Remember where an arg was found |
| if (found) { |
| configArgs[configArgIndex++] = i - 1; |
| configArgs[configArgIndex++] = i; |
| } |
| } |
| |
| // remove all the arguments consumed by this argument parsing |
| if (configArgIndex == 0) |
| return args; |
| String[] passThruArgs = new String[args.length - configArgIndex]; |
| configArgIndex = 0; |
| int j = 0; |
| for (int i = 0; i < args.length; i++) { |
| if (i == configArgs[configArgIndex]) |
| configArgIndex++; |
| else |
| passThruArgs[j++] = args[i]; |
| } |
| return passThruArgs; |
| } |
| |
| |
| private static int findEntrySeparator(String pathEntry, int cnt) { |
| for (int i=pathEntry.length()-1; i>=0; i--) { |
| if (pathEntry.charAt(i) == '/') { |
| if (--cnt == 0) |
| return i; |
| } |
| } |
| return -1; |
| } |
| |
| private static String[] stringListToArray(String prop, String separator) { |
| if (prop == null || prop.trim().equals("")) //$NON-NLS-1$ |
| return new String[0]; |
| ArrayList list = new ArrayList(); |
| StringTokenizer tokens = new StringTokenizer(prop, separator); |
| while (tokens.hasMoreTokens()) { |
| String token = tokens.nextToken().trim(); |
| if (!token.equals("")) //$NON-NLS-1$ |
| list.add(token); |
| } |
| return list.isEmpty() ? new String[0] : (String[]) list.toArray(new String[0]); |
| } |
| |
| private static boolean supportsDetection(URL url) { |
| String protocol = url.getProtocol(); |
| if (protocol.equals("file")) //$NON-NLS-1$ |
| return true; |
| else if (protocol.equals(PlatformURLHandler.PROTOCOL)) { |
| URL resolved = null; |
| try { |
| resolved = resolvePlatformURL(url); // 19536 |
| } catch(IOException e) { |
| return false; // we tried but failed to resolve the platform URL |
| } |
| return resolved.getProtocol().equals("file"); //$NON-NLS-1$ |
| } else |
| return false; |
| } |
| |
| private static void verifyPath(URL url) { |
| String protocol = url.getProtocol(); |
| String path = null; |
| if (protocol.equals("file")) //$NON-NLS-1$ |
| path = url.getFile(); |
| else if (protocol.equals(PlatformURLHandler.PROTOCOL)) { |
| URL resolved = null; |
| try { |
| resolved = resolvePlatformURL(url); // 19536 |
| if (resolved.getProtocol().equals("file")) //$NON-NLS-1$ |
| path = resolved.getFile(); |
| } catch(IOException e) { |
| // continue ... |
| } |
| } |
| |
| if (path != null) { |
| File dir = new File(path).getParentFile(); |
| if (dir != null) |
| dir.mkdirs(); |
| } |
| } |
| |
| private static URL resolvePlatformURL(URL url) throws IOException { |
| // 19536 |
| if (url.getProtocol().equals(PlatformURLHandler.PROTOCOL)) { |
| URLConnection connection = url.openConnection(); |
| if (connection instanceof PlatformURLConnection) { |
| url = ((PlatformURLConnection)connection).getResolvedURL(); |
| } else { |
| // connection = new PlatformURLBaseConnection(url); |
| // url = ((PlatformURLConnection)connection).getResolvedURL(); |
| url = InternalBootLoader.getInstallURL(); |
| } |
| } |
| return url; |
| } |
| |
| private static void debug(String s) { |
| System.out.println("PlatformConfig: " + s); //$NON-NLS-1$ |
| } |
| } |