| /******************************************************************************* |
| * Copyright (c) 2007, 2008 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.p2.publisher; |
| |
| import java.io.*; |
| 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.internal.p2.core.helpers.LogHelper; |
| import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper; |
| import org.eclipse.osgi.service.pluginconversion.PluginConversionException; |
| import org.eclipse.osgi.service.pluginconversion.PluginConverter; |
| import org.eclipse.osgi.service.resolver.*; |
| import org.eclipse.osgi.util.ManifestElement; |
| import org.eclipse.osgi.util.NLS; |
| import org.osgi.framework.BundleContext; |
| import org.osgi.framework.BundleException; |
| |
| public class BundleDescriptionFactory { |
| public static final String DIR = "dir"; //$NON-NLS-1$ |
| public static final String JAR = "jar"; //$NON-NLS-1$ |
| private static final String FEATURE_FILENAME_DESCRIPTOR = "feature.xml"; //$NON-NLS-1$ |
| private static final String PLUGIN_FILENAME_DESCRIPTOR = "plugin.xml"; //$NON-NLS-1$ |
| private static final String FRAGMENT_FILENAME_DESCRIPTOR = "fragment.xml"; //$NON-NLS-1$ |
| |
| public static String BUNDLE_SHAPE = "Eclipse-BundleShape"; //$NON-NLS-1$ |
| |
| // static final String DEFAULT_BUNDLE_LOCALIZATION = "plugin"; //$NON-NLS-1$ |
| // static final String PROPERTIES_FILE_EXTENSION = ".properties"; //$NON-NLS-1$ |
| // static final String MANIFEST_LOCALIZATIONS = "eclipse.p2.manifest.localizations"; //$NON-NLS-1$ |
| // |
| // static final Locale DEFAULT_LOCALE = new Locale("df", "LT"); //$NON-NLS-1$//$NON-NLS-2$ |
| // static final Locale PSEUDO_LOCALE = new Locale("zz", "ZZ"); //$NON-NLS-1$//$NON-NLS-2$ |
| |
| StateObjectFactory factory; |
| State state; |
| |
| public static BundleDescriptionFactory getBundleDescriptionFactory(BundleContext context) { |
| PlatformAdmin platformAdmin = (PlatformAdmin) ServiceHelper.getService(context, PlatformAdmin.class.getName()); |
| if (platformAdmin == null) |
| throw new IllegalStateException("PlatformAdmin not registered."); //$NON-NLS-1$ |
| return new BundleDescriptionFactory(platformAdmin.getFactory(), null); |
| } |
| |
| public BundleDescriptionFactory(StateObjectFactory factory, State state) { |
| this.factory = factory; |
| this.state = state; |
| //TODO find a state and a factory when not provided |
| } |
| |
| private static PluginConverter acquirePluginConverter() { |
| return (PluginConverter) ServiceHelper.getService(Activator.getContext(), PluginConverter.class.getName()); |
| } |
| |
| private static Dictionary convertPluginManifest(File bundleLocation, boolean logConversionException) { |
| PluginConverter converter; |
| try { |
| converter = acquirePluginConverter(); |
| if (converter == null) { |
| LogHelper.log(new Status(IStatus.ERROR, Activator.ID, "Unable to aquire PluginConverter service during generation for: " + bundleLocation)); |
| 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_FILENAME_DESCRIPTOR)) |
| return null; |
| if (!new File(bundleLocation, PLUGIN_FILENAME_DESCRIPTOR).exists() && !new File(bundleLocation, FRAGMENT_FILENAME_DESCRIPTOR).exists()) |
| return null; |
| if (logConversionException) { |
| IStatus status = new Status(IStatus.WARNING, Activator.ID, 0, NLS.bind(Messages.exception_errorConverting, bundleLocation.getAbsolutePath()), convertException); |
| LogHelper.log(status); |
| } |
| return null; |
| } |
| } |
| |
| public BundleDescription getBundleDescription(Dictionary enhancedManifest, File bundleLocation) { |
| try { |
| BundleDescription descriptor = factory.createBundleDescription(state, enhancedManifest, bundleLocation != null ? bundleLocation.getAbsolutePath() : null, 1); //TODO Do we need to have a real bundle id |
| descriptor.setUserObject(enhancedManifest); |
| return descriptor; |
| } catch (BundleException e) { |
| String message = NLS.bind(Messages.exception_stateAddition, bundleLocation == null ? null : bundleLocation.getAbsoluteFile()); |
| IStatus status = new Status(IStatus.WARNING, Activator.ID, message, e); |
| LogHelper.log(status); |
| return null; |
| } |
| } |
| |
| public BundleDescription getBundleDescription(File bundleLocation) { |
| Dictionary manifest = loadManifest(bundleLocation); |
| if (manifest == null) |
| return null; |
| return getBundleDescription(manifest, bundleLocation); |
| } |
| |
| public BundleDescription getBundleDescription(InputStream manifestStream, File bundleLocation) { |
| Hashtable entries = new Hashtable(); |
| try { |
| ManifestElement.parseBundleManifest(manifestStream, entries); |
| return getBundleDescription(entries, bundleLocation); |
| } catch (IOException e) { |
| String message = "An error occurred while reading the bundle description."; |
| IStatus status = new Status(IStatus.ERROR, Activator.ID, message, e); |
| LogHelper.log(status); |
| } catch (BundleException e) { |
| String message = "An error occurred while reading the bundle description."; |
| IStatus status = new Status(IStatus.ERROR, Activator.ID, message, e); |
| LogHelper.log(status); |
| } |
| return null; |
| } |
| |
| public static Dictionary loadManifest(File bundleLocation) { |
| InputStream manifestStream = null; |
| ZipFile jarFile = null; |
| try { |
| if ("jar".equalsIgnoreCase(new Path(bundleLocation.getName()).getFileExtension()) && bundleLocation.isFile()) { //$NON-NLS-1$ |
| jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ); |
| ZipEntry manifestEntry = jarFile.getEntry(JarFile.MANIFEST_NAME); |
| if (manifestEntry != null) { |
| manifestStream = jarFile.getInputStream(manifestEntry); |
| } |
| } else { |
| File manifestFile = new File(bundleLocation, JarFile.MANIFEST_NAME); |
| if (manifestFile.exists()) |
| manifestStream = new BufferedInputStream(new FileInputStream(manifestFile)); |
| } |
| } catch (IOException e) { |
| //ignore but log |
| LogHelper.log(new Status(IStatus.WARNING, Activator.ID, "An error occurred while loading the bundle manifest.", e)); |
| } |
| |
| Dictionary manifest = null; |
| if (manifestStream != null) { |
| try { |
| Map manifestMap = ManifestElement.parseBundleManifest(manifestStream, null); |
| // TODO temporary hack. We are reading a Map but everyone wants a Dictionary so convert. |
| // real answer is to have people expect a Map but that is a wider change. |
| manifest = new Hashtable(manifestMap); |
| } catch (IOException e) { |
| LogHelper.log(new Status(IStatus.ERROR, Activator.ID, "An error occurred while loading the bundle manifest.", e)); |
| return null; |
| } catch (BundleException e) { |
| LogHelper.log(new Status(IStatus.ERROR, Activator.ID, "An error occurred while loading the bundle manifest.", e)); |
| return null; |
| } finally { |
| try { |
| if (jarFile != null) |
| jarFile.close(); |
| } catch (IOException e2) { |
| //Ignore |
| } |
| } |
| } else { |
| manifest = convertPluginManifest(bundleLocation, true); |
| } |
| |
| if (manifest == null) |
| return null; |
| |
| //Deal with the pre-3.0 plug-in shape who have a default jar manifest.mf |
| if (manifest.get(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME) == null) |
| manifest = convertPluginManifest(bundleLocation, true); |
| |
| if (manifest == null) |
| return null; |
| // if the bundle itself does not define its shape, infer the shape from the current form |
| if (manifest.get(BUNDLE_SHAPE) == null) |
| manifest.put(BUNDLE_SHAPE, bundleLocation.isDirectory() ? DIR : JAR); |
| getManifestLocalizations(manifest, bundleLocation); |
| // localizeManifest(manifest, bundleLocation); |
| return manifest; |
| } |
| |
| // private Properties loadProperties(File bundleLocation, String localizationFile) throws IOException { |
| // Properties result = new Properties(); |
| // InputStream propertyStream = null; |
| // try { |
| // try { |
| // if (bundleLocation.isDirectory()) |
| // propertyStream = new FileInputStream(new File(bundleLocation, localizationFile)); |
| // else { |
| // URLConnection connection = new URL("jar:" + bundleLocation.toURL().toExternalForm() + "!/" + localizationFile).openConnection(); //$NON-NLS-1$ //$NON-NLS-2$ |
| // connection.setUseCaches(false); |
| // propertyStream = connection.getInputStream(); |
| // } |
| // } catch (FileNotFoundException e) { |
| // // if there is no messages file then just return; |
| // return result; |
| // } |
| // result.load(propertyStream); |
| // } finally { |
| // if (propertyStream != null) |
| // propertyStream.close(); |
| // } |
| // return result; |
| // } |
| |
| // Collect the manifest localizations from the bundle directory |
| // and store them in the manifest. |
| private static void getManifestLocalizations(Dictionary manifest, File bundleLocation) { |
| // Map localizations; |
| // Locale defaultLocale = null; // = Locale.ENGLISH; // TODO: get this from GeneratorInfo |
| // String bundleLocalization = (String) manifest.get(Constants.BUNDLE_LOCALIZATION); |
| // if (bundleLocalization == null || bundleLocalization.trim().length() == 0) |
| // bundleLocalization = DEFAULT_BUNDLE_LOCALIZATION; |
| // |
| // if ("jar".equalsIgnoreCase(new Path(bundleLocation.getName()).getFileExtension()) && //$NON-NLS-1$ |
| // bundleLocation.isFile()) { |
| // localizations = getJarManifestLocalization(bundleLocation, bundleLocalization, manifest, defaultLocale); |
| // } else { |
| // localizations = getDirManifestLocalization(bundleLocation, bundleLocalization, manifest, defaultLocale); |
| // } |
| // |
| // if (localizations.size() > 0) { |
| // manifest.put(MANIFEST_LOCALIZATIONS, localizations); |
| // } |
| } |
| |
| // private Map getJarManifestLocalization(File bundleLocation, String bundleLocalization, Dictionary manifest, Locale defaultLocale) { |
| // ZipFile jarFile = null; |
| // Map localizations = new HashMap(4); |
| // try { |
| // jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ); |
| // for (Enumeration entries = jarFile.entries(); entries.hasMoreElements();) { |
| // ZipEntry nextEntry = (ZipEntry) entries.nextElement(); |
| // String nextName = nextEntry.getName(); |
| // String localeString = getLocaleString(nextName, bundleLocalization); |
| // |
| // if (!nextEntry.isDirectory() && localeString != null) { |
| // Locale nextLocale = getLocale(localeString); |
| // InputStream stream = null; |
| // try { |
| // stream = jarFile.getInputStream(nextEntry); |
| // Properties properties = new Properties(); |
| // properties.load(stream); |
| // Properties localizedStrings = getLocalizedProperties(manifest, properties); |
| // if (localizedStrings.size() > 0) { |
| // localizations.put(nextLocale, localizedStrings); |
| // if (DEFAULT_LOCALE.equals(nextLocale) && defaultLocale != null) { |
| // localizations.put(nextLocale, localizedStrings); |
| // } |
| // } |
| // } finally { |
| // if (stream != null) |
| // stream.close(); |
| // } |
| // } |
| // } |
| // } catch (IOException ioe) { |
| // ioe.printStackTrace(); |
| // } finally { |
| // if (jarFile != null) { |
| // try { |
| // jarFile.close(); |
| // } catch (IOException ioe) { |
| // // do nothing |
| // } |
| // } |
| // } |
| // |
| // return localizations; |
| // } |
| // |
| // private Map getDirManifestLocalization(File bundleLocation, String bundleLocalization, Dictionary manifest, Locale defaultLocale) { |
| // File localizationPath = new File(bundleLocation, bundleLocalization); |
| // File localizationDir = localizationPath.getParentFile(); |
| // String localizationFile = localizationPath.getName(); |
| // String[] localizationFiles = localizationDir.list(new LocalizationFileFilter(localizationFile)); |
| // |
| // HashMap localizations = null; |
| // |
| // if (localizationFiles != null) { |
| // localizations = new HashMap(localizationFiles.length); |
| // for (int i = 0; i < localizationFiles.length; i++) { |
| // String nextFile = localizationFiles[i]; |
| // Locale nextLocale = getLocale(getLocaleString(nextFile, localizationFile)); |
| // |
| // try { |
| // Properties properties = loadProperties(bundleLocation, nextFile); |
| // Properties localizedStrings = getLocalizedProperties(manifest, properties); |
| // if (localizedStrings.size() > 0) { |
| // localizations.put(nextLocale, localizedStrings); |
| // if (DEFAULT_LOCALE.equals(nextLocale) && defaultLocale != null) { |
| // localizations.put(nextLocale, localizedStrings); |
| // } |
| // } |
| // } catch (IOException ioe) { |
| // ioe.printStackTrace(); |
| // } |
| // } |
| // } |
| // |
| // return localizations; |
| // } |
| |
| // private class LocalizationFileFilter implements FilenameFilter { |
| // |
| // String filenamePrefix; |
| // |
| // public LocalizationFileFilter(String filenamePrefix) { |
| // this.filenamePrefix = filenamePrefix; |
| // } |
| // |
| // /* (non-Javadoc) |
| // * @see java.io.FilenameFilter#accept(java.io.File, java.lang.String) |
| // */ |
| // public boolean accept(File directory, String filename) { |
| // return (getLocaleString(filename, filenamePrefix) != null ? true : false); |
| // } |
| // } |
| |
| // static public String getLocaleString(String filename, String filenamePrefix) { |
| // String localeString = null; |
| // if (filename.startsWith(filenamePrefix) && filename.endsWith(PROPERTIES_FILE_EXTENSION)) { |
| // if (filename.length() > filenamePrefix.length() + PROPERTIES_FILE_EXTENSION.length()) { |
| // localeString = filename.substring(filenamePrefix.length() + 1, filename.length() - PROPERTIES_FILE_EXTENSION.length()); |
| // } else { |
| // localeString = ""; //$NON-NLS-1$ |
| // } |
| // } |
| // return localeString; |
| // } |
| |
| // static private Locale getLocale(String localeString) { |
| // Locale locale = DEFAULT_LOCALE; |
| // if (localeString.length() == 5 && localeString.indexOf('_') == 2) { |
| // locale = new Locale(localeString.substring(0, 2), localeString.substring(3, 5)); |
| // } else if (localeString.length() == 2) { |
| // locale = new Locale(localeString.substring(0, 2)); |
| // } |
| // return locale; |
| // } |
| // |
| // static private Properties getLocalizedProperties(Dictionary manifest, Properties properties) { |
| // // Walk over the manifest and find all %xxx with the string value |
| // // in the properties file and copy them to the localized properties. |
| // Properties localizedProperties = new Properties(); |
| // for (Enumeration e = manifest.keys(); e.hasMoreElements();) { |
| // String key = (String) e.nextElement(); |
| // Object value = manifest.get(key); |
| // if (value instanceof String) { |
| // String stringValue = (String) value; |
| // if (stringValue.startsWith("%")) { //$NON-NLS-1$ |
| // String newValue = properties.getProperty(stringValue.substring(1)); |
| // if (newValue != null) |
| // localizedProperties.put(key, newValue); |
| // } |
| // } |
| // } |
| // return localizedProperties; |
| // } |
| |
| } |