/*******************************************************************************
* Copyright (c) 2006, 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.jdt.core.refactoring.descriptors;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.resources.IResource;
import org.eclipse.ltk.core.refactoring.Refactoring;
import org.eclipse.ltk.core.refactoring.RefactoringContribution;
import org.eclipse.ltk.core.refactoring.RefactoringCore;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptor;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.WorkingCopyOwner;
import org.eclipse.jdt.internal.core.manipulation.JavaManipulationPlugin;
import org.eclipse.jdt.internal.core.refactoring.descriptors.DescriptorMessages;
import org.eclipse.jdt.internal.core.refactoring.descriptors.JavaRefactoringDescriptorUtil;
/**
* Partial implementation of a java refactoring descriptor.
* <p>
* This class provides features common to all Java refactorings.
* </p>
* <p>
* Note: this class is not intended to be extended outside the refactoring framework.
* </p>
*
* @since 1.1
*
* @author Mohsen Vakilian, nchen - Added ability to add more information by cloning an existing
* RefactoringDescriptor. Also, made getArguments and some of the attributes public.
*
* @noextend This class is not intended to be subclassed by clients outside JDT.
*/
public class JavaRefactoringDescriptor extends RefactoringDescriptor {
/**
* Predefined argument called <code>element<Number></code>.
* <p>
* This argument should be used to describe the elements being refactored. The value of this
* argument does not necessarily have to uniquely identify the elements. However, it must be
* possible to uniquely identify the elements using the value of this argument in conjunction
* with the values of the other user-defined attributes.
* </p>
* <p>
* The element arguments are simply distinguished by appending a number to the argument name,
* e.g. element1. The indices of this argument are one-based.
* </p>
*
* CODINGSPECTATOR: Made the attribute accessible by edu.illinois.codingspectator.ui.tests.
*/
public static final String ATTRIBUTE_ELEMENT= "element"; //$NON-NLS-1$
/**
* Predefined argument called <code>input</code>.
* <p>
* This argument should be used to describe the element being refactored. The value of this
* argument does not necessarily have to uniquely identify the input element. However, it must
* be possible to uniquely identify the input element using the value of this argument in
* conjunction with the values of the other user-defined attributes.
* </p>
*
* CODINGSPECTATOR: Made the attribute accessible by edu.illinois.codingspectator.ui.tests.
*
*/
public static final String ATTRIBUTE_INPUT= "input"; //$NON-NLS-1$
/**
* Predefined argument called <code>name</code>.
* <p>
* This argument should be used to name the element being refactored. The value of this argument
* may be shown in the user interface.
* </p>
*
* CODINGSPECTATOR: Made the attribute accessible by edu.illinois.codingspectator.ui.tests.
*
*/
public static final String ATTRIBUTE_NAME= "name"; //$NON-NLS-1$
/**
* Predefined argument called <code>references</code>.
* <p>
* This argument should be used to describe whether references to the elements being refactored
* should be updated as well. The value of this argument is either <code>"true"</code> or
* <code>"false"</code>.
* </p>
*
* CODINGSPECTATOR: Made the attribute accessible by edu.illinois.codingspectator.ui.tests.
*
*/
public static final String ATTRIBUTE_REFERENCES= "references"; //$NON-NLS-1$
/**
* Predefined argument called <code>selection</code>.
* <p>
* This argument should be used to describe user input selections within a text file. The value
* of this argument has the format "offset length".
* </p>
*
* CODINGSPECTATOR: Made the attribute accessible by edu.illinois.codingspectator.ui.tests.
*
*/
public static final String ATTRIBUTE_SELECTION= "selection"; //$NON-NLS-1$
/** The version attribute */
protected static final String ATTRIBUTE_VERSION= "version"; //$NON-NLS-1$
/**
* Constant describing the jar migration flag (value: <code>65536</code>).
* <p>
* Clients should set this flag to indicate that the refactoring can be stored to a JAR file in
* order to be accessible to the Migrate JAR File refactoring, regardless whether there is a
* source attachment to the JAR file or not. If this flag is set, <code>JAR_REFACTORING</code>
* should be set as well.
* </p>
*
* @see #JAR_REFACTORING
*/
public static final int JAR_MIGRATION= 1 << 16;
/**
* Constant describing the jar refactoring flag (value: <code>524288</code>).
* <p>
* Clients should set this flag to indicate that the refactoring in principle can be performed
* on binary elements originating from a JAR file. Refactorings which are able to run on binary
* elements, but require a correctly configured source attachment to work must set the
* <code>JAR_SOURCE_ATTACHMENT</code> flag as well.
* </p>
*
* @see #JAR_SOURCE_ATTACHMENT
*/
public static final int JAR_REFACTORING= 1 << 19;
/**
* Constant describing the jar source attachment flag (value: <code>262144</code>).
* <p>
* Clients should set this flag to indicate that the refactoring can be performed on binary
* elements originating from a JAR file if and only if it has a correctly configured source
* attachment.
* </p>
*
* @see #JAR_REFACTORING
*/
public static final int JAR_SOURCE_ATTACHMENT= 1 << 18;
/** The version value <code>1.0</code> */
protected static final String VALUE_VERSION_1_0= "1.0"; //$NON-NLS-1$
/**
* Converts the specified element to an input handle.
*
* @param project the project, or <code>null</code> for the workspace
* @param element the element
* @return a corresponding input handle
*/
protected static String elementToHandle(final String project, final IJavaElement element) {
return JavaRefactoringDescriptorUtil.elementToHandle(project, element);
}
/**
* Converts an input handle back to the corresponding java element.
*
* @param project the project, or <code>null</code> for the workspace
* @param handle the input handle
* @return the corresponding java element, or <code>null</code> if no such element exists
*/
protected static IJavaElement handleToElement(final String project, final String handle) {
return handleToElement(project, handle, true);
}
/**
* Converts an input handle back to the corresponding java element.
*
* @param project the project, or <code>null</code> for the workspace
* @param handle the input handle
* @param check <code>true</code> to check for existence of the element, <code>false</code>
* otherwise
* @return the corresponding java element, or <code>null</code> if no such element exists
*/
protected static IJavaElement handleToElement(final String project, final String handle, final boolean check) {
return handleToElement(null, project, handle, check);
}
/**
* Converts an input handle back to the corresponding java element.
*
* @param owner the working copy owner
* @param project the project, or <code>null</code> for the workspace
* @param handle the input handle
* @param check <code>true</code> to check for existence of the element, <code>false</code>
* otherwise
* @return the corresponding java element, or <code>null</code> if no such element exists
*/
protected static IJavaElement handleToElement(final WorkingCopyOwner owner, final String project, final String handle, final boolean check) {
return JavaRefactoringDescriptorUtil.handleToElement(owner, project, handle, check);
}
/**
* Converts an input handle with the given prefix back to the corresponding resource.
*
* @param project the project, or <code>null</code> for the workspace
* @param handle the input handle
*
* @return the corresponding resource, or <code>null</code> if no such resource exists
*/
protected static IResource handleToResource(final String project, final String handle) {
return JavaRefactoringDescriptorUtil.handleToResource(project, handle);
}
/**
* Converts the specified resource to an input handle.
*
* @param project the project, or <code>null</code> for the workspace
* @param resource the resource
*
* @return the input handle
*/
protected static String resourceToHandle(final String project, final IResource resource) {
return JavaRefactoringDescriptorUtil.resourcePathToHandle(project, resource.getFullPath());
}
/**
* The argument map (key type: {@link String}, value type: {@link String}).
*/
protected final Map fArguments;
/**
* Creates a new java refactoring descriptor.
*
* @param id the unique id of the refactoring
*/
protected JavaRefactoringDescriptor(final String id) {
this(id, null, DescriptorMessages.JavaRefactoringDescriptor_not_available, null, new HashMap(), RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE);
}
/**
* Creates a new Java refactoring descriptor.
*
* @param id the unique id of the refactoring
* @param project the non-empty name of the project associated with this refactoring, or
* <code>null</code> for a workspace refactoring
* @param description a non-empty human-readable description of the particular refactoring
* instance
* @param comment the human-readable comment of the particular refactoring instance, or
* <code>null</code> for no comment
* @param arguments a map of arguments that will be persisted and describes all settings for
* this refactoring
* @param flags the flags of the refactoring descriptor
*
* @since 1.2
*/
public JavaRefactoringDescriptor(final String id, final String project, final String description, final String comment, final Map arguments, final int flags) {
super(id, project, description, comment, flags);
fArguments= arguments;
fArguments.put(ATTRIBUTE_VERSION, VALUE_VERSION_1_0);
}
/**
* {@inheritDoc}
*/
public Refactoring createRefactoring(final RefactoringStatus status) throws CoreException {
Refactoring refactoring= null;
final String id= getID();
final RefactoringContribution contribution= RefactoringCore.getRefactoringContribution(id);
if (contribution != null) {
if (contribution instanceof JavaRefactoringContribution) {
JavaRefactoringContribution javaContribution= (JavaRefactoringContribution)contribution;
refactoring= javaContribution.createRefactoring(this, status);
} else
JavaManipulationPlugin.log(new Status(IStatus.ERROR, JavaManipulationPlugin.getPluginId(), 0, MessageFormat.format(
DescriptorMessages.JavaRefactoringDescriptor_no_resulting_descriptor, new Object[] { id }), null));
}
return refactoring;
}
/**
* Returns the argument map of this refactoring descriptor.
* <p>
* The returned map is a copy of the argument map. Modifying the result does not change the
* refactoring descriptor itself.
* </p>
* <p>
* Note: This API must not be extended or reimplemented and should not be called from outside
* the refactoring framework.
* </p>
*
* CODINGSPECTATOR: Made the method public.
*
* @return the argument map (key type: {@link String}, value type: {@link String})
*/
public Map getArguments() {
populateArgumentMap();
return new HashMap(fArguments);
}
/**
* Populates the refactoring descriptor argument map based on the specified arguments.
* Subclasses should extend and add their arguments to {@link #fArguments}.
*/
protected void populateArgumentMap() {
RefactoringStatus status= validateDescriptor();
if (status.hasFatalError())
throw new RuntimeException("Validation returns a fatal error status", new CoreException(status.getEntryWithHighestSeverity().toStatus())); //$NON-NLS-1$
}
/**
* Sets the details comment of this refactoring.
* <p>
* This information is used in the user interface to show additional details about the performed
* refactoring. The default is to use no details comment.
* </p>
*
* @param comment the details comment to set, or <code>null</code> to set no details comment
*
* @see #getComment()
*/
public void setComment(final String comment) {
super.setComment(comment);
}
/**
* Sets the description of this refactoring.
* <p>
* This information is used to label a refactoring in the user interface. The default is an
* unspecified, but legal description.
* </p>
*
* @param description the non-empty description of the refactoring to set
*
* @see #getDescription()
*/
public void setDescription(final String description) {
super.setDescription(description);
}
/**
* Sets the flags of this refactoring.
* <p>
* The default is
* <code>RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE</code>,
* unless overridden by a concrete subclass. Clients may use refactoring flags to indicate
* special capabilities of Java refactorings.
* </p>
*
* @param flags the flags to set, or <code>RefactoringDescriptor.NONE</code> to clear the flags
*
* @see #getFlags()
*
* @see RefactoringDescriptor#NONE
* @see RefactoringDescriptor#STRUCTURAL_CHANGE
* @see RefactoringDescriptor#BREAKING_CHANGE
* @see RefactoringDescriptor#MULTI_CHANGE
*
* @see #JAR_MIGRATION
* @see #JAR_REFACTORING
* @see #JAR_SOURCE_ATTACHMENT
*/
public void setFlags(final int flags) {
super.setFlags(flags);
}
/**
* Sets the project name of this refactoring.
* <p>
* The default is to associate the refactoring with the workspace. Subclasses should call this
* method with the project name associated with the refactoring's input elements, if available.
* </p>
*
* @param project the non-empty project name to set, or <code>null</code> for the workspace
*
* @see #getProject()
*/
public void setProject(final String project) {
super.setProject(project);
}
/**
* Validates the refactoring descriptor with respect to the constraints imposed by the
* represented refactoring.
* <p>
* Clients must call this method to verify that all arguments have been correctly set and that
* they satisfy the constraints imposed by specific refactorings. Returning a refactoring status
* of severity {@link RefactoringStatus#FATAL} indicates that the refactoring descriptor cannot
* be used to create a refactoring instance.
* </p>
*
* @return a refactoring status describing the outcome of the validation
*/
public RefactoringStatus validateDescriptor() {
RefactoringStatus status= new RefactoringStatus();
String description= getDescription();
if (description == null || "".equals(description)) //$NON-NLS-1$
status.merge(RefactoringStatus.createFatalErrorStatus(DescriptorMessages.JavaRefactoringDescriptor_no_description));
return status;
}
/////////////////
//CODINGSPECTATOR
/////////////////
public RefactoringDescriptor cloneByAugmenting(Map arguments) {
Map augmentedArguments= new HashMap(getArguments());
augmentedArguments.putAll(arguments);
JavaRefactoringDescriptor augmentedDescriptor= new JavaRefactoringDescriptor(getID(), getProject(), getDescription(), getComment(), augmentedArguments, getFlags());
if (getTimeStamp() != -1) {
augmentedDescriptor.setTimeStamp(getTimeStamp());
}
return augmentedDescriptor;
}
protected boolean isCapturedByCodingSpectator() {
return fArguments.containsKey(RefactoringDescriptor.CAPTURED_BY_CODINGSPECTATOR_ATTRIBUTE);
}
}