alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*******************************************************************************
 * 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.pde.api.tools.internal;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import javax.xml.parsers.FactoryConfigurationError;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.Path;
import org.eclipse.osgi.service.resolver.BundleDescription;
import org.eclipse.osgi.service.resolver.BundleSpecification;
import org.eclipse.osgi.service.resolver.ExportPackageDescription;
import org.eclipse.osgi.service.resolver.HostSpecification;
import org.eclipse.osgi.service.resolver.State;
import org.eclipse.osgi.service.resolver.StateObjectFactory;
import org.eclipse.osgi.util.ManifestElement;
import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin;
import org.eclipse.pde.api.tools.internal.provisional.Factory;
import org.eclipse.pde.api.tools.internal.provisional.IApiDescription;
import org.eclipse.pde.api.tools.internal.provisional.IApiFilterStore;
import org.eclipse.pde.api.tools.internal.provisional.IApiProfile;
import org.eclipse.pde.api.tools.internal.provisional.IClassFileContainer;
import org.eclipse.pde.api.tools.internal.provisional.IRequiredComponentDescription;
import org.eclipse.pde.api.tools.internal.provisional.VisibilityModifiers;
import org.eclipse.pde.api.tools.internal.provisional.descriptors.IPackageDescriptor;
import org.eclipse.pde.api.tools.internal.provisional.scanner.ApiDescriptionProcessor;
import org.eclipse.pde.api.tools.internal.util.SourceDefaultHandler;
import org.eclipse.pde.api.tools.internal.util.Util;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

/**
 * Implementation of an API component based on a bundle in the file system.
 * 
 * @since 1.0.0
 */
public class BundleApiComponent extends AbstractApiComponent {
	
	/**
	 * Dictionary parsed from MANIFEST.MF
	 */
	private Dictionary fManifest;
	
	/**
	 * Root location of component in the file system
	 */
	private String fLocation;
	
	/**
	 * Underlying bundle description (OSGi model of a bundle)
	 */
	private BundleDescription fBundleDescription;
	
	/**
	 * Maps class file container to bundle it originated from.
	 * Used for exporting. 
	 */
	private Map fContainerToBundle;
	
	/**
	 * Maps class file container to its relative path in its bundle.
	 */
	private Map fContainerToPath;

	/**
	 * Constructs a new API component from the specified location in the file system
	 * in the given profile.
	 * 
	 * @param profile owning profile
	 * @param location directory or jar file
	 * @exception CoreException if unable to create a component from the specified location
	 */
	public BundleApiComponent(IApiProfile profile, String location) throws CoreException {
		super(profile);
		fLocation = location;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.pde.api.tools.internal.descriptors.AbstractApiComponent#dispose()
	 */
	public void dispose() {
		try {
			super.dispose();
		} finally {
			if (fContainerToBundle != null) {
				fContainerToBundle.clear();
			}
			if (fContainerToPath != null) {
				fContainerToPath.clear();
			}
			fManifest = null;
			fBundleDescription = null;
		}
	}
	
	/**
	 * Returns this bundle's manifest as a dictionary.
	 * 
	 * @return manifest dictionary
	 * @exception CoreException if something goes terribly wrong
	 */
	protected synchronized Dictionary getManifest() throws CoreException {
		if(fManifest == null) {
			try {
				fManifest = (Dictionary) loadManifest(new File(fLocation));
			} catch (IOException e) {
				abort("Unable to load manifest due to IO error", e); //$NON-NLS-1$
			}
		}
		return fManifest;
	}

	/**
	 * Returns if the bundle at the specified location is a valid bundle or not.
	 * Validity is determined via the existence of a readable manifest file
	 * @param location
	 * @return true if the bundle at the given location is valid false otherwise
	 * @throws IOException
	 */
	public boolean isValidBundle() throws CoreException {
		Dictionary manifest = getManifest();
		return manifest != null && (manifest.get(Constants.BUNDLE_NAME) != null && manifest.get(Constants.BUNDLE_VERSION) != null);
	}
	
	/**
	 * Initializes component state from the underlying bundle for the given
	 * state.
	 * 
	 * @param state PDE state
	 * @throws CoreException on failure
	 */
	protected void init(State state, long bundleId) throws CoreException {
		try {
			Dictionary manifest = getManifest();
			StateObjectFactory factory = StateObjectFactory.defaultFactory;
			fBundleDescription = factory.createBundleDescription(state, manifest, fLocation, bundleId);
		} catch (BundleException e) {
			abort("Unable to create API component from specified location: " + fLocation, e); //$NON-NLS-1$
		}
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.pde.api.tools.internal.AbstractApiComponent#createApiDescription()
	 */
	protected IApiDescription createApiDescription() throws CoreException {
		BundleDescription[] fragments = getBundleDescription().getFragments();
		if (fragments.length == 0) {
			return createLocalApiDescription();
		}
		// build a composite description
		IApiDescription[] descriptions = new IApiDescription[fragments.length + 1];
		for (int i = 0; i < fragments.length; i++) {
			BundleDescription fragment = fragments[i];
			BundleApiComponent component = (BundleApiComponent) getProfile().getApiComponent(fragment.getSymbolicName());
			descriptions[i + 1] = component.getApiDescription();
		}
		descriptions[0] = createLocalApiDescription();
		return new CompositeApiDescription(descriptions);
	}

	/**
	 * Creates and returns this component's API description based on packages
	 * supplied by this component, exported packages, and associated directives.
	 * 
	 * @return API description
	 * @throws CoreException if unable to initialize 
	 */
	protected IApiDescription createLocalApiDescription() throws CoreException {
		IApiDescription apiDesc = new ApiDescription(getId());
		// first mark all packages as internal
		initializeApiDescription(apiDesc, getBundleDescription(), getLocalPackageNames());
		try {
			String xml = loadApiDescription(new File(fLocation));
			if (xml != null) {
				ApiDescriptionProcessor.annotateApiSettings(null, apiDesc, xml);
			}
		} catch (IOException e) {
			abort("Unable to load component.xml", e); //$NON-NLS-1$
		}
		return apiDesc;
	}
	
	/**
	 * Returns the names of all packages that originate from this bundle.
	 * Does not include packages that originate from fragments or a host.
	 * 
	 * @return local package names
	 * @throws CoreException
	 */
	protected Set getLocalPackageNames() throws CoreException {
		Set names = new HashSet();
		IClassFileContainer[] containers = getClassFileContainers();
		for (int i = 0; i < containers.length; i++) {
			if (containers[i].getOrigin().equals(getId())) {
				String[] packageNames = containers[i].getPackageNames();
				for (int j = 0; j < packageNames.length; j++) {
					names.add(packageNames[j]);
				}
			}
		}
		return names;
	}	
	

	/**
	 * Initializes the given API description based on package exports in the manifest.
	 * The API description for a bundle only contains packages that originate from
	 * this bundle (so a host will not contain API descriptions for packages that
	 * originate from fragments). However, a host's API description will be represented
	 * by a proxy that delegates to the host and all of its fragments to provide
	 * a complete description of the host.
	 * 
	 * @param apiDesc API description to initialize
	 * @param bundle the bundle to load from
	 * @param packages the complete set of packages names originating from the backing
	 * 		component
	 * @throws CoreException if an error occurs
	 */
	protected static void initializeApiDescription(IApiDescription apiDesc, BundleDescription bundle, Set packages) throws CoreException {
		Iterator iterator = packages.iterator();
		while (iterator.hasNext()) {
			String name = (String) iterator.next();
			apiDesc.setVisibility(Factory.packageDescriptor(name), VisibilityModifiers.PRIVATE);
		}
		// then process exported packages that originate from this bundle
		// considering host and fragment package exports
		List supplied = new ArrayList();
		ExportPackageDescription[] exportPackages = bundle.getExportPackages();
		addSuppliedPackages(packages, supplied, exportPackages);
		HostSpecification host = bundle.getHost();
		if (host != null) {
			BundleDescription[] hosts = host.getHosts();
			for (int i = 0; i < hosts.length; i++) {
				addSuppliedPackages(packages, supplied, hosts[i].getExportPackages());
			}
		}
		BundleDescription[] fragments = bundle.getFragments();
		for (int i = 0; i < fragments.length; i++) {
			addSuppliedPackages(packages, supplied, fragments[i].getExportPackages());
		}
		
		annotateExportedPackages(apiDesc, (ExportPackageDescription[]) supplied.toArray(new ExportPackageDescription[supplied.size()]));
	}

	/**
	 * Adds package exports to the given list if the associated package originates
	 * from this bundle.
	 *   
	 * @param packages names of packages supplied by this bundle
	 * @param supplied list to append package exports to
	 * @param exportPackages package exports to consider
	 */
	protected static void addSuppliedPackages(Set packages, List supplied, ExportPackageDescription[] exportPackages) {
		for (int i = 0; i < exportPackages.length; i++) {
			ExportPackageDescription pkg = exportPackages[i];
			String name = pkg.getName();
			if (name.equals(".")) { //$NON-NLS-1$
				// translate . to default package
				name = Util.DEFAULT_PACKAGE_NAME;
			}
			if (packages.contains(name)) {
				supplied.add(pkg);
			}
		}
	}
	
	/**
	 * Annotates the API description with exported packages.
	 * 
	 * @param apiDesc description to annotate
	 * @param exportedPackages packages that are exported
	 */
	protected static void annotateExportedPackages(IApiDescription apiDesc, ExportPackageDescription[] exportedPackages) {
		for(int i = 0; i < exportedPackages.length; i++) {
			ExportPackageDescription pkg = exportedPackages[i];
			//TODO remove this? all pkg exports are roots according to the doc
			if (pkg.isRoot()) {
				boolean internal = ((Boolean) pkg.getDirective("x-internal")).booleanValue(); //$NON-NLS-1$
				String[] friends = (String[]) pkg.getDirective("x-friends"); //$NON-NLS-1$
				String pkgName = pkg.getName();
				if (pkgName.equals(".")) { //$NON-NLS-1$
					// default package
					pkgName = ""; //$NON-NLS-1$
				}
				IPackageDescriptor pkgDesc = Factory.packageDescriptor(pkgName);
				if(internal) {
					apiDesc.setVisibility(pkgDesc, VisibilityModifiers.PRIVATE);
				}
				if (friends != null) {
					apiDesc.setVisibility(pkgDesc, VisibilityModifiers.PRIVATE);
				}
				if (!internal && friends == null) {
					//there could have been directives that have nothing to do with
					//visibility, so we need to add the package as API in that case
					apiDesc.setVisibility(pkgDesc, VisibilityModifiers.API);
				}
			}				
		}
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.pde.api.tools.internal.AbstractApiComponent#createApiFilterStore()
	 */
	protected IApiFilterStore createApiFilterStore() throws CoreException {
		//always return a new empty store since we do not support filtering from bundles
		return null;
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.pde.api.tools.internal.AbstractClassFileContainer#createClassFileContainers()
	 */
	protected List createClassFileContainers() throws CoreException {
		List containers = new ArrayList();
		fContainerToBundle = new HashMap();
		fContainerToPath = new HashMap();
		try {
			List all = new ArrayList();
			// build the classpath from bundle and all fragments
			all.add(this);
			BundleDescription[] fragments = fBundleDescription.getFragments();
			for (int i = 0; i < fragments.length; i++) {
				BundleDescription fragment = fragments[i];
				BundleApiComponent component = (BundleApiComponent) getProfile().getApiComponent(fragment.getSymbolicName());
				if (component != null) {
					// force initialization of the fragment so we can retrieve its class file containers
					component.getClassFileContainers();
					all.add(component);
				}
			}
			Iterator iterator = all.iterator();
			Set entryNames = new HashSet();
			while (iterator.hasNext()) {
				BundleApiComponent component = (BundleApiComponent) iterator.next();
				String[] paths = getClasspathEntries(component.getManifest());
				for (int i = 0; i < paths.length; i++) {
					BundleApiComponent origin = null;
					String path = paths[i];
					// don't re-process the same entry twice (except default entries ".")
					if (!(".".equals(path))) { //$NON-NLS-1$
						if (entryNames.contains(path)) {
							continue;
						}
					}
					IClassFileContainer container = component.createClassFileContainer(path);
					if (container == null) {
						Iterator others = all.iterator();
						while (others.hasNext()) {
							BundleApiComponent other = (BundleApiComponent) others.next();
							if (other != component) {
								container = other.createClassFileContainer(path);
								if (container != null) {
									origin = other;
									break;
								}
							}
						}
					} else {
						origin = component;
					}
					if (container != null) {
						fContainerToBundle.put(container, origin);
						containers.add(container);
						fContainerToPath.put(container, path);
						if (!(".".equals(path))) { //$NON-NLS-1$
							entryNames.add(path);
						}
					}
				}
			}
		} catch (BundleException e) {
			abort("Unable to parse bundle classpath", e); //$NON-NLS-1$
		} catch (IOException e) {
			abort("Unable to initialize class file containers", e); //$NON-NLS-1$
		}
		return containers;
	}
	
	/**
	 * Returns classpath entries defined in the given manifest.
	 * 
	 * @param manifest
	 * @return classpath entries as bundle relative paths
	 * @throws BundleException
	 */
	protected String[] getClasspathEntries(Dictionary manifest) throws BundleException {
		ManifestElement[] classpath = ManifestElement.parseHeader(Constants.BUNDLE_CLASSPATH, (String) manifest.get(Constants.BUNDLE_CLASSPATH));
		String elements[] = null;
		if (classpath == null) {
			// default classpath is '.'
			elements = new String[]{"."}; //$NON-NLS-1$
		} else {
			elements = new String[classpath.length];
			for (int i = 0; i < classpath.length; i++) {
				elements[i] = classpath[i].getValue();
			}
		}
		return elements;
	}
	
	/**
	 * Creates and returns a class file container at the specified path in
	 * this bundle, or <code>null if the class file container does not
	 * exist. The path is the name (path) of entries specified by the
	 * <code>Bundle-ClassPath: header.
	 * 
	 * @param path relative path to a class file container in this bundle
	 * @return class file container or <code>null
	 * @exception IOException
	 */
	protected IClassFileContainer createClassFileContainer(String path) throws IOException {
		File bundle = new File(fLocation);
		if (bundle.isDirectory()) {
			// bundle is folder
			File entry = new File(bundle, path);
			if (entry.exists()) {
				if (entry.isFile()) {
					return new ArchiveClassFileContainer(entry.getCanonicalPath(), this.getId());
				} else {
					return new DirectoryClassFileContainer(entry.getCanonicalPath(), this.getId());
				}
			}
		} else {
			// bundle is jar'd
			ZipFile zip = null;
			try {
				if (path.equals(".")) { //$NON-NLS-1$
					return new ArchiveClassFileContainer(fLocation, this.getId());
				} else {
					// TODO: use temporary space from OSGi if in a framework
					zip = new ZipFile(fLocation);
					ZipEntry entry = zip.getEntry(path);
					if (entry != null) {
						InputStream inputStream = null;
						File tempFile;
						FileOutputStream outputStream = null;
						try {
							inputStream = zip.getInputStream(entry);
							tempFile = File.createTempFile("api", "tmp"); //$NON-NLS-1$ //$NON-NLS-2$
							tempFile.deleteOnExit();
							outputStream = new FileOutputStream(tempFile);
							byte[] bytes = new byte[8096];
							while (inputStream.available() > 0) {
								int read = inputStream.read(bytes);
								if (read > 0) {
									outputStream.write(bytes, 0, read);
								}
							}
						} finally {
							if (inputStream != null) {
								try {
									inputStream.close();
								} catch(IOException e) {
									ApiPlugin.log(e);
								}
							}
							if (outputStream != null) {
								try {
									outputStream.close();
								} catch(IOException e) {
									ApiPlugin.log(e);
								}
							}
						}
						return new ArchiveClassFileContainer(tempFile.getCanonicalPath(), this.getId());
					}
				}
			} finally {
				if (zip != null) {
					zip.close();
				}
			}
		}
		return null;
	}
		
	/**
	 * Parses a bunlde's manifest into a dictionary. The bundle may be in a jar
	 * or in a directory at the specified location.
	 * 
	 * @param bundleLocation root location of the bundle
	 * @return bundle manifest dictionary or <code>null if none
	 * @throws IOException if unable to parse
	 */
	protected Map loadManifest(File bundleLocation) throws IOException {
		ZipFile jarFile = null;
		InputStream manifestStream = null;
		String extension = new Path(bundleLocation.getName()).getFileExtension();
		try {
			if (extension != null && extension.equals("jar") && 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 file = new File(bundleLocation, JarFile.MANIFEST_NAME);
				if (file.exists())
					manifestStream = new FileInputStream(file);
			}
			if (manifestStream == null) {
				return null;
			}
			return ManifestElement.parseBundleManifest(manifestStream, new Hashtable(10));
		} catch (BundleException e) {
			ApiPlugin.log(e);
		} finally {
			closingZipFileAndStream(manifestStream, jarFile);
		}
		return null;
	}
	
	/**
	 * Reads and returns this bunlde's manifest in a Manifest object.
	 * The bundle may be in a jar or in a directory at the specified location.
	 * 
	 * @param bundleLocation root location of the bundle
	 * @return manifest or <code>null if not present
	 * @throws IOException if unable to parse
	 */
	protected Manifest readManifest(File bundleLocation) throws IOException {
		ZipFile jarFile = null;
		InputStream manifestStream = null;
		try {
			String extension = new Path(bundleLocation.getName()).getFileExtension();
			if (extension != null && extension.equals("jar") && 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 file = new File(bundleLocation, JarFile.MANIFEST_NAME);
				if (file.exists())
					manifestStream = new FileInputStream(file);
			}
			if (manifestStream == null) {
				return null;
			}
			return new Manifest(manifestStream);
		} finally {
			closingZipFileAndStream(manifestStream, jarFile);
		}
	}

	void closingZipFileAndStream(InputStream stream, ZipFile jarFile) {
		try {
			if (stream != null) {
				stream.close();
			}
		} catch (IOException e) {
			ApiPlugin.log(e);
		}
		try {
			if (jarFile != null) {
				jarFile.close();
			}
		} catch (IOException e) {
			ApiPlugin.log(e);
		}
	}
	
	/**
	 * Reads and returns the file contents corresponding to the given file name.
	 * The bundle may be in a jar or in a directory at the specified location.
	 * 
	 * @param xmlFileName the given file name
	 * @param bundleLocation the root location of the bundle
	 * @return the file contents or <code>null if not present
	 */
	protected String readFileContents(String xmlFileName, File bundleLocation) {
		ZipFile jarFile = null;
		InputStream stream = null;
		try {
			String extension = new Path(bundleLocation.getName()).getFileExtension();
			if (extension != null && extension.equals("jar") && bundleLocation.isFile()) { //$NON-NLS-1$
				jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ);
				ZipEntry manifestEntry = jarFile.getEntry(xmlFileName);
				if (manifestEntry != null) {
					stream = jarFile.getInputStream(manifestEntry);
				}
			} else {
				File file = new File(bundleLocation, xmlFileName);
				if (file.exists()) {
					stream = new FileInputStream(file);
				}
			}
			if (stream == null) {
				return null;
			}
			return new String(Util.getInputStreamAsCharArray(stream, -1, IApiCoreConstants.UTF_8));
		} catch(IOException e) {
			ApiPlugin.log(e);
		} finally {
			closingZipFileAndStream(stream, jarFile);
		}
		return null;
	}

	/**
	 * Parses a bundle's .api_description XML into a string. The file may be in a jar
	 * or in a directory at the specified location.
	 * 
	 * @param bundleLocation root location of the bundle
	 * @return API description XML as a string or <code>null if none
	 * @throws IOException if unable to parse
	 */
	protected String loadApiDescription(File bundleLocation) throws IOException {
		ZipFile jarFile = null;
		InputStream stream = null;
		String contents = null;
		try {
			String extension = new Path(bundleLocation.getName()).getFileExtension();
			if (extension != null && extension.equals("jar") && bundleLocation.isFile()) { //$NON-NLS-1$
				jarFile = new ZipFile(bundleLocation, ZipFile.OPEN_READ);
				ZipEntry manifestEntry = jarFile.getEntry(IApiCoreConstants.API_DESCRIPTION_XML_NAME);
				if (manifestEntry != null) {
					// new file is present
					stream = jarFile.getInputStream(manifestEntry);
				}
			} else {
				File file = new File(bundleLocation, IApiCoreConstants.API_DESCRIPTION_XML_NAME);
				if (file.exists()) {
					// use new file
					stream = new FileInputStream(file);
				}
			}
			if (stream == null) {
				return null;
			}
			char[] charArray = Util.getInputStreamAsCharArray(stream, -1, IApiCoreConstants.UTF_8);
			contents = new String(charArray);
		} finally {
			closingZipFileAndStream(stream, jarFile);
		}
		return contents;
	}
	
	
	/**
	 * Returns a URL describing a file inside a bundle.
	 * 
	 * @param bundleLocation root location of the bundle. May be a
	 *  directory or a file (jar)
	 * @param filePath bundle relative path to desired file
	 * @return URL to the file
	 * @throws MalformedURLException 
	 */
	protected URL getFileInBundle(File bundleLocation, String filePath) throws MalformedURLException {
		String extension = new Path(bundleLocation.getName()).getFileExtension();
		StringBuffer urlSt = new StringBuffer();
		if (extension != null && extension.equals("jar") && bundleLocation.isFile()) { //$NON-NLS-1$
			urlSt.append("jar:file:"); //$NON-NLS-1$
			urlSt.append(bundleLocation.getAbsolutePath());
			urlSt.append("!/"); //$NON-NLS-1$
			urlSt.append(filePath);
		} else {
			urlSt.append("file:"); //$NON-NLS-1$
			urlSt.append(bundleLocation.getAbsolutePath());
			urlSt.append(File.separatorChar);
			urlSt.append(filePath);
		}	
		return new URL(urlSt.toString());
	}
	
	/* (non-Javadoc)
	 * @see org.eclipse.pde.api.tools.manifest.IApiComponent#getExecutionEnvironments()
	 */
	public String[] getExecutionEnvironments() {
		return fBundleDescription.getExecutionEnvironments();
	}

	/* (non-Javadoc)
	 * @see org.eclipse.pde.api.tools.manifest.IApiComponent#getId()
	 */
	public String getId() {
		return fBundleDescription.getSymbolicName();
	}

	/* (non-Javadoc)
	 * @see org.eclipse.pde.api.tools.manifest.IApiComponent#getName()
	 */
	public String getName() throws CoreException {
		return (String)getManifest().get(Constants.BUNDLE_NAME);
	}

	/* (non-Javadoc)
	 * @see org.eclipse.pde.api.tools.manifest.IApiComponent#getRequiredComponents()
	 */
	public IRequiredComponentDescription[] getRequiredComponents() {
		BundleSpecification[] requiredBundles = fBundleDescription.getRequiredBundles();
		IRequiredComponentDescription[] req = new IRequiredComponentDescription[requiredBundles.length];
		for (int i = 0; i < requiredBundles.length; i++) {
			BundleSpecification bundle = requiredBundles[i];
			req[i] = new RequiredComponentDescription(bundle.getName(), new BundleVersionRange(bundle.getVersionRange()), bundle.isOptional());
		}
		return req;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.pde.api.tools.manifest.IApiComponent#getVersion()
	 */
	public String getVersion() {
		return fBundleDescription.getVersion().toString();
	}
	
	/**
	 * Returns this component's bundle description.
	 * 
	 * @return bundle description
	 */
	protected BundleDescription getBundleDescription() {
		return fBundleDescription;
	}

	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	public String toString() {
		if (fBundleDescription != null) {
			return fBundleDescription.toString();
		}
		return super.toString();
	}

	/* (non-Javadoc)
	 * @see org.eclipse.pde.api.tools.model.component.IApiComponent#getLocation()
	 */
	public String getLocation() {
		return fLocation;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.pde.api.tools.model.component.IApiComponent#isSystemComponent()
	 */
	public boolean isSystemComponent() {
		return false;
	}
	
	/**
	 * Returns a boolean option from the map or the default value if not present.
	 * 
	 * @param options option map
	 * @param optionName option name
	 * @param defaultValue default value for option if not present
	 * @return boolean value
	 */
	protected boolean getBooleanOption(Map options, String optionName, boolean defaultValue) {
		Boolean optionB = (Boolean)options.get(optionName);
		if (optionB != null) {
			return optionB.booleanValue();
		}
		return defaultValue;
	}
	
	/* (non-Javadoc)
	 * @see IApiComponent#isSourceComponent()
	 */
	public boolean isSourceComponent() {
		ManifestElement[] sourceBundle = null;
		try {
			sourceBundle = ManifestElement.parseHeader(IApiCoreConstants.ECLIPSE_SOURCE_BUNDLE, (String) fManifest.get(IApiCoreConstants.ECLIPSE_SOURCE_BUNDLE));
		} catch (BundleException e) {
			// ignore
		}
		if (sourceBundle != null) {
			// this is a source bundle with the new format
			return true;
		}
		// check for the old format
		String pluginXMLContents = readFileContents(IApiCoreConstants.PLUGIN_XML_NAME,new File(getLocation()));
		if (pluginXMLContents != null) {
			if (containsSourceExtensionPoint(pluginXMLContents)) {
				return true;
			}
		}
		// check if it contains a fragment.xml with the appropriate extension point
		pluginXMLContents = readFileContents(IApiCoreConstants.FRAGMENT_XML_NAME,new File(getLocation()));
		if (pluginXMLContents != null) {
			if (containsSourceExtensionPoint(pluginXMLContents)) {
				return true;
			}
		}
		// parse XML contents to find extension points
		return false;
	}

	/**
	 * Check if the given source contains an source extension point.
	 * 
	 * @param pluginXMLContents the given file contents
	 * @return true if it contains a source extension point, false otherwise
	 */
	private boolean containsSourceExtensionPoint(String pluginXMLContents) {
		SAXParserFactory factory = null;
		try {
			factory = SAXParserFactory.newInstance();
		} catch (FactoryConfigurationError e) {
			return false;
		}
		SAXParser saxParser = null;
		try {
			saxParser = factory.newSAXParser();
		} catch (ParserConfigurationException e) {
			// ignore
		} catch (SAXException e) {
			// ignore
		}

		if (saxParser == null) {
			return false;
		}

		// Parse
		InputSource inputSource = new InputSource(new BufferedReader(new StringReader(pluginXMLContents)));
		try {
			SourceDefaultHandler defaultHandler = new SourceDefaultHandler();
			saxParser.parse(inputSource, defaultHandler);
			return defaultHandler.isSource();
		} catch (SAXException e) {
			// ignore
		} catch (IOException e) {
			// ignore
		}
		return false;
	}	

	/* (non-Javadoc)
	 * @see org.eclipse.pde.api.tools.IApiComponent#isFragment()
	 */
	public boolean isFragment() {
		return fBundleDescription.getHost() != null;
	}

	/* (non-Javadoc)
	 * @see org.eclipse.pde.api.tools.IApiComponent#hasFragments()
	 */
	public boolean hasFragments() {
		return fBundleDescription.getFragments().length != 0;
	}
	
	public String getOrigin() {
		return this.getId();
	}
}
... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.