/******************************************************************************* * Copyright (c) 2000, 2007 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 * IBM Corporation - added support for requesting updates of a particular * container for generic container operations. * - canUpdateClasspathContainer(IPath, IJavaProject) * - requestClasspathContainerUpdate(IPath, IJavaProject, IClasspathContainer) * IBM Corporation - allow initializers to provide a readable description * of a container reference, ahead of actual resolution. * - getDescription(IPath, IJavaProject) *******************************************************************************/ package org.eclipse.jdt.core; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.jdt.internal.core.JavaModelStatus; /** * Abstract base implementation of all classpath container initializer. Classpath variable * containers are used in conjunction with the "org.eclipse.jdt.core.classpathContainerInitializer" * extension point. * <p> * Clients should subclass this class to implement a specific classpath container initializer. The * subclass must have a public 0-argument constructor and a concrete implementation of * {@link #initialize(IPath, IJavaProject)}. * <p> * Multiple classpath containers can be registered, each of them declares the container ID they can * handle, so as to narrow the set of containers they can resolve, in other words, a container * initializer is guaranteed to only be activated to resolve containers which match the ID they * registered onto. * <p> * In case multiple container initializers collide on the same container ID, the first registered * one will be invoked. * * @see IClasspathEntry * @see IClasspathContainer * @since 2.0 */ public abstract class ClasspathContainerInitializer { /** * Status code indicating that an attribute is not supported. * * @see #getAccessRulesStatus(IPath, IJavaProject) * @see #getAttributeStatus(IPath, IJavaProject, String) * @see #getSourceAttachmentStatus(IPath, IJavaProject) * * @since 3.3 */ public static final int ATTRIBUTE_NOT_SUPPORTED= 1; /** * Status code indicating that an attribute is not modifiable. * * @see #getAccessRulesStatus(IPath, IJavaProject) * @see #getAttributeStatus(IPath, IJavaProject, String) * @see #getSourceAttachmentStatus(IPath, IJavaProject) * * @since 3.3 */ public static final int ATTRIBUTE_READ_ONLY= 2; /** * Creates a new classpath container initializer. */ public ClasspathContainerInitializer() { // a classpath container initializer must have a public 0-argument constructor } /** * Binds a classpath container to a <code>IClasspathContainer</code> for a given project, or * silently fails if unable to do so. * <p> * A container is identified by a container path, which must be formed of two segments. The * first segment is used as a unique identifier (which this initializer did register onto), and * the second segment can be used as an additional hint when performing the resolution. * <p> * The initializer is invoked if a container path needs to be resolved for a given project, and * no value for it was recorded so far. The implementation of the initializer would typically * set the corresponding container using <code>JavaCore#setClasspathContainer</code>. * <p> * A container initialization can be indirectly performed while attempting to resolve a project * classpath using <code>IJavaProject#getResolvedClasspath(</code>; or directly when using * <code>JavaCore#getClasspathContainer</code>. During the initialization process, any attempt * to further obtain the same container will simply return <code>null</code> so as to avoid an * infinite regression of initializations. * <p> * A container initialization may also occur indirectly when setting a project classpath, as the * operation needs to resolve the classpath for validation purpose. While the operation is in * progress, a referenced container initializer may be invoked. If the initializer further tries * to access the referring project classpath, it will not see the new assigned classpath until * the operation has completed. Note that once the Java change notification occurs (at the end * of the operation), the model has been updated, and the project classpath can be queried * normally. * <p> * This method is called by the Java model to give the party that defined this particular kind * of classpath container the chance to install classpath container objects that will be used to * convert classpath container entries into simpler classpath entries. The method is typically * called exactly once for a given Java project and classpath container entry. This method must * not be called by other clients. * <p> * There are a wide variety of conditions under which this method may be invoked. To ensure that * the implementation does not interfere with correct functioning of the Java model, the * implementation should use only the following Java model APIs: * <ul> * <li> * {@link JavaCore#setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], org.eclipse.core.runtime.IProgressMonitor)} * </li> * <li>{@link JavaCore#getClasspathContainer(IPath, IJavaProject)}</li> * <li>{@link JavaCore#create(org.eclipse.core.resources.IWorkspaceRoot)}</li> * <li>{@link JavaCore#create(org.eclipse.core.resources.IProject)}</li> * <li>{@link IJavaModel#getJavaProjects()}</li> * <li>Java element operations marked as "handle-only"</li> * </ul> * The effects of using other Java model APIs are unspecified. * </p> * * @param containerPath a two-segment path (ID/hint) identifying the container that needs to be * resolved * @param project the Java project in which context the container is to be resolved. This allows * generic containers to be bound with project specific values. * @throws CoreException if an exception occurs during the initialization * * @see JavaCore#getClasspathContainer(IPath, IJavaProject) * @see JavaCore#setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], * org.eclipse.core.runtime.IProgressMonitor) * @see IClasspathContainer */ public abstract void initialize(IPath containerPath, IJavaProject project) throws CoreException; /** * Returns <code>true</code> if this container initializer can be requested to perform updates * on its own container values. If so, then an update request will be performed using * {@link #requestClasspathContainerUpdate(IPath, IJavaProject, IClasspathContainer)}. * <p> * * @param containerPath the path of the container which requires to be updated * @param project the project for which the container is to be updated * @return returns <code>true</code> if the container can be updated * @since 2.1 */ public boolean canUpdateClasspathContainer(IPath containerPath, IJavaProject project) { // By default, classpath container initializers do not accept updating containers return false; } /** * Request a registered container definition to be updated according to a container suggestion. * The container suggestion only acts as a place-holder to pass along the information to update * the matching container definition(s) held by the container initializer. In particular, it is * not expected to store the container suggestion as is, but rather adjust the actual container * definition based on suggested changes. * <p> * IMPORTANT: In reaction to receiving an update request, a container initializer will update * the corresponding container definition (after reconciling changes) at its earliest * convenience, using * {@link JavaCore#setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], IProgressMonitor)} * . Until it does so, the update will not be reflected in the Java Model. * <p> * In order to anticipate whether the container initializer allows to update its containers, the * predicate {@link #canUpdateClasspathContainer(IPath, IJavaProject)} should be used. * <p> * * @param containerPath the path of the container which requires to be updated * @param project the project for which the container is to be updated * @param containerSuggestion a suggestion to update the corresponding container definition * @throws CoreException when <code>JavaCore#setClasspathContainer</code> would throw any. * @see JavaCore#setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], * org.eclipse.core.runtime.IProgressMonitor) * @see ClasspathContainerInitializer#canUpdateClasspathContainer(IPath, IJavaProject) * @since 2.1 */ public void requestClasspathContainerUpdate(IPath containerPath, IJavaProject project, IClasspathContainer containerSuggestion) throws CoreException { // By default, classpath container initializers do not accept updating containers } /** * Returns a readable description for a container path. A readable description for a container * path can be used for improving the display of references to container, without actually * needing to resolve them. A good implementation should answer a description consistent with * the description of the associated target container (see * {@link IClasspathContainer#getDescription()}). * * @param containerPath the path of the container which requires a readable description * @param project the project from which the container is referenced * @return a string description of the container * @since 2.1 */ public String getDescription(IPath containerPath, IJavaProject project) { // By default, a container path is the only available description return containerPath.makeRelative().toString(); } /** * Returns a classpath container that is used after this initializer failed to bind a classpath * container to a {@link IClasspathContainer} for the given project. A non-<code>null</code> * failure container indicates that there will be no more request to initialize the given * container for the given project. * <p> * By default a non-<code>null</code> failure container with no classpath entries is returned. * Clients wishing to get a chance to run the initializer again should override this method and * return <code>null</code>. * </p> * * @param containerPath the path of the container which failed to initialize * @param project the project from which the container is referenced * @return the default failure container, or <code>null</code> if wishing to run the initializer * again * @since 3.3 */ public IClasspathContainer getFailureContainer(final IPath containerPath, IJavaProject project) { final String description= getDescription(containerPath, project); return new IClasspathContainer() { public IClasspathEntry[] getClasspathEntries() { return new IClasspathEntry[0]; } public String getDescription() { return description; } public int getKind() { return 0; } public IPath getPath() { return containerPath; } public String toString() { return getDescription(); } }; } /** * Returns an object which identifies a container for comparison purpose. This allows to * eliminate redundant containers when accumulating classpath entries (e.g. runtime classpath * computation). When requesting a container comparison ID, one should ensure using its * corresponding container initializer. Indeed, a random container initializer cannot be held * responsible for determining comparison IDs for arbitrary containers. * <p> * * @param containerPath the path of the container which is being checked * @param project the project for which the container is to being checked * @return returns an Object identifying the container for comparison * @since 3.0 */ public Object getComparisonID(IPath containerPath, IJavaProject project) { // By default, containers are identical if they have the same containerPath first segment, // but this may be refined by other container initializer implementations. if (containerPath == null) { return null; } else { return containerPath.segment(0); } } /** * Returns the access rules attribute status according to this initializer. * <p> * The returned {@link IStatus status} can have one of the following severities: * <ul> * <li>{@link IStatus#OK OK}: means that the attribute is supported <strong>and</strong> is * modifiable</li> * <li>{@link IStatus#ERROR ERROR}: means that either the attribute is not supported or is not * modifiable.<br> * In this case, the {@link IStatus#getCode() code}will have respectively the * {@link #ATTRIBUTE_NOT_SUPPORTED} value or the {@link #ATTRIBUTE_READ_ONLY} value.</li> * </ul> * </p> * <p> * The status message can contain more information. * </p> * <p> * If the subclass does not override this method, then the default behavior is to return * {@link IStatus#OK OK} if and only if the classpath container can be updated (see * {@link #canUpdateClasspathContainer(IPath, IJavaProject)}). * </p> * * @param containerPath the path of the container which requires to be updated * @param project the project for which the container is to be updated * @return returns the access rules attribute status * * @since 3.3 */ public IStatus getAccessRulesStatus(IPath containerPath, IJavaProject project) { if (canUpdateClasspathContainer(containerPath, project)) { return Status.OK_STATUS; } return new JavaModelStatus(ATTRIBUTE_READ_ONLY); } /** * Returns the extra attribute status according to this initializer. * <p> * The returned {@link IStatus status} can have one of the following severities: * <ul> * <li>{@link IStatus#OK OK}: means that the attribute is supported <strong>and</strong> is * modifiable</li> * <li>{@link IStatus#ERROR ERROR}: means that either the attribute is not supported or is not * modifiable.<br> * In this case, the {@link IStatus#getCode() code}will have respectively the * {@link #ATTRIBUTE_NOT_SUPPORTED} value or the {@link #ATTRIBUTE_READ_ONLY} value.</li> * </ul> * </p> * <p> * The status message can contain more information. * </p> * <p> * If the subclass does not override this method, then the default behavior is to return * {@link IStatus#OK OK} if and only if the classpath container can be updated (see * {@link #canUpdateClasspathContainer(IPath, IJavaProject)}). * </p> * * @param containerPath the path of the container which requires to be updated * @param project the project for which the container is to be updated * @param attributeKey the key of the extra attribute * @return returns the extra attribute status * @see IClasspathAttribute * * @since 3.3 */ public IStatus getAttributeStatus(IPath containerPath, IJavaProject project, String attributeKey) { if (canUpdateClasspathContainer(containerPath, project)) { return Status.OK_STATUS; } return new JavaModelStatus(ATTRIBUTE_READ_ONLY); } /** * Returns the source attachment attribute status according to this initializer. * <p> * The returned {@link IStatus status} can have one of the following severities: * <ul> * <li>{@link IStatus#OK OK}: means that the attribute is supported <strong>and</strong> is * modifiable</li> * <li>{@link IStatus#ERROR ERROR}: means that either the attribute is not supported or is not * modifiable.<br> * In this case, the {@link IStatus#getCode() code}will have respectively the * {@link #ATTRIBUTE_NOT_SUPPORTED} value or the {@link #ATTRIBUTE_READ_ONLY} value.</li> * </ul> * </p> * <p> * The status message can contain more information. * </p> * <p> * If the subclass does not override this method, then the default behavior is to return * {@link IStatus#OK OK} if and only if the classpath container can be updated (see * {@link #canUpdateClasspathContainer(IPath, IJavaProject)}). * </p> * * @param containerPath the path of the container which requires to be updated * @param project the project for which the container is to be updated * @return returns the source attachment attribute status * * @since 3.3 */ public IStatus getSourceAttachmentStatus(IPath containerPath, IJavaProject project) { if (canUpdateClasspathContainer(containerPath, project)) { return Status.OK_STATUS; } return new JavaModelStatus(ATTRIBUTE_READ_ONLY); } }