001: /*******************************************************************************
002: * Copyright (c) 2000, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: * IBM Corporation - added support for requesting updates of a particular
011: * container for generic container operations.
012: * - canUpdateClasspathContainer(IPath, IJavaProject)
013: * - requestClasspathContainerUpdate(IPath, IJavaProject, IClasspathContainer)
014: * IBM Corporation - allow initializers to provide a readable description
015: * of a container reference, ahead of actual resolution.
016: * - getDescription(IPath, IJavaProject)
017: *******************************************************************************/package org.eclipse.jdt.core;
018:
019: import org.eclipse.core.runtime.*;
020: import org.eclipse.jdt.internal.core.JavaModelStatus;
021:
022: /**
023: * Abstract base implementation of all classpath container initializer.
024: * Classpath variable containers are used in conjunction with the
025: * "org.eclipse.jdt.core.classpathContainerInitializer" extension point.
026: * <p>
027: * Clients should subclass this class to implement a specific classpath
028: * container initializer. The subclass must have a public 0-argument
029: * constructor and a concrete implementation of {@link #initialize(IPath, IJavaProject)}.
030: * <p>
031: * Multiple classpath containers can be registered, each of them declares
032: * the container ID they can handle, so as to narrow the set of containers they
033: * can resolve, in other words, a container initializer is guaranteed to only be
034: * activated to resolve containers which match the ID they registered onto.
035: * <p>
036: * In case multiple container initializers collide on the same container ID, the first
037: * registered one will be invoked.
038: *
039: * @see IClasspathEntry
040: * @see IClasspathContainer
041: * @since 2.0
042: */
043: public abstract class ClasspathContainerInitializer {
044:
045: /**
046: * Status code indicating that an attribute is not supported.
047: *
048: * @see #getAccessRulesStatus(IPath, IJavaProject)
049: * @see #getAttributeStatus(IPath, IJavaProject, String)
050: * @see #getSourceAttachmentStatus(IPath, IJavaProject)
051: *
052: * @since 3.3
053: */
054: public static final int ATTRIBUTE_NOT_SUPPORTED = 1;
055:
056: /**
057: * Status code indicating that an attribute is not modifiable.
058: *
059: * @see #getAccessRulesStatus(IPath, IJavaProject)
060: * @see #getAttributeStatus(IPath, IJavaProject, String)
061: * @see #getSourceAttachmentStatus(IPath, IJavaProject)
062: *
063: * @since 3.3
064: */
065: public static final int ATTRIBUTE_READ_ONLY = 2;
066:
067: /**
068: * Creates a new classpath container initializer.
069: */
070: public ClasspathContainerInitializer() {
071: // a classpath container initializer must have a public 0-argument constructor
072: }
073:
074: /**
075: * Binds a classpath container to a <code>IClasspathContainer</code> for a given project,
076: * or silently fails if unable to do so.
077: * <p>
078: * A container is identified by a container path, which must be formed of two segments.
079: * The first segment is used as a unique identifier (which this initializer did register onto), and
080: * the second segment can be used as an additional hint when performing the resolution.
081: * <p>
082: * The initializer is invoked if a container path needs to be resolved for a given project, and no
083: * value for it was recorded so far. The implementation of the initializer would typically set the
084: * corresponding container using <code>JavaCore#setClasspathContainer</code>.
085: * <p>
086: * A container initialization can be indirectly performed while attempting to resolve a project
087: * classpath using <code>IJavaProject#getResolvedClasspath(</code>; or directly when using
088: * <code>JavaCore#getClasspathContainer</code>. During the initialization process, any attempt
089: * to further obtain the same container will simply return <code>null</code> so as to avoid an
090: * infinite regression of initializations.
091: * <p>
092: * A container initialization may also occur indirectly when setting a project classpath, as the operation
093: * needs to resolve the classpath for validation purpose. While the operation is in progress, a referenced
094: * container initializer may be invoked. If the initializer further tries to access the referring project classpath,
095: * it will not see the new assigned classpath until the operation has completed. Note that once the Java
096: * change notification occurs (at the end of the operation), the model has been updated, and the project
097: * classpath can be queried normally.
098: * <p>
099: * This method is called by the Java model to give the party that defined
100: * this particular kind of classpath container the chance to install
101: * classpath container objects that will be used to convert classpath
102: * container entries into simpler classpath entries. The method is typically
103: * called exactly once for a given Java project and classpath container
104: * entry. This method must not be called by other clients.
105: * <p>
106: * There are a wide variety of conditions under which this method may be
107: * invoked. To ensure that the implementation does not interfere with
108: * correct functioning of the Java model, the implementation should use
109: * only the following Java model APIs:
110: * <ul>
111: * <li>{@link JavaCore#setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], org.eclipse.core.runtime.IProgressMonitor)}</li>
112: * <li>{@link JavaCore#getClasspathContainer(IPath, IJavaProject)}</li>
113: * <li>{@link JavaCore#create(org.eclipse.core.resources.IWorkspaceRoot)}</li>
114: * <li>{@link JavaCore#create(org.eclipse.core.resources.IProject)}</li>
115: * <li>{@link IJavaModel#getJavaProjects()}</li>
116: * <li>Java element operations marked as "handle-only"</li>
117: * </ul>
118: * The effects of using other Java model APIs are unspecified.
119: * </p>
120: *
121: * @param containerPath a two-segment path (ID/hint) identifying the container that needs
122: * to be resolved
123: * @param project the Java project in which context the container is to be resolved.
124: * This allows generic containers to be bound with project specific values.
125: * @throws CoreException if an exception occurs during the initialization
126: *
127: * @see JavaCore#getClasspathContainer(IPath, IJavaProject)
128: * @see JavaCore#setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], org.eclipse.core.runtime.IProgressMonitor)
129: * @see IClasspathContainer
130: */
131: public abstract void initialize(IPath containerPath,
132: IJavaProject project) throws CoreException;
133:
134: /**
135: * Returns <code>true</code> if this container initializer can be requested to perform updates
136: * on its own container values. If so, then an update request will be performed using
137: * {@link #requestClasspathContainerUpdate(IPath, IJavaProject, IClasspathContainer)}.
138: * <p>
139: * @param containerPath the path of the container which requires to be updated
140: * @param project the project for which the container is to be updated
141: * @return returns <code>true</code> if the container can be updated
142: * @since 2.1
143: */
144: public boolean canUpdateClasspathContainer(IPath containerPath,
145: IJavaProject project) {
146:
147: // By default, classpath container initializers do not accept updating containers
148: return false;
149: }
150:
151: /**
152: * Request a registered container definition to be updated according to a container suggestion. The container suggestion
153: * only acts as a place-holder to pass along the information to update the matching container definition(s) held by the
154: * container initializer. In particular, it is not expected to store the container suggestion as is, but rather adjust
155: * the actual container definition based on suggested changes.
156: * <p>
157: * IMPORTANT: In reaction to receiving an update request, a container initializer will update the corresponding
158: * container definition (after reconciling changes) at its earliest convenience, using
159: * {@link JavaCore#setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], IProgressMonitor)}.
160: * Until it does so, the update will not be reflected in the Java Model.
161: * <p>
162: * In order to anticipate whether the container initializer allows to update its containers, the predicate
163: * {@link #canUpdateClasspathContainer(IPath, IJavaProject)} should be used.
164: * <p>
165: * @param containerPath the path of the container which requires to be updated
166: * @param project the project for which the container is to be updated
167: * @param containerSuggestion a suggestion to update the corresponding container definition
168: * @throws CoreException when <code>JavaCore#setClasspathContainer</code> would throw any.
169: * @see JavaCore#setClasspathContainer(IPath, IJavaProject[], IClasspathContainer[], org.eclipse.core.runtime.IProgressMonitor)
170: * @see ClasspathContainerInitializer#canUpdateClasspathContainer(IPath, IJavaProject)
171: * @since 2.1
172: */
173:
174: public void requestClasspathContainerUpdate(IPath containerPath,
175: IJavaProject project,
176: IClasspathContainer containerSuggestion)
177: throws CoreException {
178:
179: // By default, classpath container initializers do not accept updating containers
180: }
181:
182: /**
183: * Returns a readable description for a container path. A readable description for a container path can be
184: * used for improving the display of references to container, without actually needing to resolve them.
185: * A good implementation should answer a description consistent with the description of the associated
186: * target container (see {@link IClasspathContainer#getDescription()}).
187: *
188: * @param containerPath the path of the container which requires a readable description
189: * @param project the project from which the container is referenced
190: * @return a string description of the container
191: * @since 2.1
192: */
193: public String getDescription(IPath containerPath,
194: IJavaProject project) {
195:
196: // By default, a container path is the only available description
197: return containerPath.makeRelative().toString();
198: }
199:
200: /**
201: * Returns a classpath container that is used after this initializer failed to bind a classpath container
202: * to a {@link IClasspathContainer} for the given project. A non-<code>null</code>
203: * failure container indicates that there will be no more request to initialize the given container
204: * for the given project.
205: * <p>
206: * By default a non-<code>null</code> failure container with no classpath entries is returned.
207: * Clients wishing to get a chance to run the initializer again should override this method
208: * and return <code>null</code>.
209: * </p>
210: *
211: * @param containerPath the path of the container which failed to initialize
212: * @param project the project from which the container is referenced
213: * @return the default failure container, or <code>null</code> if wishing to run the initializer again
214: * @since 3.3
215: */
216: public IClasspathContainer getFailureContainer(
217: final IPath containerPath, IJavaProject project) {
218: final String description = getDescription(containerPath,
219: project);
220: return new IClasspathContainer() {
221: public IClasspathEntry[] getClasspathEntries() {
222: return new IClasspathEntry[0];
223: }
224:
225: public String getDescription() {
226: return description;
227: }
228:
229: public int getKind() {
230: return 0;
231: }
232:
233: public IPath getPath() {
234: return containerPath;
235: }
236:
237: public String toString() {
238: return getDescription();
239: }
240: };
241: }
242:
243: /**
244: * Returns an object which identifies a container for comparison purpose. This allows
245: * to eliminate redundant containers when accumulating classpath entries (e.g.
246: * runtime classpath computation). When requesting a container comparison ID, one
247: * should ensure using its corresponding container initializer. Indeed, a random container
248: * initializer cannot be held responsible for determining comparison IDs for arbitrary
249: * containers.
250: * <p>
251: * @param containerPath the path of the container which is being checked
252: * @param project the project for which the container is to being checked
253: * @return returns an Object identifying the container for comparison
254: * @since 3.0
255: */
256: public Object getComparisonID(IPath containerPath,
257: IJavaProject project) {
258:
259: // By default, containers are identical if they have the same containerPath first segment,
260: // but this may be refined by other container initializer implementations.
261: if (containerPath == null) {
262: return null;
263: } else {
264: return containerPath.segment(0);
265: }
266: }
267:
268: /**
269: * Returns the access rules attribute status according to this initializer.
270: * <p>
271: * The returned {@link IStatus status} can have one of the following severities:
272: * <ul>
273: * <li>{@link IStatus#OK OK}: means that the attribute is supported
274: * <strong>and</strong> is modifiable</li>
275: * <li>{@link IStatus#ERROR ERROR}: means that either the attribute
276: * is not supported or is not modifiable.<br>
277: * In this case, the {@link IStatus#getCode() code}will have
278: * respectively the {@link #ATTRIBUTE_NOT_SUPPORTED} value
279: * or the {@link #ATTRIBUTE_READ_ONLY} value.</li>
280: * </ul>
281: * </p><p>
282: * The status message can contain more information.
283: * </p><p>
284: * If the subclass does not override this method, then the default behavior is
285: * to return {@link IStatus#OK OK} if and only if the classpath container can
286: * be updated (see {@link #canUpdateClasspathContainer(IPath, IJavaProject)}).
287: * </p>
288: *
289: * @param containerPath the path of the container which requires to be
290: * updated
291: * @param project the project for which the container is to be updated
292: * @return returns the access rules attribute status
293: *
294: * @since 3.3
295: */
296: public IStatus getAccessRulesStatus(IPath containerPath,
297: IJavaProject project) {
298:
299: if (canUpdateClasspathContainer(containerPath, project)) {
300: return Status.OK_STATUS;
301: }
302: return new JavaModelStatus(ATTRIBUTE_READ_ONLY);
303: }
304:
305: /**
306: * Returns the extra attribute status according to this initializer.
307: * <p>
308: * The returned {@link IStatus status} can have one of the following severities:
309: * <ul>
310: * <li>{@link IStatus#OK OK}: means that the attribute is supported
311: * <strong>and</strong> is modifiable</li>
312: * <li>{@link IStatus#ERROR ERROR}: means that either the attribute
313: * is not supported or is not modifiable.<br>
314: * In this case, the {@link IStatus#getCode() code}will have
315: * respectively the {@link #ATTRIBUTE_NOT_SUPPORTED} value
316: * or the {@link #ATTRIBUTE_READ_ONLY} value.</li>
317: * </ul>
318: * </p><p>
319: * The status message can contain more information.
320: * </p><p>
321: * If the subclass does not override this method, then the default behavior is
322: * to return {@link IStatus#OK OK} if and only if the classpath container can
323: * be updated (see {@link #canUpdateClasspathContainer(IPath, IJavaProject)}).
324: * </p>
325: *
326: * @param containerPath the path of the container which requires to be
327: * updated
328: * @param project the project for which the container is to be updated
329: * @param attributeKey the key of the extra attribute
330: * @return returns the extra attribute status
331: * @see IClasspathAttribute
332: *
333: * @since 3.3
334: */
335: public IStatus getAttributeStatus(IPath containerPath,
336: IJavaProject project, String attributeKey) {
337:
338: if (canUpdateClasspathContainer(containerPath, project)) {
339: return Status.OK_STATUS;
340: }
341: return new JavaModelStatus(ATTRIBUTE_READ_ONLY);
342: }
343:
344: /**
345: * Returns the source attachment attribute status according to this initializer.
346: * <p>
347: * The returned {@link IStatus status} can have one of the following severities:
348: * <ul>
349: * <li>{@link IStatus#OK OK}: means that the attribute is supported
350: * <strong>and</strong> is modifiable</li>
351: * <li>{@link IStatus#ERROR ERROR}: means that either the attribute
352: * is not supported or is not modifiable.<br>
353: * In this case, the {@link IStatus#getCode() code}will have
354: * respectively the {@link #ATTRIBUTE_NOT_SUPPORTED} value
355: * or the {@link #ATTRIBUTE_READ_ONLY} value.</li>
356: * </ul>
357: * </p><p>
358: * The status message can contain more information.
359: * </p><p>
360: * If the subclass does not override this method, then the default behavior is
361: * to return {@link IStatus#OK OK} if and only if the classpath container can
362: * be updated (see {@link #canUpdateClasspathContainer(IPath, IJavaProject)}).
363: * </p>
364: *
365: * @param containerPath the path of the container which requires to be
366: * updated
367: * @param project the project for which the container is to be updated
368: * @return returns the source attachment attribute status
369: *
370: * @since 3.3
371: */
372: public IStatus getSourceAttachmentStatus(IPath containerPath,
373: IJavaProject project) {
374:
375: if (canUpdateClasspathContainer(containerPath, project)) {
376: return Status.OK_STATUS;
377: }
378: return new JavaModelStatus(ATTRIBUTE_READ_ONLY);
379: }
380: }
|