/******************************************************************************* * Copyright (c) 2007, 2010 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.equinox.internal.frameworkadmin.utils; import java.io.*; import java.net.*; import java.text.SimpleDateFormat; import java.util.*; import java.util.jar.JarFile; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; import org.eclipse.core.runtime.*; import org.eclipse.equinox.frameworkadmin.BundleInfo; import org.eclipse.osgi.service.pluginconversion.PluginConversionException; import org.eclipse.osgi.service.pluginconversion.PluginConverter; import org.eclipse.osgi.util.ManifestElement; import org.osgi.framework.BundleException; import org.osgi.framework.Constants; public class Utils { private static final String FEATURE_MANIFEST = "feature.xml"; //$NON-NLS-1$ private static final String FILE_SCHEME = "file"; //$NON-NLS-1$ private static final String FRAGMENT_MANIFEST = "fragment.xml"; //$NON-NLS-1$ private static final String PATH_SEP = "/"; //$NON-NLS-1$ private static final String PLUGIN_MANIFEST = "plugin.xml"; //$NON-NLS-1$ /** * Overwrite all properties of from to the properties of to. Return the result of to. * * @param to Properties whose keys and values of other Properties will be appended to. * @param from Properties whose keys and values will be set to the other properties. * @return Properties as a result of this method. */ public static Properties appendProperties(Properties to, Properties from) { if (from != null) { if (to == null) to = new Properties(); // printoutProperties(System.out, "to", to); // printoutProperties(System.out, "from", from); for (Enumeration enumeration = from.keys(); enumeration.hasMoreElements();) { String key = (String) enumeration.nextElement(); to.setProperty(key, from.getProperty(key)); } } // printoutProperties(System.out, "to", to); return to; } //Return a dictionary representing a manifest. The data may result from plugin.xml conversion private static Dictionary basicLoadManifest(File bundleLocation) { InputStream manifestStream = null; ZipFile jarFile = null; try { try { // Handle a JAR'd bundle if (bundleLocation.isFile()) { jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ); ZipEntry manifestEntry = jarFile.getEntry(JarFile.MANIFEST_NAME); if (manifestEntry != null) { manifestStream = jarFile.getInputStream(manifestEntry); } } else { // we have a directory-based bundle File bundleManifestFile = new File(bundleLocation, JarFile.MANIFEST_NAME); if (bundleManifestFile.exists()) manifestStream = new BufferedInputStream(new FileInputStream(new File(bundleLocation, JarFile.MANIFEST_NAME))); } } catch (IOException e) { //ignore } // we were unable to get an OSGi manifest file so try and convert an old-style manifest if (manifestStream == null) return convertPluginManifest(bundleLocation, true); try { Map manifest = ManifestElement.parseBundleManifest(manifestStream, null); // add this check to handle the case were we read a non-OSGi manifest if (manifest.get(Constants.BUNDLE_SYMBOLICNAME) == null) return convertPluginManifest(bundleLocation, true); return manifestToProperties(manifest); } catch (IOException ioe) { return null; } catch (BundleException e) { return null; } } finally { try { if (manifestStream != null) manifestStream.close(); } catch (IOException e1) { //Ignore } try { if (jarFile != null) jarFile.close(); } catch (IOException e2) { //Ignore } } } public static void checkAbsoluteDir(File file, String dirName) throws IllegalArgumentException { if (file == null) throw new IllegalArgumentException(dirName + " is null"); if (!file.isAbsolute()) throw new IllegalArgumentException(dirName + " is not absolute path. file=" + file.getAbsolutePath()); if (!file.isDirectory()) throw new IllegalArgumentException(dirName + " is not directory. file=" + file.getAbsolutePath()); } public static void checkAbsoluteFile(File file, String dirName) {//throws ManipulatorException { if (file == null) throw new IllegalArgumentException(dirName + " is null"); if (!file.isAbsolute()) throw new IllegalArgumentException(dirName + " is not absolute path. file=" + file.getAbsolutePath()); if (file.isDirectory()) throw new IllegalArgumentException(dirName + " is not file but directory"); } public static URL checkFullUrl(URL url, String urlName) throws IllegalArgumentException {//throws ManipulatorException { if (url == null) throw new IllegalArgumentException(urlName + " is null"); if (!url.getProtocol().endsWith("file")) //$NON-NLS-1$ return url; File file = new File(url.getFile()); if (!file.isAbsolute()) throw new IllegalArgumentException(urlName + "(" + url + ") does not have absolute path"); if (file.getAbsolutePath().startsWith(PATH_SEP)) return url; try { return getUrl("file", null, PATH_SEP + file.getAbsolutePath()); //$NON-NLS-1$ } catch (MalformedURLException e) { throw new IllegalArgumentException(urlName + "(" + "file:" + PATH_SEP + file.getAbsolutePath() + ") is not fully quallified"); } } /* * Copied from BundleDescriptionFactory in the metadata generator. */ private static Dictionary convertPluginManifest(File bundleLocation, boolean logConversionException) { PluginConverter converter; try { converter = org.eclipse.equinox.internal.frameworkadmin.utils.Activator.acquirePluginConverter(); if (converter == null) { new RuntimeException("Unable to aquire PluginConverter service during generation for: " + bundleLocation).printStackTrace(); //$NON-NLS-1$ return null; } return converter.convertManifest(bundleLocation, false, null, true, null); } catch (PluginConversionException convertException) { // only log the exception if we had a plugin.xml or fragment.xml and we failed conversion if (bundleLocation.getName().equals(FEATURE_MANIFEST)) return null; if (!new File(bundleLocation, PLUGIN_MANIFEST).exists() && !new File(bundleLocation, FRAGMENT_MANIFEST).exists()) return null; if (logConversionException) { IStatus status = new Status(IStatus.WARNING, "org.eclipse.equinox.frameworkadmin", 0, "Error converting bundle manifest.", convertException); System.out.println(status); //TODO Need to find a way to get a logging service to log } return null; } } public static boolean createParentDir(File file) { File parent = file.getParentFile(); if (parent == null) return false; if (parent.exists()) return true; return parent.mkdirs(); } public static BundleInfo[] getBundleInfosFromList(List list) { if (list == null) return new BundleInfo[0]; BundleInfo[] ret = new BundleInfo[list.size()]; list.toArray(ret); return ret; } public static String[] getClauses(String header) { StringTokenizer token = new StringTokenizer(header, ","); //$NON-NLS-1$ List list = new LinkedList(); while (token.hasMoreTokens()) { list.add(token.nextToken()); } String[] ret = new String[list.size()]; list.toArray(ret); return ret; } public static String[] getClausesManifestMainAttributes(URI location, String name) { return getClauses(getManifestMainAttributes(location, name)); } public static String getManifestMainAttributes(URI location, String name) { Dictionary manifest = Utils.getOSGiManifest(location); if (manifest == null) throw new RuntimeException("Unable to locate bundle manifest: " + location); return (String) manifest.get(name); } public static Dictionary getOSGiManifest(URI location) { if (location == null) return null; // if we have a file-based URL that doesn't end in ".jar" then... if (FILE_SCHEME.equals(location.getScheme())) return basicLoadManifest(URIUtil.toFile(location)); try { URL url = new URL("jar:" + location.toString() + "!/"); //$NON-NLS-1$//$NON-NLS-2$ JarURLConnection jarConnection = (JarURLConnection) url.openConnection(); ZipFile jar = jarConnection.getJarFile(); try { ZipEntry entry = jar.getEntry(JarFile.MANIFEST_NAME); if (entry == null) return null; Map manifest = ManifestElement.parseBundleManifest(jar.getInputStream(entry), null); // if we have a JAR'd bundle that has a non-OSGi manifest file (like // the ones produced by Ant, then try and convert the plugin.xml if (manifest.get(Constants.BUNDLE_SYMBOLICNAME) == null) { String jarName = jar.getName(); File file = jarName != null ? new File(jarName) : null; if (file != null && file.exists()) { return convertPluginManifest(file, true); } return null; } return manifestToProperties(manifest); } catch (BundleException e) { return null; } finally { jar.close(); } } catch (IOException e) { if (System.getProperty("osgi.debug") != null) { System.err.println("location=" + location); e.printStackTrace(); } } return null; } public static String getPathFromClause(String clause) { if (clause == null) return null; if (clause.indexOf(";") != -1) clause = clause.substring(0, clause.indexOf(";")); return clause.trim(); } public static String getRelativePath(File target, File from) { String targetPath = Utils.replaceAll(target.getAbsolutePath(), File.separator, PATH_SEP); String fromPath = Utils.replaceAll(from.getAbsolutePath(), File.separator, PATH_SEP); String[] targetTokens = Utils.getTokens(targetPath, PATH_SEP); String[] fromTokens = Utils.getTokens(fromPath, PATH_SEP); int index = -1; for (int i = 0; i < fromTokens.length; i++) if (fromTokens[i].equals(targetTokens[i])) index = i; else break; StringBuffer sb = new StringBuffer(); for (int i = index + 1; i < fromTokens.length; i++) sb.append(".." + PATH_SEP); for (int i = index + 1; i < targetTokens.length; i++) if (i != targetTokens.length - 1) sb.append(targetTokens[i] + PATH_SEP); else sb.append(targetTokens[i]); return sb.toString(); } /** * This method will be called for create a backup file. * * @param file target file * @return File backup file whose filename consists of "hogehoge.yyyyMMddHHmmss.ext" or * "hogehoge.yyyyMMddHHmmss". */ public static File getSimpleDataFormattedFile(File file) { SimpleDateFormat df = new SimpleDateFormat("yyyyMMddHHmmss"); //$NON-NLS-1$ String date = df.format(new Date()); String filename = file.getName(); int index = filename.lastIndexOf("."); //$NON-NLS-1$ if (index != -1) filename = filename.substring(0, index) + "." + date + "." + filename.substring(index + 1); //$NON-NLS-1$ //$NON-NLS-2$ else filename = filename + "." + date; //$NON-NLS-1$ File dest = new File(file.getParentFile(), filename); return dest; } public static String[] getTokens(String msg, String delim) { return getTokens(msg, delim, false); } public static String[] getTokens(String msg, String delim, boolean returnDelims) { StringTokenizer targetST = new StringTokenizer(msg, delim, returnDelims); String[] tokens = new String[targetST.countTokens()]; ArrayList list = new ArrayList(targetST.countTokens()); while (targetST.hasMoreTokens()) { list.add(targetST.nextToken()); } list.toArray(tokens); return tokens; } public static URL getUrl(String protocol, String host, String file) throws MalformedURLException {// throws ManipulatorException { file = Utils.replaceAll(file, File.separator, "/"); return new URL(protocol, host, file); } public static URL getUrlInFull(String path, URL from) throws MalformedURLException {//throws ManipulatorException { Utils.checkFullUrl(from, "from"); path = Utils.replaceAll(path, File.separator, "/"); //$NON-NLS-1$ //System.out.println("from.toExternalForm()=" + from.toExternalForm()); String fromSt = Utils.removeLastCh(from.toExternalForm(), '/'); //System.out.println("fromSt=" + fromSt); if (path.startsWith("/")) { //$NON-NLS-1$ String fileSt = from.getFile(); return new URL(fromSt.substring(0, fromSt.lastIndexOf(fileSt) - 1) + path); } return new URL(fromSt + "/" + path); //$NON-NLS-1$ } private static Properties manifestToProperties(Map d) { Iterator iter = d.keySet().iterator(); Properties result = new Properties(); while (iter.hasNext()) { String key = (String) iter.next(); result.put(key, d.get(key)); } return result; } /** * Just used for debug. * * @param ps printstream * @param name name of properties * @param props properties whose keys and values will be printed out. */ public static void printoutProperties(PrintStream ps, String name, Properties props) { if (props == null || props.size() == 0) { ps.println("Props(" + name + ") is empty"); return; } ps.println("Props(" + name + ")="); for (Enumeration enumeration = props.keys(); enumeration.hasMoreElements();) { String key = (String) enumeration.nextElement(); ps.print("\tkey=" + key); ps.println("\tvalue=" + props.getProperty(key)); } } public static String removeLastCh(String target, char ch) { while (target.charAt(target.length() - 1) == ch) { target = target.substring(0, target.length() - 1); } return target; } public static String replaceAll(String st, String oldSt, String newSt) { if (oldSt.equals(newSt)) return st; int index = -1; while ((index = st.indexOf(oldSt)) != -1) { st = st.substring(0, index) + newSt + st.substring(index + oldSt.length()); } return st; } /** * Sort by increasing order of startlevels. * * @param bInfos array of BundleInfos to be sorted. * @param initialBSL initial bundle start level to be used. * @return sorted array of BundleInfos */ public static BundleInfo[] sortBundleInfos(BundleInfo[] bInfos, int initialBSL) { SortedMap bslToList = new TreeMap(); for (int i = 0; i < bInfos.length; i++) { Integer sL = new Integer(bInfos[i].getStartLevel()); if (sL.intValue() == BundleInfo.NO_LEVEL) sL = new Integer(initialBSL); List list = (List) bslToList.get(sL); if (list == null) { list = new LinkedList(); bslToList.put(sL, list); } list.add(bInfos[i]); } // bslToList is sorted by the key (StartLevel). List bundleInfoList = new LinkedList(); for (Iterator ite = bslToList.keySet().iterator(); ite.hasNext();) { Integer sL = (Integer) ite.next(); List list = (List) bslToList.get(sL); for (Iterator ite2 = list.iterator(); ite2.hasNext();) { BundleInfo bInfo = (BundleInfo) ite2.next(); bundleInfoList.add(bInfo); } } return getBundleInfosFromList(bundleInfoList); } /** * get String representing the given properties. * * @param name name of properties * @param props properties whose keys and values will be printed out. */ public static String toStringProperties(String name, Properties props) { if (props == null || props.size() == 0) { return "Props(" + name + ") is empty\n"; } StringBuffer sb = new StringBuffer(); sb.append("Props(" + name + ") is \n"); for (Enumeration enumeration = props.keys(); enumeration.hasMoreElements();) { String key = (String) enumeration.nextElement(); sb.append("\tkey=" + key + "\tvalue=" + props.getProperty(key) + "\n"); } return sb.toString(); } }