blob: 355a907cec8bd24aa80721a58a77b8fd84dd8e71 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2003, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.core.runtime.adaptor;
import java.io.*;
import java.net.URL;
import java.util.*;
import org.eclipse.osgi.framework.adaptor.core.BundleEntry;
import org.eclipse.osgi.framework.internal.core.Constants;
import org.eclipse.osgi.framework.internal.defaultadaptor.DefaultAdaptor;
import org.eclipse.osgi.framework.internal.defaultadaptor.DefaultBundleData;
import org.eclipse.osgi.framework.util.Headers;
import org.eclipse.osgi.service.resolver.Version;
import org.eclipse.osgi.util.ManifestElement;
import org.osgi.framework.BundleException;
//TODO This class does not override save().
//Maybe for consistency should it be overriden to do nothing. See also EclipseAdaptor.saveMetadataFor(BundleData)
public class EclipseBundleData extends DefaultBundleData {
static final byte MANIFEST_TYPE_UNKNOWN = 0x00;
static final byte MANIFEST_TYPE_BUNDLE = 0x01;
static final byte MANIFEST_TYPE_PLUGIN = 0x02;
static final byte MANIFEST_TYPE_FRAGMENT = 0x04;
static final byte MANIFEST_TYPE_JAR = 0x08;
private static String[] libraryVariants = null;
/** data to detect modification made in the manifest */
private long manifestTimeStamp = 0;
private byte manifestType = MANIFEST_TYPE_UNKNOWN;
// URL protocol designations
public static final String PROTOCOL = "platform"; //$NON-NLS-1$
public static final String FILE = "file"; //$NON-NLS-1$
private static final String PROP_CHECK_CONFIG = "osgi.checkConfiguration"; //$NON-NLS-1$
protected String isLegacy = null;
protected String pluginClass = null;
private String autoStart;
private String autoStop;
private static String[] buildLibraryVariants() {
ArrayList result = new ArrayList();
EnvironmentInfo info = EnvironmentInfo.getDefault();
result.add("ws/" + info.getWS() + "/"); //$NON-NLS-1$ //$NON-NLS-2$
result.add("os/" + info.getOS() + "/" + info.getOSArch() + "/"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
result.add("os/" + info.getOS() + "/"); //$NON-NLS-1$ //$NON-NLS-2$
String nl = info.getNL();
nl = nl.replace('_', '/');
while (nl.length() > 0) {
result.add("nl/" + nl + "/"); //$NON-NLS-1$ //$NON-NLS-2$
int i = nl.lastIndexOf('/');
nl = (i < 0) ? "" : nl.substring(0, i); //$NON-NLS-1$
}
result.add(""); //$NON-NLS-1$
return (String[]) result.toArray(new String[result.size()]);
}
public EclipseBundleData(DefaultAdaptor adaptor, long id) throws IOException {
super(adaptor, id);
}
public void initializeExistingBundle() throws IOException {
File delete = new File(getBundleStoreDir(), ".delete");
/* and the directory is not marked for delete */
if (delete.exists())
throw new IOException();
createBaseBundleFile();
if (!checkManifestTimeStamp())
throw new IOException();
}
private boolean checkManifestTimeStamp() {
if (!"true".equalsIgnoreCase(System.getProperty(PROP_CHECK_CONFIG))) //$NON-NLS-1$
return true;
return PluginConverterImpl.getTimeStamp(getBaseFile(), getManifestType()) == getManifestTimeStamp();
}
/**
* Returns the absolute path name of a native library. The VM invokes this
* method to locate the native libraries that belong to classes loaded with
* this class loader. If this method returns <code>null</code>, the VM
* searches the library along the path specified as the <code>java.library.path</code>
* property.
*
* @param libname
* the library name
* @return the absolute path of the native library
*/
public String findLibrary(String libName) {
// first do the standard OSGi lookup using the native clauses
// in the manifest. If that fails, do the legacy Eclipse lookup.
String result = super.findLibrary(libName);
if (result != null)
return result;
if (libraryVariants == null)
libraryVariants = buildLibraryVariants();
if (libName.length() == 0)
return null;
if (libName.charAt(0) == '/' || libName.charAt(0) == '\\')
libName = libName.substring(1);
libName = System.mapLibraryName(libName);
// if (DEBUG && DEBUG_SHOW_ACTIONS && debugNative(libName))
// debug("findLibrary(" + libName + ")"); //$NON-NLS-1$ //$NON-NLS-2$
return searchVariants(libraryVariants, libName);
}
private String searchVariants(String[] variants, String path) {
for (int i = 0; i < variants.length; i++) {
BundleEntry libEntry = baseBundleFile.getEntry(variants[i] + path);
if (libEntry == null) {
// if (DEBUG && DEBUG_SHOW_FAILURE)
// debug("not found " + variants[i] + path);
// //$NON-NLS-1$
} else {
// if (DEBUG && DEBUG_SHOW_SUCCESS)
// debug("found " + path + " as " +
// variants[i] + path); //$NON-NLS-1$ //$NON-NLS-2$
File libFile = baseBundleFile.getFile(variants[i] + path);
return libFile.getAbsolutePath();
}
}
return null;
}
//TODO Unused method
private URL[] getSearchURLs(URL target) {
return new URL[] {target};
}
public synchronized Dictionary getManifest() {
try {
return getManifest(false);
} catch (BundleException e) {
// TODO: handle exception
return null;
}
}
public synchronized Dictionary getManifest(boolean first) throws BundleException {
if (manifest == null)
manifest = first ? loadManifest() : new CachedManifest(this);
if (manifest.get(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME) == null) {
Dictionary generatedManifest = generateManifest(manifest);
if (generatedManifest != null)
manifest = generatedManifest;
}
return manifest;
}
public synchronized Dictionary loadManifest() throws BundleException {
URL url = getEntry(Constants.OSGI_BUNDLE_MANIFEST);
if (url != null) {
manifestTimeStamp = getBaseBundleFile().getEntry(Constants.OSGI_BUNDLE_MANIFEST).getTime();
manifestType = MANIFEST_TYPE_BUNDLE;
return loadManifestFrom(url);
}
Dictionary result = generateManifest(null);
if (result == null) //TODO: need to NLS this
throw new BundleException("Manifest not found: " + getLocation());
return result;
}
private Dictionary generateManifest(Dictionary originalManifest) throws BundleException {
String cacheLocation = (String) System.getProperties().get("osgi.manifest.cache"); //TODO This should be a constant
if (getSymbolicName() != null) {
Version version = getVersion();
File currentFile = new File(cacheLocation, getSymbolicName() + '_' + version.toString() + ".MF");
if (PluginConverterImpl.upToDate(currentFile, getBaseFile(), manifestType))
try {
return Headers.parseManifest(new FileInputStream(currentFile));
} catch (FileNotFoundException e) {
// do nothing.
}
}
PluginConverterImpl converter = PluginConverterImpl.getDefault();
Dictionary generatedManifest = converter.convertManifest(getBaseFile(), true, null);
if (generatedManifest == null) //TODO Why don't we return the original manifest?
return null;
ManifestElement generatedFrom = ManifestElement.parseHeader(PluginConverterImpl.GENERATED_FROM, (String) generatedManifest.get(PluginConverterImpl.GENERATED_FROM))[0];
setManifestTimeStamp(Long.parseLong(generatedFrom.getValue()));
setManifestType(Byte.parseByte(generatedFrom.getAttribute(PluginConverterImpl.MANIFEST_TYPE_ATTRIBUTE)));
//merge the original manifest with the generated one
if (originalManifest != null) {
Enumeration enum = originalManifest.keys();
while (enum.hasMoreElements()) {
Object key = enum.nextElement();
generatedManifest.put(key, originalManifest.get(key));
}
}
//write the generated manifest
Version version = new Version((String) generatedManifest.get(Constants.BUNDLE_VERSION));
File bundleManifestLocation = new File(cacheLocation, ManifestElement.parseHeader(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME, (String) generatedManifest.get(org.osgi.framework.Constants.BUNDLE_SYMBOLICNAME))[0].getValue() + '_' + version.toString() + ".MF");
try {
converter.writeManifest(bundleManifestLocation, generatedManifest, true);
} catch (Exception e) {
//TODO Need to log
}
return generatedManifest;
}
private Dictionary loadManifestFrom(URL manifestURL) throws BundleException {
try {
return Headers.parseManifest(manifestURL.openStream());
} catch (IOException e) {
throw new BundleException("Error reading manifest: " + getLocation(), e);
}
}
protected void loadFromManifest() throws IOException {
try {
getManifest(true);
} catch (BundleException e) {
//TODO we whould not swallow the exception like that
throw new IOException("Unable to properly read manifest for: " + getLocation());
}
super.loadFromManifest();
autoStart = (String) manifest.get(EclipseAdaptorConstants.ECLIPSE_AUTOSTART);
autoStop = (String) manifest.get(EclipseAdaptorConstants.ECLIPSE_AUTOSTOP);
pluginClass = (String) manifest.get(EclipseAdaptorConstants.PLUGIN_CLASS);
isLegacy = (String) manifest.get(EclipseAdaptorConstants.LEGACY);
}
public String isLegacy() {
return isLegacy;
}
public void setLegacy(String value) {
isLegacy = value;
}
public String getPluginClass() {
return pluginClass;
}
public void setPluginClass(String value) {
pluginClass = value;
}
public long getManifestTimeStamp() {
return manifestTimeStamp;
}
public void setManifestTimeStamp(long stamp) {
manifestTimeStamp = stamp;
}
public byte getManifestType() {
return manifestType;
}
public void setManifestType(byte manifestType) {
this.manifestType = manifestType;
}
public void setAutoStart(String value) {
autoStart = value;
}
public void setAutoStop(String value) {
autoStop = value;
}
public String getAutoStart() {
return autoStart;
}
public String getAutoStop() {
return autoStop;
}
}