Copyright (c) 2005, 2015 IBM Corporation and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: IBM Corporation - initial API and implementation Sergey Prigogin - [refactoring] Provide a way to implement refactorings that depend on resources that have to be explicitly released - https://bugs.eclipse.org/347599
/******************************************************************************* * Copyright (c) 2005, 2015 IBM Corporation and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * IBM Corporation - initial API and implementation * Sergey Prigogin <eclipse.sprigogin@gmail.com> - [refactoring] Provide a way to implement refactorings that depend on resources that have to be explicitly released - https://bugs.eclipse.org/347599 *******************************************************************************/
package org.eclipse.ltk.core.refactoring; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.CoreException; import org.eclipse.ltk.core.refactoring.history.IRefactoringExecutionListener; import org.eclipse.ltk.core.refactoring.history.IRefactoringHistoryListener; import org.eclipse.ltk.core.refactoring.history.IRefactoringHistoryService;
Descriptor object of a refactoring.

A refactoring descriptor contains refactoring-specific data which allows the framework to completely reconstruct a particular refactoring instance and execute it on an arbitrary workspace.

Refactoring descriptors contain the following information:

  • a short description string, which provides a human-readable text designed to be displayed in the user interface to represent the refactoring in trees and lists. Descriptions are automatically generated by refactorings.
  • an optional comment string, which provides a full human-readable description of the refactoring. Comments are automatically generated by refactorings and provide more refactoring-specific information, such as which elements have participated in the refactoring.
  • refactoring descriptor flags, which tell the framework what capabilities or properties a certain refactorings has when executed in a remote context.
  • a timestamp, measured as the milliseconds since January 1, 1970, 00:00:00 GMT, which denotes the original execution time of the refactoring.
  • a unique ID, which denotes a certain kind of refactoring (e.g. Rename File). This ID is usually composed of the plugin identifier of the contributing plugin and a plugin-wide unique identifier (e.g. org.eclipse.ltk.core.refactoring.renameFile).
  • the optional name of the project this refactoring is associated with. Note that the project name is not available if the refactoring cannot be associated with a single project, or the refactoring descriptor has been read from a file which cannot be associated with a project.

Refactoring descriptors are identified by their refactoring id getID() and their time stamps getTimeStamp() and are potentially heavy weight objects which should not be held on to. Use refactoring descriptor proxies RefactoringDescriptorProxy to present refactoring descriptors in the user interface or otherwise manipulate refactoring histories.

Clients which create specific refactoring descriptors during change generation should choose a short, informative and human-readable description of the particular refactoring instance and pass appropriate descriptor flags to the constructor. More details about a particular refactoring can be revealed in the comment, which contains more text with refactoring-specific information.

Refactoring descriptors do not provide version information. It is the responsibility of the client to enhance subclasses with refactoring version information in order to provide a means of schema evolution.

All time stamps are measured as the milliseconds since January 1, 1970, 00:00:00 GMT.

Note: this class is indented to be subclassed by clients to provide specialized refactoring descriptors for particular refactorings.

See Also:
Since:3.2
/** * Descriptor object of a refactoring. * <p> * A refactoring descriptor contains refactoring-specific data which allows the * framework to completely reconstruct a particular refactoring instance and * execute it on an arbitrary workspace. * </p> * <p> * Refactoring descriptors contain the following information: * </p> * <ul> * <li>a short description string, which provides a human-readable text * designed to be displayed in the user interface to represent the refactoring * in trees and lists. Descriptions are automatically generated by refactorings.</li> * <li> an optional comment string, which provides a full human-readable * description of the refactoring. Comments are automatically generated by * refactorings and provide more refactoring-specific information, such as which * elements have participated in the refactoring. </li> * <li> refactoring descriptor flags, which tell the framework what capabilities * or properties a certain refactorings has when executed in a remote context. * </li> * <li> a timestamp, measured as the milliseconds since January 1, 1970, * 00:00:00 GMT, which denotes the original execution time of the refactoring. * </li> * <li> a unique ID, which denotes a certain kind of refactoring (e.g. Rename * File). This ID is usually composed of the plugin identifier of the * contributing plugin and a plugin-wide unique identifier (e.g. * <code>org.eclipse.ltk.core.refactoring.renameFile</code>). </li> * <li> the optional name of the project this refactoring is associated with. * Note that the project name is not available if the refactoring cannot be * associated with a single project, or the refactoring descriptor has been read * from a file which cannot be associated with a project. </li> * </ul> * <p> * Refactoring descriptors are identified by their refactoring id * {@link #getID()} and their time stamps {@link #getTimeStamp()} and are * potentially heavy weight objects which should not be held on to. Use * refactoring descriptor proxies {@link RefactoringDescriptorProxy} to present * refactoring descriptors in the user interface or otherwise manipulate * refactoring histories. * </p> * <p> * Clients which create specific refactoring descriptors during change * generation should choose a short, informative and human-readable description * of the particular refactoring instance and pass appropriate descriptor flags * to the constructor. More details about a particular refactoring can be * revealed in the comment, which contains more text with refactoring-specific * information. * </p> * <p> * Refactoring descriptors do not provide version information. It is the * responsibility of the client to enhance subclasses with refactoring version * information in order to provide a means of schema evolution. * </p> * <p> * All time stamps are measured as the milliseconds since January 1, 1970, * 00:00:00 GMT. * </p> * <p> * Note: this class is indented to be subclassed by clients to provide * specialized refactoring descriptors for particular refactorings. * </p> * * @see RefactoringDescriptorProxy * @see IRefactoringHistoryService * * @since 3.2 */
public abstract class RefactoringDescriptor implements Comparable<RefactoringDescriptor> {
Constant describing the API change flag (value: 1).

Clients should set this flag to indicate that the represented refactoring may cause breaking API changes. If clients set the BREAKING_CHANGE flag, they should set STRUCTURAL_CHANGE as well. Typically, refactorings which change elements that are marked as API according to the semantics of the associated programming language should set this flag. This flag is used by the refactoring framework to determine whether a refactoring may break existing API when replayed by clients.

/** * Constant describing the API change flag (value: <code>1</code>). * <p> * Clients should set this flag to indicate that the represented refactoring * may cause breaking API changes. If clients set the * {@link #BREAKING_CHANGE} flag, they should set {@link #STRUCTURAL_CHANGE} * as well. Typically, refactorings which change elements that are marked as * API according to the semantics of the associated programming language * should set this flag. This flag is used by the refactoring framework to * determine whether a refactoring may break existing API when replayed by * clients. * </p> */
public static final int BREAKING_CHANGE= 1 << 0;
The unknown refactoring id (value: org.eclipse.ltk.core.refactoring.unknown).

This id is reserved by the refactoring framework to signal that a refactoring has been performed which did not deliver a refactoring descriptor via its Change.getDescriptor() method. The refactoring history service never returns unknown refactorings. For consistency reasons, they are reported for IRefactoringExecutionListener or IRefactoringHistoryListener in order to keep clients of these listeners synchronized with the workbench's operation history.

/** * The unknown refactoring id (value: * <code>org.eclipse.ltk.core.refactoring.unknown</code>). * <p> * This id is reserved by the refactoring framework to signal that a * refactoring has been performed which did not deliver a refactoring * descriptor via its {@link Change#getDescriptor()} method. The refactoring * history service never returns unknown refactorings. For consistency * reasons, they are reported for {@link IRefactoringExecutionListener} or * {@link IRefactoringHistoryListener} in order to keep clients of these * listeners synchronized with the workbench's operation history. * </p> */
public static final String ID_UNKNOWN= "org.eclipse.ltk.core.refactoring.unknown"; //$NON-NLS-1$
Constant describing the multi change flag (value: 4).

Clients should set this flag to indicate that the change created by the represented refactoring might causes changes in other files than the files of the input elements according to the semantics of the associated programming language. Typically, refactorings which update references to the refactored element should set this flag. This flag is used during team synchronize operations to optimize the processing of refactorings.

/** * Constant describing the multi change flag (value: <code>4</code>). * <p> * Clients should set this flag to indicate that the change created by the * represented refactoring might causes changes in other files than the * files of the input elements according to the semantics of the associated * programming language. Typically, refactorings which update references to * the refactored element should set this flag. This flag is used during * team synchronize operations to optimize the processing of refactorings. * </p> */
public static final int MULTI_CHANGE= 1 << 2;
Constant describing the absence of any flags (value: 0).
/** Constant describing the absence of any flags (value: <code>0</code>). */
public static final int NONE= 0;
Constant describing the structural change flag (value: 2).

Clients should set this flag to indicate that the change created by the represented refactoring might be a structural change according to the semantics of the associated programming language. Typically, refactorings which cause changes in elements other than the element which declares the refactored element should set this flag. This flag is used by language-specific tools to determine whether the refactoring may impact client code.

/** * Constant describing the structural change flag (value: <code>2</code>). * <p> * Clients should set this flag to indicate that the change created by the * represented refactoring might be a structural change according to the * semantics of the associated programming language. Typically, refactorings * which cause changes in elements other than the element which declares the * refactored element should set this flag. This flag is used by * language-specific tools to determine whether the refactoring may impact * client code. * </p> */
public static final int STRUCTURAL_CHANGE= 1 << 1;
Constant describing the user flag (value: 256).

This constant is not intended to be used in refactoring descriptors. Clients should use the value of this constant to define user-defined flags with integer values greater than this constant. Clients must not use this constant directly.

/** * Constant describing the user flag (value: <code>256</code>). * <p> * This constant is not intended to be used in refactoring descriptors. * Clients should use the value of this constant to define user-defined * flags with integer values greater than this constant. Clients must not * use this constant directly. * </p> */
public static final int USER_CHANGE= 1 << 8;
The comment of the refactoring, or null for no comment
/** The comment of the refactoring, or <code>null</code> for no comment */
private String fComment;
The non-empty description of the refactoring
/** The non-empty description of the refactoring */
private String fDescription;
The flags of the refactoring, or NONE
/** The flags of the refactoring, or <code>NONE</code> */
private int fFlags;
The project name, or null for no project
/** The project name, or <code>null</code> for no project */
private String fProject;
The unique id of the refactoring
/** The unique id of the refactoring */
private final String fRefactoringId;
The time stamp, or -1 if no time information is associated with the refactoring
/** * The time stamp, or <code>-1</code> if no time information is associated * with the refactoring */
private long fTimeStamp= -1;
Creates a new refactoring descriptor.
Params:
  • id – the unique id of the refactoring
  • project – the non-empty name of the project associated with this refactoring, or null for a workspace refactoring
  • description – a non-empty human-readable description of the particular refactoring instance
  • comment – the human-readable comment of the particular refactoring instance, or null for no comment
  • flags – the flags of the refactoring descriptor
/** * Creates a new 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 flags * the flags of the refactoring descriptor */
protected RefactoringDescriptor(final String id, final String project, final String description, final String comment, final int flags) { Assert.isNotNull(id); Assert.isLegal(!"".equals(id), "Refactoring id must not be empty"); //$NON-NLS-1$ //$NON-NLS-2$ Assert.isLegal(project == null || !"".equals(project), "Project must either be null or non-empty"); //$NON-NLS-1$ //$NON-NLS-2$ Assert.isNotNull(description); Assert.isLegal(!"".equals(description), "Description must not be empty"); //$NON-NLS-1$//$NON-NLS-2$ Assert.isLegal(flags >= NONE, "Flags must be non-negative"); //$NON-NLS-1$ fRefactoringId= id; fDescription= description; fProject= project; fComment= comment; fFlags= flags; }
{@inheritDoc}
Since:3.7
/** * {@inheritDoc} * @since 3.7 */
@Override public final int compareTo(final RefactoringDescriptor descriptor) { long delta= fTimeStamp - descriptor.fTimeStamp; if (delta < 0) return -1; else if (delta > 0) return +1; return 0; }
Creates the a new refactoring instance for this refactoring descriptor.

The returned refactoring must be in an initialized state, i.e. ready to be executed via PerformRefactoringOperation.

This method is not intended to be called directly from code that does not belong to this class and its subclasses. External code should call createRefactoringContext(RefactoringStatus) and obtain the refactoring object from the refactoring context.

Params:
  • status – a refactoring status used to describe the outcome of the initialization
Throws:
  • CoreException – if an error occurs while creating the refactoring instance
Returns:the refactoring, or null if this refactoring descriptor represents the unknown refactoring, or if no refactoring contribution is available for this refactoring descriptor which is capable to create a refactoring
/** * Creates the a new refactoring instance for this refactoring descriptor. * <p> * The returned refactoring must be in an initialized state, i.e. ready to * be executed via {@link PerformRefactoringOperation}. * </p> * <p> * This method is not intended to be called directly from code that does not belong to this * class and its subclasses. External code should call * {@link #createRefactoringContext(RefactoringStatus)} and obtain the refactoring object from * the refactoring context. * </p> * * @param status * a refactoring status used to describe the outcome of the initialization * @return the refactoring, or <code>null</code> if this refactoring * descriptor represents the unknown refactoring, or if no * refactoring contribution is available for this refactoring * descriptor which is capable to create a refactoring * @throws CoreException * if an error occurs while creating the refactoring instance */
public abstract Refactoring createRefactoring(RefactoringStatus status) throws CoreException;
Creates the a new refactoring context and the associated refactoring instance for this refactoring descriptor.

This method is used by the refactoring framework to instantiate a refactoring from a refactoring descriptor, in order to apply it later on a local or remote workspace.

The default implementation of this method wraps the refactoring in a trivial refactoring context. Subclasses may override this method to create a custom refactoring context.

Params:
  • status – a refactoring status used to describe the outcome of the initialization
Throws:
  • CoreException – if an error occurs while creating the refactoring context
Returns:the refactoring context, or null if this refactoring descriptor represents the unknown refactoring, or if no refactoring contribution is available for this refactoring descriptor which is capable to create a refactoring.
Since:3.6
/** * Creates the a new refactoring context and the associated refactoring instance for this * refactoring descriptor. * <p> * This method is used by the refactoring framework to instantiate a refactoring * from a refactoring descriptor, in order to apply it later on a local or remote workspace. * </p> * <p> * The default implementation of this method wraps the refactoring in a trivial refactoring * context. Subclasses may override this method to create a custom refactoring context. * </p> * * @param status * a refactoring status used to describe the outcome of the initialization * @return the refactoring context, or <code>null</code> if this refactoring * descriptor represents the unknown refactoring, or if no * refactoring contribution is available for this refactoring * descriptor which is capable to create a refactoring. * @throws CoreException * if an error occurs while creating the refactoring context * @since 3.6 */
public RefactoringContext createRefactoringContext(RefactoringStatus status) throws CoreException { Refactoring refactoring= createRefactoring(status); if (refactoring == null) return null; return new RefactoringContext(refactoring); } @Override public final boolean equals(final Object object) { if (object instanceof RefactoringDescriptor) { final RefactoringDescriptor descriptor= (RefactoringDescriptor) object; return fTimeStamp == descriptor.fTimeStamp && getDescription().equals(descriptor.getDescription()); } return false; }
Returns the details comment.

This information is used in the user interface to show additional details about the performed refactoring.

Returns:the details comment, or the empty string
/** * Returns the details comment. * <p> * This information is used in the user interface to show additional details * about the performed refactoring. * </p> * * @return the details comment, or the empty string */
public final String getComment() { return (fComment != null) ? fComment : ""; //$NON-NLS-1$ }
Returns the description.

This information is used to label a refactoring in the user interface.

Returns:the description
/** * Returns the description. * <p> * This information is used to label a refactoring in the user interface. * </p> * * @return the description */
public final String getDescription() { return fDescription; }
Returns the flags.
Returns:the flags
/** * Returns the flags. * * @return the flags */
public final int getFlags() { return fFlags; }
Returns the refactoring id.
Returns:the refactoring id.
/** * Returns the refactoring id. * * @return the refactoring id. */
public final String getID() { return fRefactoringId; }
Returns the project name.
Returns:the non-empty name of the project, or null
/** * Returns the project name. * * @return the non-empty name of the project, or <code>null</code> */
public final String getProject() { return fProject; }
Returns the time stamp.
Returns:the time stamp, or -1 if no time information is available
/** * Returns the time stamp. * * @return the time stamp, or <code>-1</code> if no time information is * available */
public final long getTimeStamp() { return fTimeStamp; } @Override public final int hashCode() { int code= getDescription().hashCode(); if (fTimeStamp >= 0) code+= (17 * fTimeStamp); return code; }
Sets the details comment of this refactoring.

Note: This API must not be extended or reimplemented and should not be called from outside the refactoring framework.

Params:
  • comment – the comment to set, or null for no comment
/** * Sets the details comment of this refactoring. * <p> * Note: This API must not be extended or reimplemented and should not be * called from outside the refactoring framework. * </p> * * @param comment * the comment to set, or <code>null</code> for no comment */
public void setComment(final String comment) { fComment= comment; }
Sets the description of this refactoring.

Note: This API must not be extended or reimplemented and should not be called from outside the refactoring framework.

Params:
  • description – the non-empty description of the refactoring to set
Since:3.3
/** * Sets the description of this refactoring. * <p> * Note: This API must not be extended or reimplemented and should not be * called from outside the refactoring framework. * </p> * * @param description * the non-empty description of the refactoring to set * * @since 3.3 */
public void setDescription(final String description) { Assert.isNotNull(description); Assert.isLegal(!"".equals(description), "Description must not be empty"); //$NON-NLS-1$ //$NON-NLS-2$ fDescription= description; }
Sets the flags of this refactoring.

Note: This API must not be extended or reimplemented and should not be called from outside the refactoring framework.

Params:
  • flags – the flags to set, or NONE to clear the flags
Since:3.3
/** * Sets the flags of this refactoring. * <p> * Note: This API must not be extended or reimplemented and should not be * called from outside the refactoring framework. * </p> * * @param flags * the flags to set, or <code>NONE</code> to clear the flags * * @since 3.3 */
public void setFlags(final int flags) { Assert.isLegal(flags >= NONE, "Flags must be non-negative"); //$NON-NLS-1$ fFlags= flags; }
Sets the project name of this refactoring.

Note: This API must not be extended or reimplemented and should not be called from outside the refactoring framework.

Params:
  • project – the non-empty project name to set, or null for the workspace
/** * Sets the project name of this refactoring. * <p> * Note: This API must not be extended or reimplemented and should not be * called from outside the refactoring framework. * </p> * * @param project * the non-empty project name to set, or <code>null</code> for * the workspace */
public void setProject(final String project) { Assert.isLegal(project == null || !"".equals(project), "Project must either be null or non-empty"); //$NON-NLS-1$ //$NON-NLS-2$ fProject= project; }
Sets the time stamp of this refactoring. This method can be called only once.

Note: This API must not be extended or reimplemented and should not be called from outside the refactoring framework.

Params:
  • stamp – the time stamp to set
/** * Sets the time stamp of this refactoring. This method can be called only * once. * <p> * Note: This API must not be extended or reimplemented and should not be * called from outside the refactoring framework. * </p> * * @param stamp * the time stamp to set */
public void setTimeStamp(final long stamp) { Assert.isTrue(stamp >= 0); fTimeStamp= stamp; } @Override public String toString() { final StringBuilder buffer= new StringBuilder(128); buffer.append(getClass().getName()); if (fRefactoringId.equals(ID_UNKNOWN)) buffer.append("[unknown refactoring]"); //$NON-NLS-1$ else { buffer.append("[timeStamp="); //$NON-NLS-1$ buffer.append(fTimeStamp); buffer.append(",id="); //$NON-NLS-1$ buffer.append(fRefactoringId); buffer.append(",description="); //$NON-NLS-1$ buffer.append(fDescription); buffer.append(",project="); //$NON-NLS-1$ buffer.append(fProject); buffer.append(",comment="); //$NON-NLS-1$ buffer.append(fComment); buffer.append(",flags="); //$NON-NLS-1$ buffer.append(fFlags); buffer.append("]"); //$NON-NLS-1$ } return buffer.toString(); } }