Java tutorial
/******************************************************************************* * Copyright (c) 2007, 2013 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.model; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.osgi.service.resolver.BundleDescription; import org.eclipse.osgi.util.NLS; import org.eclipse.pde.api.tools.internal.ApiDescriptionManager; import org.eclipse.pde.api.tools.internal.ApiFilterStore; import org.eclipse.pde.api.tools.internal.CoreMessages; import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; 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.model.IApiBaseline; import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent; import org.eclipse.pde.api.tools.internal.provisional.model.IApiTypeContainer; import org.eclipse.pde.api.tools.internal.util.Util; import org.eclipse.pde.core.build.IBuild; import org.eclipse.pde.core.build.IBuildEntry; import org.eclipse.pde.core.build.IBuildModel; import org.eclipse.pde.core.plugin.IPluginModelBase; import org.eclipse.pde.core.plugin.PluginRegistry; import org.osgi.framework.BundleException; /** * An API component for a plug-in project in the workspace. * <p> * Note: this class requires a running workspace to be instantiated. * </p> * * @since 1.0.0 */ public class ProjectComponent extends BundleComponent { /** * Constant used to describe the custom build.properties entry * * @since 1.0.3 */ public static final String ENTRY_CUSTOM = "custom"; //$NON-NLS-1$ /** * Constant used to describe build.properties that start with * <code>extra.</code> * * @since 1.0.3 */ public static final String EXTRA_PREFIX = "extra."; //$NON-NLS-1$ /** * Associated Java project */ private IJavaProject fProject = null; /** * Associated IPluginModelBase object */ private IPluginModelBase fModel = null; /** * A cache of bundle class path entries to class file containers. */ private Map<String, IApiTypeContainer> fPathToOutputContainers = null; /** * A cache of output location paths to corresponding class file containers. */ private Map<IPath, IApiTypeContainer> fOutputLocationToContainer = null; /** * Constructs an API component for the given Java project in the specified * baseline. * * @param baseline the owning API baseline * @param location the given location of the component * @param model the given model * @param bundleid * @throws CoreException if unable to create the API component */ public ProjectComponent(IApiBaseline baseline, String location, IPluginModelBase model, long bundleid) throws CoreException { super(baseline, location, bundleid); IPath path = new Path(location); IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(path.lastSegment()); this.fProject = JavaCore.create(project); this.fModel = model; } /* * (non-Javadoc) * @see * org.eclipse.pde.api.tools.internal.model.ApiElement#setName(java.lang * .String) */ @Override protected void setName(String newname) { // Override to use the translated name from the plug-in model super.setName(fModel.getResourceString(newname)); } /* * (non-Javadoc) * @see org.eclipse.pde.api.tools.internal.model.BundleComponent#isBinary() */ @Override protected boolean isBinary() { return false; } /* * (non-Javadoc) * @see * org.eclipse.pde.api.tools.internal.model.BundleComponent#getBundleDescription * (java.util.Map, java.lang.String, long) */ @Override protected BundleDescription getBundleDescription(Map<String, String> manifest, String location, long id) throws BundleException { try { BundleDescription result = getModel().getBundleDescription(); if (result == null) { throw new BundleException("Cannot find manifest for bundle at " + location); //$NON-NLS-1$ } return result; } catch (CoreException ce) { throw new BundleException(ce.getMessage()); } } /** * Returns the {@link IPluginModelBase} backing this component * * @return the {@link IPluginModelBase} or throws and exception, never * retruns <code>null</code> * @throws CoreException */ IPluginModelBase getModel() throws CoreException { if (fModel == null) { fModel = PluginRegistry.findModel(fProject.getProject()); if (fModel == null) { abort(NLS.bind(CoreMessages.ProjectComponent_could_not_locate_model, fProject.getElementName()), null); } } return fModel; } /* * (non-Javadoc) * @see * org.eclipse.pde.api.tools.internal.model.BundleComponent#isApiEnabled() */ @Override protected boolean isApiEnabled() { return Util.isApiProject(fProject); } /* * (non-Javadoc) * @see org.eclipse.pde.api.tools.internal.model.BundleComponent#dispose() */ @Override public void dispose() { try { if (hasApiFilterStore()) { getFilterStore().dispose(); } fModel = null; if (fOutputLocationToContainer != null) { fOutputLocationToContainer.clear(); fOutputLocationToContainer = null; } if (fPathToOutputContainers != null) { fPathToOutputContainers.clear(); fPathToOutputContainers = null; } } catch (CoreException ce) { ApiPlugin.log(ce); } finally { super.dispose(); } } /* * (non-Javadoc) * @see org.eclipse.pde.api.tools.internal.model.BundleComponent# * createLocalApiDescription() */ @Override protected IApiDescription createLocalApiDescription() throws CoreException { long time = System.currentTimeMillis(); if (Util.isApiProject(getJavaProject())) { setHasApiDescription(true); } IApiDescription apiDesc = ApiDescriptionManager.getManager().getApiDescription(this, getBundleDescription()); if (ApiPlugin.DEBUG_PROJECT_COMPONENT) { System.out.println("Time to create api description for: [" + fProject.getElementName() + "] " //$NON-NLS-1$//$NON-NLS-2$ + (System.currentTimeMillis() - time) + "ms"); //$NON-NLS-1$ } return apiDesc; } /* * (non-Javadoc) * @see * org.eclipse.pde.api.tools.internal.model.BundleComponent#createApiFilterStore * () */ @Override protected IApiFilterStore createApiFilterStore() throws CoreException { long time = System.currentTimeMillis(); IApiFilterStore store = new ApiFilterStore(getJavaProject()); if (ApiPlugin.DEBUG_PROJECT_COMPONENT) { System.out.println("Time to create api filter store for: [" + fProject.getElementName() + "] " //$NON-NLS-1$//$NON-NLS-2$ + (System.currentTimeMillis() - time) + "ms"); //$NON-NLS-1$ } return store; } /* * (non-Javadoc) * @see org.eclipse.pde.api.tools.internal.model.BundleComponent# * createApiTypeContainers() */ @Override protected synchronized List<IApiTypeContainer> createApiTypeContainers() throws CoreException { // first populate build.properties cache so we can create class file // containers // from bundle classpath entries fPathToOutputContainers = new HashMap<String, IApiTypeContainer>(4); fOutputLocationToContainer = new HashMap<IPath, IApiTypeContainer>(4); if (fProject.exists() && fProject.getProject().isOpen()) { IPluginModelBase model = PluginRegistry.findModel(fProject.getProject()); if (model != null) { IBuildModel buildModel = PluginRegistry.createBuildModel(model); if (buildModel != null) { IBuild build = buildModel.getBuild(); IBuildEntry entry = build.getEntry(ENTRY_CUSTOM); if (entry != null) { String[] tokens = entry.getTokens(); if (tokens.length == 1 && tokens[0].equals("true")) { //$NON-NLS-1$ // hack : add the current output location for each // classpath entries IClasspathEntry[] classpathEntries = fProject.getRawClasspath(); List<IApiTypeContainer> containers = new ArrayList<IApiTypeContainer>(); for (int i = 0; i < classpathEntries.length; i++) { IClasspathEntry classpathEntry = classpathEntries[i]; switch (classpathEntry.getEntryKind()) { case IClasspathEntry.CPE_SOURCE: String containerPath = classpathEntry.getPath().removeFirstSegments(1) .toString(); IApiTypeContainer container = getApiTypeContainer(containerPath, this); if (container != null && !containers.contains(container)) { containers.add(container); } break; case IClasspathEntry.CPE_VARIABLE: classpathEntry = JavaCore.getResolvedClasspathEntry(classpathEntry); //$FALL-THROUGH$ case IClasspathEntry.CPE_LIBRARY: IPath path = classpathEntry.getPath(); if (Util.isArchive(path.lastSegment())) { IResource resource = ResourcesPlugin.getWorkspace().getRoot() .findMember(path); if (resource != null) { // jar inside the workspace containers.add(new ArchiveApiTypeContainer(this, resource.getLocation().toOSString())); } else { // external jar containers.add(new ArchiveApiTypeContainer(this, path.toOSString())); } } break; default: break; } } if (!containers.isEmpty()) { IApiTypeContainer cfc = null; if (containers.size() == 1) { cfc = containers.get(0); } else { cfc = new CompositeApiTypeContainer(this, containers); } fPathToOutputContainers.put(".", cfc); //$NON-NLS-1$ } } } else { IBuildEntry[] entries = build.getBuildEntries(); int length = entries.length; for (int i = 0; i < length; i++) { IBuildEntry buildEntry = entries[i]; String name = buildEntry.getName(); if (name.startsWith(IBuildEntry.JAR_PREFIX)) { retrieveContainers(name, IBuildEntry.JAR_PREFIX, buildEntry); } else if (name.startsWith(EXTRA_PREFIX)) { retrieveContainers(name, EXTRA_PREFIX, buildEntry); } } } } } return super.createApiTypeContainers(); } return Collections.EMPTY_LIST; } private void retrieveContainers(String name, String prefix, IBuildEntry buildEntry) throws CoreException { String jar = name.substring(prefix.length()); String[] tokens = buildEntry.getTokens(); if (tokens.length == 1) { IApiTypeContainer container = getApiTypeContainer(tokens[0], this); if (container != null) { IApiTypeContainer existingContainer = this.fPathToOutputContainers.get(jar); if (existingContainer != null) { // concat both containers List<IApiTypeContainer> allContainers = new ArrayList<IApiTypeContainer>(); allContainers.add(existingContainer); allContainers.add(container); IApiTypeContainer apiTypeContainer = new CompositeApiTypeContainer(this, allContainers); fPathToOutputContainers.put(jar, apiTypeContainer); } else { fPathToOutputContainers.put(jar, container); } } } else { List<IApiTypeContainer> containers = new ArrayList<IApiTypeContainer>(); for (int j = 0; j < tokens.length; j++) { String currentToken = tokens[j]; IApiTypeContainer container = getApiTypeContainer(currentToken, this); if (container != null && !containers.contains(container)) { containers.add(container); } } if (!containers.isEmpty()) { IApiTypeContainer existingContainer = this.fPathToOutputContainers.get(jar); if (existingContainer != null) { // concat both containers containers.add(existingContainer); } IApiTypeContainer cfc = null; if (containers.size() == 1) { cfc = containers.get(0); } else { cfc = new CompositeApiTypeContainer(this, containers); } fPathToOutputContainers.put(jar, cfc); } } } /* * (non-Javadoc) * @see org.eclipse.pde.api.tools.internal.model.BundleComponent# * createApiTypeContainer(java.lang.String) */ @Override protected IApiTypeContainer createApiTypeContainer(String path) throws CoreException { if (this.fPathToOutputContainers == null) { baselineDisposed(getBaseline()); } IApiTypeContainer container = fPathToOutputContainers.get(path); if (container == null) { // could be a binary jar included in the plug-in, just look for it container = findApiTypeContainer(path); } return container; } /** * Finds and returns an existing {@link IApiTypeContainer} at the specified * location in this project, or <code>null</code> if none. * * @param location project relative path to the class file container * @return {@link IApiTypeContainer} or <code>null</code> */ private IApiTypeContainer findApiTypeContainer(String location) { IResource res = fProject.getProject().findMember(new Path(location)); if (res != null) { if (res.getType() == IResource.FILE) { return new ArchiveApiTypeContainer(this, res.getLocation().toOSString()); } else { return new DirectoryApiTypeContainer(this, res.getLocation().toOSString()); } } return null; } /** * Finds and returns an {@link IApiTypeContainer} for the specified source * folder, or <code>null</code> if it does not exist. If the source folder * shares an output location with a previous source folder, the output * location is shared (a new one is not created). * * @param location project relative path to the source folder * @return {@link IApiTypeContainer} or <code>null</code> */ private IApiTypeContainer getApiTypeContainer(String location, IApiComponent component) throws CoreException { if (this.fOutputLocationToContainer == null) { baselineDisposed(getBaseline()); } IResource res = fProject.getProject().findMember(new Path(location)); if (res != null) { IPackageFragmentRoot root = fProject.getPackageFragmentRoot(res); if (root.exists()) { if (root.getKind() == IPackageFragmentRoot.K_BINARY) { if (res.getType() == IResource.FOLDER) { // class file folder IPath location2 = res.getLocation(); IApiTypeContainer cfc = fOutputLocationToContainer.get(location2); if (cfc == null) { cfc = new ProjectTypeContainer(component, (IContainer) res); fOutputLocationToContainer.put(location2, cfc); } return cfc; } } else { IClasspathEntry entry = root.getRawClasspathEntry(); IPath outputLocation = entry.getOutputLocation(); if (outputLocation == null) { outputLocation = fProject.getOutputLocation(); } IApiTypeContainer cfc = fOutputLocationToContainer.get(outputLocation); if (cfc == null) { IPath projectFullPath = fProject.getProject().getFullPath(); IContainer container = null; if (projectFullPath.equals(outputLocation)) { // The project is its own output location container = fProject.getProject(); } else { container = fProject.getProject().getWorkspace().getRoot().getFolder(outputLocation); } cfc = new ProjectTypeContainer(component, container); fOutputLocationToContainer.put(outputLocation, cfc); } return cfc; } } } return null; } /** * Returns the Java project associated with this component. * * @return associated Java project */ public IJavaProject getJavaProject() { return fProject; } /** * Returns the cached API type container for the given package fragment * root, or <code>null</code> if none. The given package fragment has to be * a SOURCE package fragment - this method is only used by the project API * description to obtain a class file corresponding to a compilation unit * when tag scanning (to resolve signatures). * * @param root source package fragment root * @return API type container associated with the package fragment root, or * <code>null</code> if none */ public IApiTypeContainer getTypeContainer(IPackageFragmentRoot root) throws CoreException { if (root.getKind() == IPackageFragmentRoot.K_SOURCE) { getApiTypeContainers(); // ensure initialized IResource resource = root.getResource(); if (resource != null) { String location = resource.getProjectRelativePath().toString(); return getApiTypeContainer(location, this); } } return null; } }