/******************************************************************************* * Copyright (c) 2006, 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 * *******************************************************************************/ package org.eclipse.dltk.internal.corext.refactoring; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import java.util.Map.Entry; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; 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.dltk.core.DLTKCore; import org.eclipse.dltk.core.IModelElement; import org.eclipse.dltk.core.IScriptProject; import org.eclipse.dltk.core.WorkingCopyOwner; import org.eclipse.dltk.core.manipulation.ScriptManipulation; import org.eclipse.dltk.internal.core.manipulation.Messages; import org.eclipse.dltk.internal.core.refactoring.descriptors.DescriptorMessages; import org.eclipse.dltk.internal.corext.refactoring.tagging.IScriptableRefactoring; 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.ltk.core.refactoring.participants.RefactoringArguments; /** * Descriptor object of a script refactoring. * * */ public class ScriptRefactoringDescriptor 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 non * zero-based. * </p> */ 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> */ 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> */ 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> */ 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> */ public static final String ATTRIBUTE_SELECTION= "selection"; //$NON-NLS-1$ /** The version attribute */ private static final String ATTRIBUTE_VERSION= "version"; //$NON-NLS-1$ /** * Constant describing the deprecation resolving flag. * <p> * Clients should set this flag to indicate that the refactoring can used to * resolve deprecation problems of members. Refactorings which can run on * binary targets, but require a source attachment to work correctly, should * set the <code>ARCHIVE_SOURCE_ATTACHMENT</code> flag as well. * </p> */ public static final int DEPRECATION_RESOLVING= 1 << 17; /** * Constant describing the archive importable flag. * <p> * Clients should set this flag to indicate that the refactoring can be * imported from a archive file. If this flag is set, * <code>ARCHIVE_REFACTORABLE</code> should be set as well. * </p> */ public static final int ARCHIVE_IMPORTABLE= 1 << 16; /** * Constant describing the jar refactorable flag. * <p> * Clients should set this flag to indicate that the refactoring can be * performed on a JAR file. Refactorings which can run on binary targets, * but require a source attachment to work correctly, should set the * <code>JAR_SOURCE_ATTACHMENT</code> flag as well. * </p> */ public static final int ARCHIVE_REFACTORABLE= 1 << 19; /** The version value 1.0 */ private 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 */ public static String elementToHandle(final String project, final IModelElement element) { final String handle= element.getHandleIdentifier(); if (project != null && !(element instanceof IScriptProject)) { final String id= element.getScriptProject().getHandleIdentifier(); return handle.substring(id.length()); } return handle; } /** * Converts an input handle back to the corresponding script element. * * @param project * the project, or <code>null</code> for the workspace * @param handle * the input handle * @return the corresponding script element, or <code>null</code> if no such * element exists */ public static IModelElement handleToElement(final String project, final String handle) { return handleToElement(project, handle, true); } /** * Converts an input handle back to the corresponding script 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 script element, or <code>null</code> if no such * element exists */ public static IModelElement handleToElement(final String project, final String handle, final boolean check) { return handleToElement(null, project, handle, check); } /** * Converts an input handle back to the corresponding script 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 script element, or <code>null</code> if no such * element exists */ public static IModelElement handleToElement(final WorkingCopyOwner owner, final String project, final String handle, final boolean check) { IModelElement element= null; if (owner != null) element= DLTKCore.create(handle, owner); else element= DLTKCore.create(handle); if (element == null && project != null) { final IScriptProject scriptProject= DLTKCore.create(ResourcesPlugin.getWorkspace().getRoot()).getScriptProject(project); final String identifier= scriptProject.getHandleIdentifier(); if (owner != null) element= DLTKCore.create(identifier + handle, owner); else element= DLTKCore.create(identifier + handle); } if (DLTKCore.DEBUG) { System.err.println("TODo: ScriptRefactoringDescriptor add find Methods member in types..."); //$NON-NLS-1$ } // if (check && element instanceof IMethod) { // final IMethod method= (IMethod) element; // final IMethod[] methods= method.getDeclaringType().findMethods(method); // 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 */ public 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 */ public 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 map of arguments (element type: <String, String>) */ protected final Map fArguments; /** The refactoring contribution, or <code>null</code> */ private ScriptRefactoringContribution fContribution; /** * Creates a new script refactoring descriptor. * * @param contribution * the refactoring contribution, or <code>null</code> * @param id * the unique id of the refactoring * @param project * the project name, or <code>null</code> * @param description * the description * @param comment * the comment, or <code>null</code> * @param arguments * the argument map * @param flags * the flags */ public ScriptRefactoringDescriptor(final ScriptRefactoringContribution contribution, final String id, final String project, final String description, final String comment, final Map arguments, final int flags) { super(id, project, description, comment, flags); Assert.isNotNull(arguments); fContribution= contribution; fArguments= arguments; } /** * Creates a new java refactoring descriptor. * * @param id * the unique id of the refactoring */ protected ScriptRefactoringDescriptor(final String id) { this(id, null, DescriptorMessages.ScriptRefactoringDescriptor_not_available, null, new HashMap(), RefactoringDescriptor.STRUCTURAL_CHANGE | RefactoringDescriptor.MULTI_CHANGE); } /** * Creates a new script refactoring descriptor. * * @param id * the unique id of the refactoring * @param project * the project name, or <code>null</code> * @param description * the description * @param comment * the comment, or <code>null</code> * @param arguments * the argument map * @param flags * the flags */ public ScriptRefactoringDescriptor(final String id, final String project, final String description, final String comment, final Map arguments, final int flags) { this(null, id, project, description, comment, arguments, flags); } /** * Creates refactoring arguments for this refactoring descriptor. * * @return the refactoring arguments */ public RefactoringArguments createArguments() { final ScriptRefactoringArguments arguments= new ScriptRefactoringArguments(getProject()); for (final Iterator iterator= fArguments.entrySet().iterator(); iterator.hasNext();) { final Map.Entry entry= (Entry) iterator.next(); final String name= (String) entry.getKey(); final String value= (String) entry.getValue(); if (name != null && !"".equals(name) && value != null) //$NON-NLS-1$ arguments.setAttribute(name, value); } return arguments; } /** * {@inheritDoc} */ public Refactoring createRefactoring(final RefactoringStatus status) throws CoreException { Refactoring refactoring= null; if (fContribution != null) refactoring= fContribution.createRefactoring(this); else { final RefactoringContribution contribution= RefactoringCore.getRefactoringContribution(getID()); if (contribution instanceof ScriptRefactoringContribution) { fContribution= (ScriptRefactoringContribution) contribution; refactoring= fContribution.createRefactoring(this); } } if (refactoring != null) { if (refactoring instanceof IScriptableRefactoring) { final RefactoringStatus result= ((IScriptableRefactoring) refactoring).initialize(createArguments()); if (result.hasFatalError()) throw new CoreException(new Status(IStatus.ERROR, ScriptManipulation.ID_PLUGIN, 0, result.getMessageMatchingSeverity(RefactoringStatus.FATAL), null)); status.merge(result); } else throw new CoreException(new Status(IStatus.ERROR, ScriptManipulation.ID_PLUGIN, 0, Messages.format(DescriptorMessages.ScriptRefactoringDescriptor_no_resulting_descriptor, getDescription()), null)); } return refactoring; } /** * Converts the specified element to an input handle. * * @param element * the element * @return a corresponding input handle */ public String elementToHandle(final IModelElement element) { Assert.isNotNull(element); return elementToHandle(getProject(), element); } /** * Returns the argument map * * @return the argument map. */ 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() { fArguments.put(ATTRIBUTE_VERSION, VALUE_VERSION_1_0); } /** * Returns the refactoring contribution. * * @return the refactoring contribution, or <code>null</code> */ public ScriptRefactoringContribution getContribution() { return fContribution; } }