| //------------------------------------------------------------------------------ |
| // Copyright (c) 2005, 2007 IBM Corporation and others. |
| // All rights reserved. This program and the accompanying materials |
| // are made available under the terms of the Eclipse Public License v1.0 |
| // which accompanies this distribution, and is available at |
| // http://www.eclipse.org/legal/epl-v10.html |
| // |
| // Contributors: |
| // IBM Corporation - initial implementation |
| //------------------------------------------------------------------------------ |
| package org.eclipse.epf.common.service.versioning; |
| |
| import java.io.File; |
| import java.util.ArrayList; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.LinkedHashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.MissingResourceException; |
| import java.util.Set; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| |
| import org.eclipse.core.runtime.IConfigurationElement; |
| import org.eclipse.core.runtime.IExtension; |
| import org.eclipse.core.runtime.IExtensionPoint; |
| import org.eclipse.core.runtime.IExtensionRegistry; |
| import org.eclipse.core.runtime.Platform; |
| import org.eclipse.epf.common.service.ServicePlugin; |
| import org.eclipse.epf.common.utils.FileUtil; |
| import org.eclipse.epf.common.utils.StrUtil; |
| import org.osgi.framework.Bundle; |
| import org.osgi.framework.Version; |
| |
| /** |
| * Provides utilities to query a method library schema and the version of the |
| * tool that created it. |
| * |
| * @author Jeff Hardy |
| * @since 1.0 |
| */ |
| public class VersionUtil { |
| |
| public static class VersionCheckInfo { |
| public VersionCheckInfo(String id, String toolVersion, |
| String currentMinToolVersion, int result) { |
| this.toolID = id; |
| this.toolVersion = toolVersion; |
| this.currentMinToolVersion = currentMinToolVersion; |
| this.result = result; |
| } |
| |
| public String toolID; |
| |
| public String toolVersion; |
| |
| public String currentMinToolVersion; |
| |
| /** |
| * < 0: fileToolVersion is older than currentMinToolVersion <br/> == 0: |
| * match <br/> > 0 : fileToolVersion is newer than currentMinToolVersion |
| * <br/> |
| */ |
| public int result; |
| } |
| |
| /** |
| * The extension point namespace. |
| */ |
| public static final String EXTENSION_POINT_NAMESPACE = ServicePlugin.class |
| .getPackage().getName(); |
| |
| /** |
| * The extension point name. |
| */ |
| public static final String EXTENSION_POINT_NAME = "version"; //$NON-NLS-1$ |
| |
| public static final String EXTENSION_VERSIONS_INFO = "versions"; //$NON-NLS-1$ |
| |
| public static final String EXTENSION_LIB_EXTENSION_CHECK = "libraryExtensionVersionCheck"; //$NON-NLS-1$ |
| |
| private static final String DISABLE_VERSION_CHECKING_PREF = "disable_version_checking"; //$NON-NLS-1$ |
| |
| public static Map<String, EPFVersions> versions = new LinkedHashMap<String, EPFVersions>(); |
| |
| public static Map<String, ILibraryExtensionVersionCheck> libExtCheckers = new LinkedHashMap<String, ILibraryExtensionVersionCheck>(); |
| |
| protected static boolean versionCheckingDisabled = false; |
| |
| /** |
| * List of toolIDs to check, in order |
| */ |
| private static List<String> toolIDsCheckList = new ArrayList<String>(); |
| |
| static { |
| toolIDsCheckList.add(EPFVersions.TOOL_ID); |
| |
| // read properties file |
| try { |
| String valueStr = ServicePlugin.getDefault().getPreferenceStore() |
| .getString(DISABLE_VERSION_CHECKING_PREF); |
| versionCheckingDisabled = Boolean.valueOf(valueStr).booleanValue(); |
| } catch (MissingResourceException e) { |
| versionCheckingDisabled = false; |
| } |
| |
| // Process the "org.eclipse.epf.common.version" extension point |
| // contributors. |
| IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry(); |
| IExtensionPoint extensionPoint = extensionRegistry.getExtensionPoint( |
| EXTENSION_POINT_NAMESPACE, EXTENSION_POINT_NAME); |
| if (extensionPoint != null) { |
| IExtension[] extensions = extensionPoint.getExtensions(); |
| for (int i = 0; i < extensions.length; i++) { |
| IExtension extension = extensions[i]; |
| initExtension(extension); |
| } |
| } |
| |
| } |
| |
| protected static void initExtension(IExtension extension) { |
| String extensionID = extension.getSimpleIdentifier(); |
| String pluginId = extension.getNamespaceIdentifier(); |
| Bundle bundle = Platform.getBundle(pluginId); |
| IConfigurationElement[] configElements = extension |
| .getConfigurationElements(); |
| for (int j = 0; j < configElements.length; j++) { |
| IConfigurationElement configElement = configElements[j]; |
| try { |
| if (EXTENSION_VERSIONS_INFO.equals(configElement.getName())) { |
| String className = configElement.getAttribute("class"); //$NON-NLS-1$ |
| if (className != null) { |
| versions.put(extensionID, (EPFVersions) bundle |
| .loadClass(className).newInstance()); |
| break; |
| } |
| } |
| if (EXTENSION_LIB_EXTENSION_CHECK.equals(configElement |
| .getName())) { |
| String className = configElement.getAttribute("class"); //$NON-NLS-1$ |
| if (className != null) { |
| libExtCheckers.put(extensionID, |
| (ILibraryExtensionVersionCheck) bundle |
| .loadClass(className).newInstance()); |
| break; |
| } |
| } |
| } catch (Exception e) { |
| ServicePlugin.getDefault().getLogger().logError(e); |
| } |
| } |
| } |
| |
| /** |
| * |
| * @return the map of Tool IDs-to-Versions class |
| */ |
| public static Map getVersionsMap() { |
| return Collections.unmodifiableMap(versions); |
| } |
| |
| /** |
| * |
| * @return a Set of all known Tool IDs |
| */ |
| public static Set<String> getAllToolIDs() { |
| return Collections.unmodifiableSet(versions.keySet()); |
| } |
| |
| /** |
| * |
| * @param toolID |
| * @return The Versions class for the given Tool ID |
| */ |
| public static EPFVersions getVersions(String toolID) { |
| return (EPFVersions) versions.get(toolID); |
| } |
| |
| /** |
| * |
| * @return true iff version checking is disabled |
| */ |
| public static boolean isVersionCheckingDisabled() { |
| return versionCheckingDisabled; |
| } |
| |
| public static final Pattern p_XMIVersionPattern = Pattern.compile( |
| "(\\w+?):version=\"(.+?)\"", Pattern.DOTALL); //$NON-NLS-1$ |
| |
| public static final Pattern p_XMLVersionAttributePattern = Pattern.compile( |
| "tool=\"(.*?)\"", Pattern.DOTALL); //$NON-NLS-1$ |
| |
| public static final Pattern p_XMI_ELEMENT_START_TAG = Pattern |
| .compile("<?xml version=\".+?\" encoding=\".+?\"?>"); //$NON-NLS-1$ |
| |
| public static final String XML_ELEMENT_END_TAG = ">"; //$NON-NLS-1$ |
| |
| public static final String XMI_ATTRIBUTE_TAG = "xmi"; //$NON-NLS-1$ |
| |
| public static final String XML_ELEMENT_START_TAG = "<uma:MethodLibrary"; //$NON-NLS-1$ |
| |
| public static final String XML_VERSIONS_SEPARATOR = ";"; //$NON-NLS-1$ |
| |
| public static final String XML_TOOL_VERSION_SEPARATOR = "="; //$NON-NLS-1$ |
| |
| /** |
| * Given an XML file, will read the tool="foo=a.b.c.d;bar=w.x.y.z" |
| * attributes and return a map of the id-to-versions. |
| * |
| * @param xmlFile |
| * file to process |
| * @return null if no versions found; a map of the id-to-versions otherwise |
| */ |
| protected static Map readVersionsFromXMLFile(File xmlFile) { |
| Map<String, String> versions = new LinkedHashMap<String, String>(); |
| StringBuffer buf = null; |
| try { |
| buf = FileUtil.readFile(xmlFile, FileUtil.ENCODING_UTF_8); |
| } catch (Exception ex) { |
| ServicePlugin.getDefault().getLogger().logError(ex); |
| } |
| if (buf != null) { |
| int xmiElementStartIdx = buf.indexOf(XML_ELEMENT_START_TAG); |
| if (xmiElementStartIdx != -1) { |
| int xmiElementEndIdx = buf.indexOf(XML_ELEMENT_END_TAG, |
| xmiElementStartIdx + XML_ELEMENT_START_TAG.length()); |
| if (xmiElementEndIdx != -1) { |
| String rootElement = buf.substring(xmiElementStartIdx, |
| xmiElementEndIdx); |
| Matcher mAttribute = p_XMLVersionAttributePattern |
| .matcher(rootElement); |
| if (mAttribute.find()) { |
| String toolsAttribute = mAttribute.group(1); |
| if (toolsAttribute != null |
| && toolsAttribute.length() > 0) { |
| String[] versionsArray = StrUtil.split( |
| toolsAttribute, XML_VERSIONS_SEPARATOR); |
| for (int i = 0; i < versionsArray.length; i++) { |
| if (versionsArray[i] != null |
| && versionsArray[i].length() > 0) { |
| String[] versionInfoArray = StrUtil.split( |
| versionsArray[i], |
| XML_TOOL_VERSION_SEPARATOR); |
| if (versionInfoArray.length != 2) |
| continue; |
| String toolID = versionInfoArray[0]; |
| String toolVersion = versionInfoArray[1]; |
| if (toolID != null |
| && toolID.trim().length() > 0 |
| && toolVersion != null |
| && toolVersion.trim().length() > 0) |
| versions.put(toolID, toolVersion); |
| } |
| } |
| } |
| } |
| } |
| } |
| } |
| if (versions.size() == 0) { |
| return null; |
| } else { |
| return versions; |
| } |
| } |
| |
| /** |
| * Given an XMI file, will read the foo:version="x.x.x" attributes and |
| * return a map of the id-to-versions. |
| * |
| * @param xmlFile |
| * file to process |
| * @return null if no versions found; a map of the id-to-versions otherwise |
| */ |
| protected static Map readVersionsFromXMIFile(File xmiFile) { |
| Map<String, String> versions = new LinkedHashMap<String, String>(); |
| StringBuffer buf = null; |
| try { |
| buf = FileUtil.readFile(xmiFile, FileUtil.ENCODING_UTF_8); |
| } catch (Exception ex) { |
| ServicePlugin.getDefault().getLogger().logError(ex); |
| } |
| if (buf != null) { |
| Matcher docStartMatcher = p_XMI_ELEMENT_START_TAG.matcher(buf); |
| if (docStartMatcher.find()) { |
| int docHeaderEndIdx = docStartMatcher.end(); |
| int xmiElementEndIdx = buf.indexOf(XML_ELEMENT_END_TAG, |
| docHeaderEndIdx); |
| if (xmiElementEndIdx != -1) { |
| String rootElement = buf.substring(docHeaderEndIdx, |
| xmiElementEndIdx + 1); |
| Matcher m = p_XMIVersionPattern.matcher(rootElement); |
| while (m.find()) { |
| String toolID = m.group(1); |
| if (toolID.equals(XMI_ATTRIBUTE_TAG)) |
| continue; |
| String toolVersion = m.group(2); |
| if (toolID != null && toolID.trim().length() > 0 |
| && toolVersion != null |
| && toolVersion.trim().length() > 0) |
| versions.put(toolID, toolVersion); |
| } |
| } |
| } |
| } |
| if (versions.size() == 0) { |
| return null; |
| } else { |
| return versions; |
| } |
| } |
| |
| /** |
| * Given a file, will read version information and return a map of the |
| * id-to-versions. |
| * |
| * @param file |
| * file to process |
| * @return null if no versions found; a map of the id-to-versions otherwise |
| */ |
| public static Map readVersionsFromFile(File file) { |
| if (file.getName().toUpperCase().endsWith("XMI")) { //$NON-NLS-1$ |
| return readVersionsFromXMIFile(file); |
| } else if (file.getName().toUpperCase().endsWith("XML")) { //$NON-NLS-1$ |
| return readVersionsFromXMLFile(file); |
| } else { |
| Map versions = readVersionsFromXMIFile(file); |
| if (versions != null) |
| return versions; |
| versions = readVersionsFromXMLFile(file); |
| if (versions != null) |
| return versions; |
| } |
| return null; |
| } |
| |
| /** |
| * Given a file, will compare with current XML Schema version. |
| * |
| * @param file |
| * @return null if file tool version can not be found; a VersionCheckInfo |
| * object otherwise |
| */ |
| public static VersionCheckInfo checkXMLVersion(File file) { |
| Map versionMap = VersionUtil.readVersionsFromFile(file); |
| if (versionMap == null) { |
| return null; |
| } else { |
| VersionCheckInfo vci = null; |
| for (Iterator iter = toolIDsCheckList.iterator(); iter.hasNext();) { |
| String toolID = (String) iter.next(); |
| if (versionMap.get(toolID) != null) { |
| String toolVersion = (String) versionMap.get(toolID); |
| vci = _checkXMLVersion(toolID, toolVersion); |
| if (vci != null) |
| return vci; |
| } |
| } |
| } |
| return null; |
| } |
| |
| private static VersionCheckInfo _checkXMLVersion(String toolID, |
| String toolVersion) { |
| // get the class that stores all the version info for this tool ID |
| EPFVersions versions = getVersions(toolID); |
| if (versions != null) { |
| EPFVersion minCurrVersion = versions |
| .getMinToolVersionForCurrentXMLSchemaVersion(); |
| int result = minCurrVersion.compareToolVersionTo(new Version( |
| toolVersion)); |
| String currentMinToolVersion = minCurrVersion.getToolVersion() |
| .toString(); |
| return new VersionCheckInfo(toolID, toolVersion, |
| currentMinToolVersion, -result); |
| } |
| return null; |
| } |
| |
| /** |
| * Given a file, compares with current library schema version |
| * |
| * @param file |
| * @return null if file tool version can not be found; a VersionCheckInfo |
| * object otherwise |
| */ |
| public static VersionCheckInfo checkLibraryVersion(File file) { |
| if (file.getName().equals("library.xmi")) { //$NON-NLS-1$ |
| // check library extensions first |
| for (Iterator iter = toolIDsCheckList.iterator(); iter.hasNext();) { |
| String toolID = (String) iter.next(); |
| if (libExtCheckers.get(toolID) != null) { |
| VersionCheckInfo vci = null; |
| ILibraryExtensionVersionCheck extCheck = (ILibraryExtensionVersionCheck) libExtCheckers |
| .get(toolID); |
| vci = extCheck.checkLibraryVersion(file.getParentFile()); |
| if (vci != null) |
| return vci; |
| } |
| } |
| } |
| Map versionMap = VersionUtil.readVersionsFromFile(file); |
| if (versionMap == null) { |
| return null; |
| } else { |
| VersionCheckInfo vci = null; |
| for (Iterator iter = toolIDsCheckList.iterator(); iter.hasNext();) { |
| String toolID = (String) iter.next(); |
| if (versionMap.get(toolID) != null) { |
| String toolVersion = (String) versionMap.get(toolID); |
| vci = _checkLibVersion(toolID, toolVersion); |
| if (vci != null) |
| return vci; |
| } |
| } |
| } |
| return null; |
| } |
| |
| private static VersionCheckInfo _checkLibVersion(String toolID, |
| String toolVersion) { |
| // get the class that stores all the version info for this tool ID |
| EPFVersions versions = getVersions(toolID); |
| if (versions != null) { |
| EPFVersion minCurrVersion = versions |
| .getMinToolVersionForCurrentLibraryVersion(); |
| int result = minCurrVersion.compareToolVersionTo(new Version( |
| toolVersion)); |
| String currentMinToolVersion = minCurrVersion.getToolVersion() |
| .toString(); |
| return new VersionCheckInfo(toolID, toolVersion, |
| currentMinToolVersion, -result); |
| } |
| return null; |
| } |
| |
| /** |
| * |
| * @return the first toolID that is checked. In most cases, the ID of the |
| * currently running application |
| */ |
| public static String getPrimaryToolID() { |
| return (String) toolIDsCheckList.get(0); |
| } |
| |
| /** |
| * Adds a tool ID to the order of tools to check. |
| * |
| * @param toolID |
| * toolID to add |
| * @param toolIDfollowing |
| * if null, adds toolID to front of list. otherwise, adds toolID |
| * before the specified ID |
| * @return false iff toolIDfollowing is not null and could not be found in |
| * list; true otherwise |
| */ |
| public static boolean addToolID(String toolID, String toolIDfollowing) { |
| if (toolIDfollowing != null) { |
| int idx = toolIDsCheckList.indexOf(toolIDfollowing); |
| if (idx != -1) { |
| toolIDsCheckList.add(idx, toolID); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| toolIDsCheckList.add(0, toolID); |
| return true; |
| } |
| |
| } |