| /******************************************************************************* |
| * 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 v2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.wst.jsdt.core.refactoring.descriptors; |
| |
| import java.text.MessageFormat; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.eclipse.core.runtime.Assert; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Status; |
| |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.resources.IWorkspaceRoot; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| |
| 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.wst.jsdt.core.IJavaScriptElement; |
| import org.eclipse.wst.jsdt.core.IJavaScriptProject; |
| import org.eclipse.wst.jsdt.core.IFunction; |
| import org.eclipse.wst.jsdt.core.JavaScriptCore; |
| import org.eclipse.wst.jsdt.core.WorkingCopyOwner; |
| |
| import org.eclipse.wst.jsdt.internal.core.manipulation.JavaManipulationPlugin; |
| import org.eclipse.wst.jsdt.internal.core.refactoring.descriptors.DescriptorMessages; |
| |
| /** |
| * 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> |
| * |
| * Provisional API: This class/interface is part of an interim API that is still under development and expected to |
| * change significantly before reaching stability. It is being made available at this early stage to solicit feedback |
| * from pioneering adopters on the understanding that any code that uses this API will almost certainly be broken |
| * (repeatedly) as the API evolves. |
| */ |
| public abstract class JavaScriptRefactoringDescriptor 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> |
| */ |
| protected 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> |
| */ |
| protected 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> |
| */ |
| protected 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> |
| */ |
| protected 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> |
| */ |
| protected 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 IJavaScriptElement element) { |
| final String handle= element.getHandleIdentifier(); |
| if (project != null && !(element instanceof IJavaScriptProject)) { |
| final String id= element.getJavaScriptProject().getHandleIdentifier(); |
| return handle.substring(id.length()); |
| } |
| return handle; |
| } |
| |
| /** |
| * 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 IJavaScriptElement 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 IJavaScriptElement 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 IJavaScriptElement handleToElement(final WorkingCopyOwner owner, final String project, final String handle, final boolean check) { |
| IJavaScriptElement element= null; |
| if (owner != null) |
| element= JavaScriptCore.create(handle, owner); |
| else |
| element= JavaScriptCore.create(handle); |
| if (element == null && project != null) { |
| final IJavaScriptProject javaProject= JavaScriptCore.create(ResourcesPlugin.getWorkspace().getRoot()).getJavaScriptProject(project); |
| final String identifier= javaProject.getHandleIdentifier(); |
| if (owner != null) |
| element= JavaScriptCore.create(identifier + handle, owner); |
| else |
| element= JavaScriptCore.create(identifier + handle); |
| } |
| if (check && element instanceof IFunction) { |
| final IFunction method= (IFunction) element; |
| final IFunction[] methods= (method.getDeclaringType()!=null) ? method.getDeclaringType().findMethods(method) |
| : new IFunction[]{ method.getJavaScriptUnit().getFunction(method.getElementName(), method.getParameterTypes())}; |
| if (methods != null && methods.length > 0) |
| element= methods[0]; |
| } |
| if (element != null && (!check || element.exists())) |
| return element; |
| return null; |
| } |
| |
| /** |
| * 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) { |
| final IWorkspaceRoot root= ResourcesPlugin.getWorkspace().getRoot(); |
| if ("".equals(handle)) //$NON-NLS-1$ |
| return null; |
| final IPath path= Path.fromPortableString(handle); |
| if (path == null) |
| return null; |
| if (project != null && !"".equals(project)) //$NON-NLS-1$ |
| return root.getProject(project).findMember(path); |
| return root.findMember(path); |
| } |
| |
| /** |
| * 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) { |
| if (project != null && !"".equals(project)) //$NON-NLS-1$ |
| return resource.getProjectRelativePath().toPortableString(); |
| return resource.getFullPath().toPortableString(); |
| } |
| |
| /** The argument map */ |
| protected final Map fArguments; |
| |
| /** |
| * Creates a new java refactoring descriptor. |
| * |
| * @param id |
| * the unique id of the refactoring |
| */ |
| protected JavaScriptRefactoringDescriptor(final String id) { |
| this(id, new HashMap()); |
| } |
| |
| /** |
| * Creates a new java refactoring descriptor. |
| * |
| * @param id |
| * the unique id of the refactoring |
| * @param arguments |
| * the argument map to use |
| */ |
| protected JavaScriptRefactoringDescriptor(final String id, final Map arguments) { |
| super(id, null, DescriptorMessages.JavaRefactoringDescriptor_not_available, null, RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE); |
| fArguments= arguments; |
| fArguments.put(ATTRIBUTE_VERSION, VALUE_VERSION_1_0); |
| } |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Refactoring createRefactoring(final RefactoringStatus status) throws CoreException { |
| populateArgumentMap(); |
| Refactoring refactoring= null; |
| final String id= getID(); |
| final RefactoringContribution contribution= RefactoringCore.getRefactoringContribution(id); |
| if (contribution != null) { |
| final RefactoringDescriptor descriptor= contribution.createDescriptor(id, getProject(), getDescription(), getComment(), fArguments, getFlags()); |
| if (descriptor != null) { |
| refactoring= descriptor.createRefactoring(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> |
| * |
| * @return the argument map |
| */ |
| protected Map getArguments() { |
| populateArgumentMap(); |
| return new HashMap(fArguments); |
| } |
| |
| /** |
| * Populates the refactoring descriptor argument map based on the specified |
| * arguments. |
| */ |
| protected void populateArgumentMap() { |
| Assert.isTrue(!validateDescriptor().hasFatalError(), "Validation returns a fatal error status."); //$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; |
| } |
| } |