Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPascal Rapicault2010-12-06 22:10:52 +0000
committerPascal Rapicault2010-12-06 22:10:52 +0000
commitfbb4f5902cade92cc1689e73209c60a6413a5ef7 (patch)
treeace0fb107bafe980fc14fd7f3429e5c9aac2d795 /org.eclipse.m2e.refactoring/src
parenta9c878c2624b33d8c74062717bf75302f0ae1fa7 (diff)
downloadm2e-core-fbb4f5902cade92cc1689e73209c60a6413a5ef7.tar.gz
m2e-core-fbb4f5902cade92cc1689e73209c60a6413a5ef7.tar.xz
m2e-core-fbb4f5902cade92cc1689e73209c60a6413a5ef7.zip
Initial commit at Eclipse
Diffstat (limited to 'org.eclipse.m2e.refactoring/src')
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/AbstractPomRefactoring.java321
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/ChangeCreator.java187
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/Messages.java68
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/PomRefactoringException.java28
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/PomVisitor.java33
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/RefactoringModelResources.java194
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/exclude/DependencyExcludeAction.java112
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/exclude/ExcludeRefactoring.java195
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/exclude/MavenExcludeWizard.java32
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/Activator.java63
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/RefactoringImages.java62
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/RefactoringMavenMenuCreator.java36
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/SaveDirtyFilesDialog.java166
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/messages.properties20
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/MavenRenameWizard.java40
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/MavenRenameWizardPage.java159
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/RenameArtifactAction.java79
-rw-r--r--org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/RenameRefactoring.java332
18 files changed, 2127 insertions, 0 deletions
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/AbstractPomRefactoring.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/AbstractPomRefactoring.java
new file mode 100644
index 00000000..12882164
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/AbstractPomRefactoring.java
@@ -0,0 +1,321 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.maven.execution.MavenExecutionRequest;
+import org.apache.maven.project.MavenProject;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.command.BasicCommandStack;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.common.notify.impl.AdapterFactoryImpl;
+import org.eclipse.emf.common.util.EList;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
+import org.eclipse.emf.edit.provider.ComposedAdapterFactory;
+import org.eclipse.emf.edit.provider.ReflectiveItemProviderAdapterFactory;
+import org.eclipse.emf.edit.provider.resource.ResourceItemProviderAdapterFactory;
+import org.eclipse.jdt.core.JavaCore;
+import org.eclipse.jdt.internal.corext.refactoring.rename.RenameJavaProjectProcessor;
+import org.eclipse.ltk.core.refactoring.Change;
+import org.eclipse.ltk.core.refactoring.CompositeChange;
+import org.eclipse.ltk.core.refactoring.Refactoring;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.ltk.core.refactoring.TextFileChange;
+import org.eclipse.ltk.core.refactoring.participants.RenameRefactoring;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.embedder.IMaven;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.core.project.MavenProjectManager;
+import org.eclipse.m2e.model.edit.pom.Model;
+import org.eclipse.m2e.model.edit.pom.PropertyElement;
+import org.eclipse.m2e.refactoring.RefactoringModelResources.PropertyInfo;
+import org.eclipse.m2e.refactoring.internal.Activator;
+import org.eclipse.osgi.util.NLS;
+
+
+/**
+ * Base class for all pom.xml refactorings in workspace
+ *
+ * @author Anton Kraev
+ */
+@SuppressWarnings("restriction")
+public abstract class AbstractPomRefactoring extends Refactoring {
+
+ protected static final String PROBLEMS_DURING_REFACTORING = Messages.AbstractPomRefactoring_error;
+
+ // main file that is being refactored
+ protected IFile file;
+
+ // maven plugin
+ protected MavenPlugin mavenPlugin;
+
+ // editing domain
+ protected AdapterFactoryEditingDomain editingDomain;
+
+ private HashMap<String, RefactoringModelResources> models;
+
+ public AbstractPomRefactoring(IFile file) {
+ this.file = file;
+
+ this.mavenPlugin = MavenPlugin.getDefault();
+
+ List<AdapterFactoryImpl> factories = new ArrayList<AdapterFactoryImpl>();
+ factories.add(new ResourceItemProviderAdapterFactory());
+ factories.add(new ReflectiveItemProviderAdapterFactory());
+
+ ComposedAdapterFactory adapterFactory = new ComposedAdapterFactory(factories);
+ BasicCommandStack commandStack = new BasicCommandStack();
+ this.editingDomain = new AdapterFactoryEditingDomain(adapterFactory, //
+ commandStack, new HashMap<Resource, Boolean>());
+ }
+
+ // this gets actual refactoring visitor
+ public abstract PomVisitor getVisitor();
+
+ @Override
+ public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
+ return new RefactoringStatus();
+ }
+
+ @Override
+ public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException {
+ CompositeChange res = new CompositeChange(getTitle());
+ IMavenProjectFacade[] projects = mavenPlugin.getMavenProjectManager().getProjects();
+ pm.beginTask(Messages.AbstractPomRefactoring_task, projects.length);
+
+ models = new HashMap<String, RefactoringModelResources>();
+
+ try {
+ // load all models
+ // XXX: assumption: artifactId is unique within workspace
+ for(IMavenProjectFacade projectFacade : projects) {
+ // skip "other" projects if not requested
+ if(!scanAllArtifacts() && !projectFacade.getPom().equals(file)) {
+ continue;
+ }
+
+ // skip closed projects
+ if(!projectFacade.getProject().isAccessible() || !projectFacade.getPom().isAccessible()) {
+ continue;
+ }
+
+ loadModel(projectFacade, pm);
+ }
+
+ // construct properties for all models
+ for(IMavenProjectFacade projectFacade : projects) {
+ RefactoringModelResources model = models.get(projectFacade.getArtifactKey().getArtifactId());
+ if(model == null) {
+ continue;
+ }
+
+ Map<String, PropertyInfo> properties = new HashMap<String, PropertyInfo>();
+
+ // find all workspace parents
+ List<RefactoringModelResources> workspaceParents = new ArrayList<RefactoringModelResources>();
+ MavenProject current = model.getProject();
+ // add itself
+ workspaceParents.add(model);
+ for(MavenProject parentProject = getParentProject(projectFacade, current, pm); parentProject != null;) {
+ String id = parentProject.getArtifactId();
+ RefactoringModelResources parent = models.get(id);
+ if(parent != null) {
+ workspaceParents.add(parent);
+ } else {
+ break;
+ }
+ parentProject = getParentProject(projectFacade, parentProject, pm);
+ }
+
+ //fill properties (from the root)
+ for(int i = workspaceParents.size() - 1; i >= 0; i-- ) {
+ RefactoringModelResources resource = workspaceParents.get(i);
+ EList<PropertyElement> props = resource.getTmpModel().getProperties();
+ if(props == null)
+ continue;
+ Iterator<?> it = props.iterator();
+ while(it.hasNext()) {
+ PropertyElement pair = (PropertyElement) it.next();
+ String pName = pair.getName();
+ PropertyInfo info = properties.get(pName);
+ if(info == null) {
+ info = new PropertyInfo();
+ properties.put(pName, info);
+ }
+ info.setPair(pair);
+ info.setResource(resource);
+ }
+ }
+
+ model.setProperties(properties);
+ }
+
+ // calculate the list of affected models
+ for(String artifact : models.keySet()) {
+ RefactoringModelResources model = models.get(artifact);
+ model.setCommand(getVisitor().applyChanges(model, pm));
+ }
+
+ // process all refactored properties, creating more commands
+ for(String artifact : models.keySet()) {
+ RefactoringModelResources model = models.get(artifact);
+
+ if(model.getProperties() == null) {
+ continue;
+ }
+
+ for(String pName : model.getProperties().keySet()) {
+ PropertyInfo info = model.getProperties().get(pName);
+ if(info.getNewValue() != null) {
+ CompoundCommand command = info.getResource().getCommand();
+ if(command == null) {
+ command = new CompoundCommand();
+ info.getResource().setCommand(command);
+ }
+ command.append(info.getNewValue());
+ }
+ }
+ }
+
+ // process the file itself first
+ for(String artifact : models.keySet()) {
+ RefactoringModelResources model = models.get(artifact);
+ if(model.getPomFile().equals(file)) {
+ processCommand(model, res);
+ model.releaseAllResources();
+ models.remove(artifact);
+ break;
+ }
+ }
+
+ // process others
+ for(String artifact : models.keySet()) {
+ processCommand(models.get(artifact), res);
+ }
+
+ // rename project if required
+ // TODO probably should copy relevant classes from internal packages
+ String newName = getNewProjectName();
+ if(newName != null) {
+ RenameJavaProjectProcessor processor = new RenameJavaProjectProcessor(JavaCore.create(file.getProject()));
+ RenameRefactoring refactoring = new RenameRefactoring(processor);
+ processor.setNewElementName(newName);
+ RefactoringStatus tmp = new RefactoringStatus();
+ tmp.merge(refactoring.checkInitialConditions(pm));
+ if(!tmp.hasFatalError()) {
+ tmp.merge(refactoring.checkFinalConditions(pm));
+ if(!tmp.hasFatalError()) {
+ res.add(refactoring.createChange(pm));
+ }
+ }
+ }
+ } catch(final PomRefactoringException ex) {
+ return new Change() {
+ public RefactoringStatus isValid(IProgressMonitor pm) throws CoreException, OperationCanceledException {
+ return RefactoringStatus.createFatalErrorStatus(ex.getStatus().getMessage());
+ }
+ public Object getModifiedElement() {
+ return null;
+ }
+ public String getName() {
+ return ex.getStatus().getMessage();
+ }
+ public void initializeValidationData(IProgressMonitor pm) {
+ }
+ public Change perform(IProgressMonitor pm) throws CoreException {
+ return null;
+ }
+ public boolean isEnabled() {
+ return false;
+ }
+ };
+ } catch(Exception ex) {
+ throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, PROBLEMS_DURING_REFACTORING, ex));
+ } finally {
+ for(String artifact : models.keySet()) {
+ models.get(artifact).releaseAllResources();
+ }
+ RefactoringModelResources.cleanupTmpProject();
+ }
+
+ return res;
+ }
+
+ protected MavenProject getParentProject(IMavenProjectFacade project, MavenProject current, IProgressMonitor monitor)
+ throws CoreException {
+ IMaven maven = mavenPlugin.getMaven();
+ MavenProjectManager projectManager = mavenPlugin.getMavenProjectManager();
+
+ MavenExecutionRequest request = projectManager.createExecutionRequest(project.getPom(),
+ project.getResolverConfiguration(), monitor);
+
+ return maven.resolveParentProject(request, current, monitor);
+ }
+
+ // title for a composite change
+ public abstract String getTitle();
+
+ protected RefactoringModelResources loadModel(IMavenProjectFacade projectFacade, IProgressMonitor pm)
+ throws CoreException, IOException {
+ pm.setTaskName(NLS.bind(Messages.AbstractPomRefactoring_loading, projectFacade.getProject().getName()));
+ RefactoringModelResources current = new RefactoringModelResources(projectFacade);
+ models.put(current.effective.getArtifactId(), current);
+ pm.worked(1);
+ return current;
+ }
+
+ // this method determines whether all artifacts will be sent to visitor or only main one
+ public abstract boolean scanAllArtifacts();
+
+ protected void processCommand(RefactoringModelResources model, CompositeChange res) throws Exception {
+ CompoundCommand command = model.getCommand();
+ if(command == null) {
+ return;
+ }
+ if(command.canExecute()) {
+ // apply changes to temp file
+ editingDomain.getCommandStack().execute(command);
+ // create text change comparing temp file and real file
+ TextFileChange change = new ChangeCreator(model.getPomFile(), model.getPomBuffer().getDocument(), model
+ .getTmpBuffer().getDocument(), file.getParent().getName()).createChange();
+ res.add(change);
+ }
+ }
+
+ // returns new eclipse project name or null if no change
+ public String getNewProjectName() {
+ return null;
+ }
+
+ public Model createModel() {
+ try {
+ Resource resource = MavenPlugin.getDefault().getMavenModelManager().loadResource(file);
+ return (Model) resource.getContents().get(0);
+ } catch(CoreException ex) {
+ MavenLogger.log(PROBLEMS_DURING_REFACTORING, ex);
+ return null;
+ }
+ }
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/ChangeCreator.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/ChangeCreator.java
new file mode 100644
index 00000000..5a49dc99
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/ChangeCreator.java
@@ -0,0 +1,187 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.eclipse.compare.rangedifferencer.IRangeComparator;
+import org.eclipse.compare.rangedifferencer.RangeDifference;
+import org.eclipse.compare.rangedifferencer.RangeDifferencer;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jface.text.BadLocationException;
+import org.eclipse.jface.text.IDocument;
+import org.eclipse.jface.text.IRegion;
+import org.eclipse.ltk.core.refactoring.TextFileChange;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.text.edits.DeleteEdit;
+import org.eclipse.text.edits.InsertEdit;
+import org.eclipse.text.edits.MultiTextEdit;
+import org.eclipse.text.edits.ReplaceEdit;
+import org.eclipse.text.edits.TextEdit;
+import org.eclipse.text.edits.TextEditGroup;
+
+
+/**
+ * This class creates an org.eclipse.ltk.core.refactoring.DocumentChange instance based on old and new text values
+ *
+ * @author Anton Kraev
+ */
+public class ChangeCreator {
+ private String label;
+
+ private IDocument oldDocument;
+
+ private IDocument newDocument;
+
+ private IFile oldFile;
+
+ public ChangeCreator(IFile oldFile, IDocument oldDocument, IDocument newDocument, String label) {
+ this.newDocument = newDocument;
+ this.oldDocument = oldDocument;
+ this.oldFile = oldFile;
+ this.label = label;
+ }
+
+ public TextFileChange createChange() throws Exception {
+ TextFileChange change = new TextFileChange(label, oldFile);
+ // change.setSaveMode(TextFileChange.FORCE_SAVE);
+ change.setEdit(new MultiTextEdit());
+ Object leftSide = new LineComparator(oldDocument);
+ Object rightSide = new LineComparator(newDocument);
+
+ RangeDifference[] differences = RangeDifferencer.findDifferences((IRangeComparator) leftSide, (IRangeComparator) rightSide);
+ int insertOffset = 0;
+ for(int i = 0; i < differences.length; i++ ) {
+ RangeDifference curr = differences[i];
+ int startLine = 0;
+ // when comparing 2 files, only RangeDifference.CHANGE is possible, no need to test
+ if (curr.rightLength() == curr.leftLength()) {
+ // replace
+ startLine = curr.rightStart();
+ int endLine = curr.rightEnd() - 1;
+ for(int j = startLine; j <= endLine; j++ ) {
+ int newPos = curr.leftStart() - startLine + j;
+ String newText = newDocument.get(newDocument.getLineOffset(newPos), newDocument.getLineLength(newPos));
+ addEdit(change, startLine, new ReplaceEdit(oldDocument.getLineOffset(j), oldDocument.getLineLength(j), newText));
+ }
+ } else if (curr.rightLength() > 0 && curr.leftLength() == 0) {
+ // insert
+ startLine = curr.rightStart();
+ int endLine = curr.rightEnd() - 1;
+ int posInsert = oldDocument.getLineOffset(curr.leftStart());
+ String newText = ""; //$NON-NLS-1$
+ for(int j = startLine; j <= endLine; j++ ) {
+ int newPos = curr.leftStart() - startLine + j + insertOffset;
+ newText += newDocument.get(newDocument.getLineOffset(newPos), newDocument.getLineLength(newPos));
+ }
+ if(newText.length() > 0){
+ addEdit(change, startLine, new InsertEdit(posInsert, newText));
+ }
+ insertOffset += curr.rightEnd() - curr.rightStart();
+ } else if (curr.leftLength() > 0 && curr.rightLength() == 0) {
+ // delete
+ startLine = curr.leftStart();
+ int endLine = curr.leftEnd() - 1;
+ int startOffset = oldDocument.getLineOffset(startLine);
+ int endOffset = 0;
+ for(int j = startLine; j <= endLine; j++ ) {
+ endOffset += oldDocument.getLineLength(j);
+ }
+ addEdit(change, startLine, new DeleteEdit(startOffset, endOffset));
+ insertOffset -= (curr.leftEnd() - curr.leftStart());
+ } else {
+ // unhandled
+ }
+ }
+ return change;
+ }
+
+ private void addEdit(TextFileChange change, int startLine, TextEdit edit) {
+ change.addTextEditGroup(new TextEditGroup("Line " + (startLine + 1), edit));
+ change.addEdit(edit);
+ }
+
+ public static class LineComparator implements IRangeComparator {
+ private final IDocument document;
+ private final ArrayList<Integer> hashes;
+
+ /**
+ * Create a line comparator for the given document.
+ *
+ * @param document
+ */
+ public LineComparator(IDocument document) {
+ this.document = document;
+ this.hashes = new ArrayList<Integer>(Arrays.asList(new Integer[document.getNumberOfLines()]));
+ }
+
+ /*
+ * @see org.eclipse.compare.rangedifferencer.IRangeComparator#getRangeCount()
+ */
+ public int getRangeCount() {
+ return document.getNumberOfLines();
+ }
+
+ /*
+ * @see org.eclipse.compare.rangedifferencer.IRangeComparator#rangesEqual(int, org.eclipse.compare.rangedifferencer.IRangeComparator, int)
+ */
+ public boolean rangesEqual(int thisIndex, IRangeComparator other, int otherIndex) {
+ try {
+ return getHash(thisIndex).equals(((LineComparator) other).getHash(otherIndex));
+ } catch (BadLocationException e) {
+ MavenLogger.log("Problem comparing", e);
+ return false;
+ }
+ }
+
+ /*
+ * @see org.eclipse.compare.rangedifferencer.IRangeComparator#skipRangeComparison(int, int, org.eclipse.compare.rangedifferencer.IRangeComparator)
+ */
+ public boolean skipRangeComparison(int length, int maxLength, IRangeComparator other) {
+ return false;
+ }
+
+ /**
+ * @param line the number of the line in the document to get the hash for
+ * @return the hash of the line
+ * @throws BadLocationException if the line number is invalid
+ */
+ private Integer getHash(int line) throws BadLocationException {
+ Integer hash = hashes.get(line);
+ if (hash == null) {
+ IRegion lineRegion;
+ lineRegion = document.getLineInformation(line);
+ String lineContents= document.get(lineRegion.getOffset(), lineRegion.getLength());
+ hash = new Integer(computeDJBHash(lineContents));
+ hashes.set(line, hash);
+ }
+ return hash;
+ }
+
+ /**
+ * Compute a hash using the DJB hash algorithm
+ *
+ * @param string the string for which to compute a hash
+ * @return the DJB hash value of the string
+ */
+ private int computeDJBHash(String string) {
+ int hash = 5381;
+ int len = string.length();
+ for (int i = 0; i < len; i++) {
+ hash = (hash << 5) + hash + string.charAt(i);
+ }
+ return hash;
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/Messages.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/Messages.java
new file mode 100644
index 00000000..6dfe7d59
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/Messages.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring;
+
+import org.eclipse.osgi.util.NLS;
+
+
+/**
+ * @author mkleint
+ *
+ */
+public class Messages extends NLS {
+ private static final String BUNDLE_NAME = "org.eclipse.m2e.refactoring.messages"; //$NON-NLS-1$
+
+ public static String AbstractPomRefactoring_error;
+
+ public static String AbstractPomRefactoring_loading;
+
+ public static String AbstractPomRefactoring_task;
+ public static String ExcludeRefactoring_error_parent;
+
+ public static String ExcludeRefactoring_name;
+
+ public static String ExcludeRefactoring_task_loading;
+
+ public static String ExcludeRefactoring_title;
+
+ public static String MavenRenameWizardPage_cbRenameWorkspace;
+
+ public static String MavenRenameWizardPage_desc;
+
+ public static String MavenRenameWizardPage_lblArtifactId;
+
+ public static String MavenRenameWizardPage_lblGroupId;
+
+ public static String MavenRenameWizardPage_lblVersion;
+
+ public static String MavenRenameWizardPage_title;
+
+ public static String RefactoringMavenMenuCreator_action_exclude;
+
+ public static String RenameRefactoring_1;
+
+ public static String RenameRefactoring_name;
+
+ public static String RenameRefactoring_title;
+
+ public static String SaveDirtyFilesDialog_message_not_saved;
+ public static String SaveDirtyFilesDialog_title;
+
+ public static String SaveDirtyFilesDialog_title_error;
+ static {
+ // initialize resource bundle
+ NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+ }
+
+ private Messages() {
+ }
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/PomRefactoringException.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/PomRefactoringException.java
new file mode 100644
index 00000000..75385c31
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/PomRefactoringException.java
@@ -0,0 +1,28 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring;
+
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IStatus;
+
+
+/**
+ * A POM refactoring exception, to pass error from refactoring implementations into the wizard.
+ */
+public class PomRefactoringException extends CoreException {
+ private static final long serialVersionUID = 994564746763321105L;
+
+ public PomRefactoringException(IStatus status) {
+ super(status);
+ }
+
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/PomVisitor.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/PomVisitor.java
new file mode 100644
index 00000000..7d01169e
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/PomVisitor.java
@@ -0,0 +1,33 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.emf.common.command.CompoundCommand;
+
+
+/**
+ * This interface defines refactoring visitor
+ *
+ * @author Anton Kraev
+ */
+public interface PomVisitor {
+ /**
+ * Applies refactoring changes through undoable command
+ *
+ * @param model - current model being visited
+ * @param pm - progress monitor
+ * @return command that executes changes (if any)
+ * @throws Exception
+ */
+ public CompoundCommand applyChanges(RefactoringModelResources model, IProgressMonitor pm) throws Exception;
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/RefactoringModelResources.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/RefactoringModelResources.java
new file mode 100644
index 00000000..c47bd0d8
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/RefactoringModelResources.java
@@ -0,0 +1,194 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Map;
+
+import org.apache.maven.project.MavenProject;
+import org.eclipse.core.filebuffers.FileBuffers;
+import org.eclipse.core.filebuffers.ITextFileBuffer;
+import org.eclipse.core.filebuffers.ITextFileBufferManager;
+import org.eclipse.core.filebuffers.LocationKind;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.emf.common.command.Command;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.ecore.resource.Resource;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.core.project.IMavenProjectFacade;
+import org.eclipse.m2e.model.edit.pom.Model;
+import org.eclipse.m2e.model.edit.pom.PropertyElement;
+
+/**
+ * This class manages all refactoring-related resources for a particular maven project
+ *
+ * @author Anton Kraev
+ */
+public class RefactoringModelResources {
+ private static final String TMP_PROJECT_NAME = ".m2eclipse_refactoring"; //$NON-NLS-1$
+ protected IFile pomFile;
+ protected IFile tmpFile;
+ protected ITextFileBuffer pomBuffer;
+ protected ITextFileBuffer tmpBuffer;
+ protected Model tmpModel;
+ protected org.apache.maven.model.Model effective;
+ protected ITextFileBufferManager textFileBufferManager;
+ protected Map<String, PropertyInfo> properties;
+ protected MavenProject project;
+ protected CompoundCommand command;
+ protected static IProject tmpProject;
+
+ protected IProject getTmpProject() {
+ if (tmpProject == null) {
+ tmpProject = ResourcesPlugin.getWorkspace().getRoot().getProject(TMP_PROJECT_NAME);
+ }
+ if (!tmpProject.exists()) {
+ try {
+ tmpProject.create(null);
+ tmpProject.open(null);
+ } catch(CoreException ex) {
+ MavenLogger.log(ex);
+ }
+ }
+ return tmpProject;
+ }
+
+ public RefactoringModelResources(IMavenProjectFacade projectFacade) throws CoreException, IOException {
+ textFileBufferManager = FileBuffers.getTextFileBufferManager();
+ project = projectFacade.getMavenProject(null);
+ effective = project.getModel();
+ pomFile = projectFacade.getPom();
+ pomBuffer = getBuffer(pomFile);
+
+ //create temp file
+ IProject project = getTmpProject();
+ File f = File.createTempFile("pom", ".xml", project.getLocation().toFile()); //$NON-NLS-1$ //$NON-NLS-2$
+ f.delete();
+ tmpFile = project.getFile(f.getName());
+ pomFile.copy(tmpFile.getFullPath(), true, null);
+
+ Resource resource = MavenPlugin.getDefault().getMavenModelManager().loadResource(tmpFile);
+ tmpModel = (Model)resource.getContents().get(0);
+ tmpBuffer = getBuffer(tmpFile);
+ }
+
+ public CompoundCommand getCommand() {
+ return command;
+ }
+
+ public void setCommand(CompoundCommand command) {
+ this.command = command;
+ }
+
+ public IFile getPomFile() {
+ return pomFile;
+ }
+
+ public IFile getTmpFile() {
+ return tmpFile;
+ }
+
+ public ITextFileBuffer getPomBuffer() {
+ return pomBuffer;
+ }
+
+ public ITextFileBuffer getTmpBuffer() {
+ return tmpBuffer;
+ }
+
+ public Model getTmpModel() {
+ return tmpModel;
+ }
+
+ public org.apache.maven.model.Model getEffective() {
+ return effective;
+ }
+
+ public MavenProject getProject() {
+ return project;
+ }
+
+ public Map<String, PropertyInfo> getProperties() {
+ return properties;
+ }
+
+ public void setProperties(Map<String, PropertyInfo> properties) {
+ this.properties = properties;
+ }
+
+ public void releaseAllResources() throws CoreException {
+ releaseBuffer(pomBuffer, pomFile);
+ if (tmpFile != null && tmpFile.exists()) {
+ releaseBuffer(tmpBuffer, tmpFile);
+ }
+ if (tmpModel != null) {
+ tmpModel.eResource().unload();
+ }
+ }
+
+ public static void cleanupTmpProject() throws CoreException {
+ if (tmpProject.exists()) {
+ tmpProject.delete(true, true, null);
+ }
+ }
+
+
+ protected ITextFileBuffer getBuffer(IFile file) throws CoreException {
+ textFileBufferManager.connect(file.getLocation(), LocationKind.NORMALIZE, null);
+ return textFileBufferManager.getTextFileBuffer(file.getLocation(), LocationKind.NORMALIZE);
+ }
+
+ protected void releaseBuffer(ITextFileBuffer buffer, IFile file) throws CoreException {
+ buffer.revert(null);
+ textFileBufferManager.disconnect(file.getLocation(), LocationKind.NORMALIZE, null);
+ }
+
+ public String getName() {
+ return pomFile.getProject().getName();
+ }
+
+ public static class PropertyInfo {
+ protected PropertyElement pair;
+ protected RefactoringModelResources resource;
+ protected Command newValue;
+
+ public Command getNewValue() {
+ return newValue;
+ }
+
+ public void setNewValue(Command newValue) {
+ this.newValue = newValue;
+ }
+
+ public PropertyElement getPair() {
+ return pair;
+ }
+
+ public void setPair(PropertyElement pair) {
+ this.pair = pair;
+ }
+
+ public RefactoringModelResources getResource() {
+ return resource;
+ }
+
+ public void setResource(RefactoringModelResources resource) {
+ this.resource = resource;
+ }
+ }
+
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/exclude/DependencyExcludeAction.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/exclude/DependencyExcludeAction.java
new file mode 100644
index 00000000..54eaf0e9
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/exclude/DependencyExcludeAction.java
@@ -0,0 +1,112 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring.exclude;
+
+import org.apache.maven.artifact.Artifact;
+import org.eclipse.core.resources.IFile;
+import org.eclipse.jdt.core.IJavaElement;
+import org.eclipse.jdt.core.IJavaProject;
+import org.eclipse.jdt.internal.ui.packageview.ClassPathContainer.RequiredProjectWrapper;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
+import org.eclipse.m2e.core.actions.SelectionUtil;
+import org.eclipse.m2e.core.embedder.ArtifactKey;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IActionDelegate;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IFileEditorInput;
+import org.eclipse.ui.PlatformUI;
+
+/**
+ * This action is intended to be used in popup menus
+ *
+ * @author Anton Kraev
+ */
+@SuppressWarnings("restriction")
+public class DependencyExcludeAction implements IActionDelegate {
+
+ public static final String ID = "org.eclipse.m2e.refactoring.DependencyExclude"; //$NON-NLS-1$
+
+ private IFile file;
+ private ArtifactKey artifactKey;
+
+ public void run(IAction action) {
+ if (artifactKey != null && file != null) {
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ MavenExcludeWizard wizard = new MavenExcludeWizard(file, //
+ artifactKey.getGroupId(), artifactKey.getArtifactId());
+ try {
+ String titleForFailedChecks = ""; //$NON-NLS-1$
+ RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
+ op.run(shell, titleForFailedChecks);
+ } catch(InterruptedException e) {
+ // XXX
+ }
+ }
+ }
+
+ public void selectionChanged(IAction action, ISelection selection) {
+ file = null;
+ artifactKey = null;
+
+ // TODO move logic into adapters
+ if (selection instanceof IStructuredSelection) {
+ IStructuredSelection structuredSelection = (IStructuredSelection) selection;
+ if(structuredSelection.size()==1) {
+ Object selected = structuredSelection.getFirstElement();
+ if (selected instanceof Artifact) {
+ file = getFileFromEditor();
+ artifactKey = new ArtifactKey((Artifact) selected);
+
+ } else if (selected instanceof org.sonatype.aether.graph.DependencyNode) {
+ file = getFileFromEditor();
+ artifactKey = new ArtifactKey(((org.sonatype.aether.graph.DependencyNode) selected).getDependency().getArtifact());
+
+ } else if (selected instanceof RequiredProjectWrapper) {
+ RequiredProjectWrapper w = (RequiredProjectWrapper) selected;
+ file = getFileFromProject(w.getParentClassPathContainer().getJavaProject());
+ artifactKey = SelectionUtil.getType(selected, ArtifactKey.class);
+
+ } else {
+ artifactKey = SelectionUtil.getType(selected, ArtifactKey.class);
+ if (selected instanceof IJavaElement) {
+ IJavaElement el = (IJavaElement) selected;
+ file = getFileFromProject(el.getParent().getJavaProject());
+ }
+
+ }
+ }
+ }
+
+ if (artifactKey != null && file != null) {
+ action.setEnabled(true);
+ } else {
+ action.setEnabled(false);
+ }
+ }
+
+ private IFile getFileFromProject(IJavaProject javaProject) {
+ return javaProject.getProject().getFile("pom.xml"); //$NON-NLS-1$
+ }
+
+ private IFile getFileFromEditor() {
+ IEditorPart part = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage().getActiveEditor();
+ if (part != null && part.getEditorInput() instanceof IFileEditorInput) {
+ IFileEditorInput input = (IFileEditorInput) part.getEditorInput();
+ return input.getFile();
+ }
+ return null;
+ }
+
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/exclude/ExcludeRefactoring.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/exclude/ExcludeRefactoring.java
new file mode 100644
index 00000000..a0524178
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/exclude/ExcludeRefactoring.java
@@ -0,0 +1,195 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring.exclude;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.edit.command.AddCommand;
+import org.eclipse.emf.edit.command.RemoveCommand;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.core.core.IMavenConstants;
+import org.eclipse.m2e.core.embedder.MavenModelManager;
+import org.eclipse.m2e.model.edit.pom.Dependency;
+import org.eclipse.m2e.model.edit.pom.Exclusion;
+import org.eclipse.m2e.model.edit.pom.Model;
+import org.eclipse.m2e.model.edit.pom.impl.PomFactoryImpl;
+import org.eclipse.m2e.refactoring.AbstractPomRefactoring;
+import org.eclipse.m2e.refactoring.Messages;
+import org.eclipse.m2e.refactoring.PomRefactoringException;
+import org.eclipse.m2e.refactoring.PomVisitor;
+import org.eclipse.m2e.refactoring.RefactoringModelResources;
+import org.eclipse.osgi.util.NLS;
+import org.sonatype.aether.artifact.Artifact;
+import org.sonatype.aether.graph.DependencyNode;
+import org.sonatype.aether.graph.DependencyVisitor;
+import org.sonatype.aether.util.artifact.JavaScopes;
+
+
+/**
+ * Exclude artifact refactoring implementation
+ *
+ * @author Anton Kraev
+ */
+public class ExcludeRefactoring extends AbstractPomRefactoring {
+
+ private String excludedArtifactId;
+
+ private String excludedGroupId;
+
+ /**
+ * @param file
+ */
+ public ExcludeRefactoring(IFile file, String excludedGroupId, String excludedArtifactId) {
+ super(file);
+ this.excludedGroupId = excludedGroupId;
+ this.excludedArtifactId = excludedArtifactId;
+ }
+
+ public PomVisitor getVisitor() {
+ return new PomVisitor() {
+
+ public CompoundCommand applyChanges(RefactoringModelResources resources, IProgressMonitor pm)
+ throws CoreException, IOException {
+ final CompoundCommand command = new CompoundCommand();
+
+ final List<Dependency> toRemove = new ArrayList<Dependency>();
+
+ Model model = resources.getTmpModel();
+
+ final List<Dependency> deps = model.getDependencies();
+
+ final IStatus[] status = new IStatus[] {null};
+
+ pm.beginTask(Messages.ExcludeRefactoring_task_loading, 1);
+ MavenModelManager modelManager = MavenPlugin.getDefault().getMavenModelManager();
+ DependencyNode root = modelManager.readDependencyTree(resources.getPomFile(), JavaScopes.TEST, pm);
+ pm.worked(1);
+ root.accept(new DependencyVisitor() {
+
+ private Dependency findDependency(String groupId, String artifactId) {
+ for(Dependency d : deps) {
+ if(d.getGroupId().equals(groupId) && d.getArtifactId().equals(artifactId)) {
+ return d;
+ }
+ }
+ return null;
+ }
+
+ private Dependency findDependency(DependencyNode node) {
+ Artifact artifact;
+ if(node.getRelocations().isEmpty()) {
+ artifact = node.getDependency().getArtifact();
+ } else {
+ artifact = node.getRelocations().get(0);
+ }
+ return findDependency(artifact.getGroupId(), artifact.getArtifactId());
+ }
+
+ private int depth;
+
+ private DependencyNode topLevel;
+
+ private Set<Dependency> excluded = new HashSet<Dependency>();
+
+ public boolean visitLeave(DependencyNode node) {
+ depth-- ;
+ return status[0] == null;
+ }
+
+ public boolean visitEnter(DependencyNode node) {
+ if(depth == 1) {
+ topLevel = node;
+ }
+ depth++ ;
+
+ if(node.getDependency() != null) {
+ Artifact a = node.getDependency().getArtifact();
+ if(a.getGroupId().equals(excludedGroupId) && a.getArtifactId().equals(excludedArtifactId)) {
+ if(topLevel == null) {
+ // do not touch itself
+ } else if(node == topLevel) {
+ // need to remove top-level dependency
+ toRemove.add(findDependency(topLevel));
+ } else {
+ // need to add exclusion to top-level dependency
+ Dependency dependency = findDependency(topLevel);
+ if(dependency == null) {
+ status[0] = new Status(IStatus.ERROR, IMavenConstants.PLUGIN_ID, NLS.bind(Messages.ExcludeRefactoring_error_parent,
+ topLevel.getDependency().getArtifact().getGroupId(),
+ topLevel.getDependency().getArtifact().getArtifactId()));
+ }
+ if(excluded.add(dependency)) {
+ addExclusion(command, dependency);
+ }
+ }
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ });
+
+ if(status[0] != null) {
+ throw new PomRefactoringException(status[0]);
+ }
+
+ for(Iterator<Dependency> rem = toRemove.iterator(); rem.hasNext();) {
+ command.append(new RemoveCommand(editingDomain, model.getDependencies(), rem.next()));
+ }
+
+ // XXX scan management as well
+
+ return command;
+ }
+
+ private void addExclusion(CompoundCommand command, Dependency dep) {
+ Exclusion exclusion = PomFactoryImpl.eINSTANCE.createExclusion();
+ exclusion.setArtifactId(excludedArtifactId);
+ exclusion.setGroupId(excludedGroupId);
+ command.append(new AddCommand(editingDomain, dep.getExclusions(), exclusion));
+ }
+ };
+ }
+
+ public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
+ return new RefactoringStatus();
+ }
+
+ public String getName() {
+ return Messages.ExcludeRefactoring_name;
+ }
+
+ public String getTitle() {
+ return NLS.bind(Messages.ExcludeRefactoring_title, new Object[] {excludedGroupId, excludedArtifactId, file.getParent().getName()});
+ }
+
+ public boolean scanAllArtifacts() {
+ //do not scan other artifacts
+ return false;
+ }
+
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/exclude/MavenExcludeWizard.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/exclude/MavenExcludeWizard.java
new file mode 100644
index 00000000..8bfd857a
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/exclude/MavenExcludeWizard.java
@@ -0,0 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring.exclude;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
+
+
+/**
+ * @author Anton Kraev
+ */
+public class MavenExcludeWizard extends RefactoringWizard {
+
+ public MavenExcludeWizard(IFile file, String excludedGroupId, String excludedArtifactId) {
+ super(new ExcludeRefactoring(file, excludedGroupId, excludedArtifactId), DIALOG_BASED_USER_INTERFACE);
+ }
+
+ @Override
+ protected void addUserInputPages() {
+ setDefaultPageTitle(getRefactoring().getName());
+ }
+
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/Activator.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/Activator.java
new file mode 100644
index 00000000..060a6f99
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/Activator.java
@@ -0,0 +1,63 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring.internal;
+
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+import org.osgi.framework.BundleContext;
+
+/**
+ * The activator class controls the plug-in life cycle
+ *
+ * @author Anton Kraev
+ */
+public class Activator extends AbstractUIPlugin {
+
+ // The plug-in ID
+ public static final String PLUGIN_ID = "org.eclipse.m2e.refactoring"; //$NON-NLS-1$
+
+ // The shared instance
+ private static Activator plugin;
+
+ /**
+ * The constructor
+ */
+ public Activator() {
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#start(org.osgi.framework.BundleContext)
+ */
+ public void start(BundleContext context) throws Exception {
+ super.start(context);
+ plugin = this;
+ }
+
+ /*
+ * (non-Javadoc)
+ * @see org.eclipse.ui.plugin.AbstractUIPlugin#stop(org.osgi.framework.BundleContext)
+ */
+ public void stop(BundleContext context) throws Exception {
+ plugin = null;
+ super.stop(context);
+ }
+
+ /**
+ * Returns the shared instance
+ *
+ * @return the shared instance
+ */
+ public static Activator getDefault() {
+ return plugin;
+ }
+
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/RefactoringImages.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/RefactoringImages.java
new file mode 100644
index 00000000..949c5ef8
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/RefactoringImages.java
@@ -0,0 +1,62 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring.internal;
+
+import org.eclipse.jface.resource.ImageDescriptor;
+import org.eclipse.jface.resource.ImageRegistry;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.ui.plugin.AbstractUIPlugin;
+
+/**
+ * @author Eugene Kuleshov
+ */
+public class RefactoringImages {
+
+ // images
+
+ // public static final Image IMG_CLEAR = createImage("clear.gif");
+
+ // image descriptors
+
+ public static final ImageDescriptor EXCLUDE = create("exclude.gif"); //$NON-NLS-1$
+
+
+ private static ImageDescriptor create(String key) {
+ try {
+ ImageDescriptor imageDescriptor = createDescriptor(key);
+ ImageRegistry imageRegistry = getImageRegistry();
+ if(imageRegistry!=null) {
+ imageRegistry.put(key, imageDescriptor);
+ }
+ return imageDescriptor;
+ } catch (Exception ex) {
+ MavenLogger.log(key, ex);
+ return null;
+ }
+ }
+
+// private static Image createImage(String key) {
+// create(key);
+// ImageRegistry imageRegistry = getImageRegistry();
+// return imageRegistry==null ? null : imageRegistry.get(key);
+// }
+
+ private static ImageRegistry getImageRegistry() {
+ Activator plugin = Activator.getDefault();
+ return plugin==null ? null : plugin.getImageRegistry();
+ }
+
+ private static ImageDescriptor createDescriptor(String image) {
+ return AbstractUIPlugin.imageDescriptorFromPlugin(Activator.PLUGIN_ID, "icons/" + image); //$NON-NLS-1$
+ }
+
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/RefactoringMavenMenuCreator.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/RefactoringMavenMenuCreator.java
new file mode 100644
index 00000000..781599cd
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/RefactoringMavenMenuCreator.java
@@ -0,0 +1,36 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring.internal;
+
+import org.eclipse.jface.action.IMenuManager;
+import org.eclipse.m2e.core.actions.AbstractMavenMenuCreator;
+import org.eclipse.m2e.core.actions.SelectionUtil;
+import org.eclipse.m2e.refactoring.Messages;
+import org.eclipse.m2e.refactoring.exclude.DependencyExcludeAction;
+
+/**
+ * @author Eugene Kuleshov
+ */
+public class RefactoringMavenMenuCreator extends AbstractMavenMenuCreator {
+
+ public void createMenu(IMenuManager mgr) {
+ int selectionType = SelectionUtil.getSelectionType(selection);
+ if(selectionType == SelectionUtil.JAR_FILE) {
+ mgr.appendToGroup(OPEN, getAction(new DependencyExcludeAction(), //
+ DependencyExcludeAction.ID, //
+ Messages.RefactoringMavenMenuCreator_action_exclude, //
+ RefactoringImages.EXCLUDE));
+ }
+ }
+
+}
+
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/SaveDirtyFilesDialog.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/SaveDirtyFilesDialog.java
new file mode 100644
index 00000000..ec01227e
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/internal/SaveDirtyFilesDialog.java
@@ -0,0 +1,166 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring.internal;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+import org.eclipse.jface.dialogs.IDialogConstants;
+import org.eclipse.jface.dialogs.MessageDialog;
+import org.eclipse.jface.viewers.ILabelProvider;
+import org.eclipse.jface.viewers.IStructuredContentProvider;
+import org.eclipse.jface.viewers.LabelProvider;
+import org.eclipse.jface.viewers.Viewer;
+import org.eclipse.jface.window.Window;
+import org.eclipse.m2e.refactoring.Messages;
+import org.eclipse.swt.graphics.Image;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Display;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IWorkbench;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.dialogs.ListDialog;
+
+/**
+ * Taken from org.eclipse.wst.common.ui.internal.dialogs
+ *
+ * A generic save files dialog. The bulk of the code for this dialog was taken
+ * from the JDT refactoring support in
+ * org.eclipse.jdt.internal.ui.refactoring.RefactoringSaveHelper. This class is
+ * a good candidate for reuse amoung components.
+ */
+public class SaveDirtyFilesDialog extends ListDialog {
+ public static final String ALL_MODIFIED_RESOURCES_MUST_BE_SAVED_BEFORE_THIS_OPERATION = Messages.SaveDirtyFilesDialog_message_not_saved;
+
+ public static boolean saveDirtyFiles(String mask)
+ {
+ boolean result = true;
+ // TODO (cs) add support for save automatically
+ Shell shell = Display.getCurrent().getActiveShell();
+ IEditorPart[] dirtyEditors = getDirtyEditors(mask);
+ if (dirtyEditors.length > 0)
+ {
+ result = false;
+ SaveDirtyFilesDialog saveDirtyFilesDialog = new SaveDirtyFilesDialog(shell);
+ saveDirtyFilesDialog.setInput(Arrays.asList(dirtyEditors));
+ // Save all open editors.
+ if (saveDirtyFilesDialog.open() == Window.OK)
+ {
+ result = true;
+ int numDirtyEditors = dirtyEditors.length;
+ for (int i = 0; i < numDirtyEditors; i++)
+ {
+ dirtyEditors[i].doSave(null);
+ }
+ }
+ else
+ {
+ MessageDialog dlg = new MessageDialog(shell, Messages.SaveDirtyFilesDialog_title_error, null,
+ ALL_MODIFIED_RESOURCES_MUST_BE_SAVED_BEFORE_THIS_OPERATION,
+ MessageDialog.ERROR, new String[] {IDialogConstants.OK_LABEL}, 0);
+ dlg.open();
+ }
+ }
+ return result;
+ }
+
+ private static IEditorPart[] getDirtyEditors(String mask)
+ {
+ List<IEditorPart> result = new ArrayList<IEditorPart>(0);
+ IWorkbench workbench = PlatformUI.getWorkbench();
+ IWorkbenchWindow[] windows = workbench.getWorkbenchWindows();
+ for (int i = 0; i < windows.length; i++) {
+ IWorkbenchPage[] pages = windows[i].getPages();
+ for (int x = 0; x < pages.length; x++) {
+ IEditorPart[] editors = pages[x].getDirtyEditors();
+ for (int z = 0; z < editors.length; z++) {
+ IEditorPart ep = editors[z];
+ if (ep.getTitle().indexOf(mask) > 0) {
+ result.add(ep);
+ }
+ }
+ }
+ }
+ return result.toArray(new IEditorPart[result.size()]);
+ }
+
+ public SaveDirtyFilesDialog(Shell parent)
+ {
+ super(parent);
+ setTitle(Messages.SaveDirtyFilesDialog_title);
+ setAddCancelButton(true);
+ setLabelProvider(createDialogLabelProvider());
+ setMessage(ALL_MODIFIED_RESOURCES_MUST_BE_SAVED_BEFORE_THIS_OPERATION);
+ setContentProvider(new ListContentProvider());
+ }
+
+ protected Control createDialogArea(Composite container)
+ {
+ Composite result = (Composite) super.createDialogArea(container);
+ // TODO... provide preference that supports 'always save'
+ return result;
+ }
+
+
+ private ILabelProvider createDialogLabelProvider()
+ {
+ return new LabelProvider()
+ {
+ public Image getImage(Object element)
+ {
+ return ((IEditorPart) element).getTitleImage();
+ }
+
+ public String getText(Object element)
+ {
+ return ((IEditorPart) element).getTitle();
+ }
+ };
+ }
+
+ /**
+ * A specialized content provider to show a list of editor parts.
+ * This class has been copied from org.eclipse.jdt.internal.ui.viewsupport.ListContentProvider
+ * This class should be removed once a generic solution is made available.
+ */
+ @SuppressWarnings("unchecked")
+ static class ListContentProvider implements IStructuredContentProvider {
+ List fContents;
+
+ public Object[] getElements(Object input) {
+ if(fContents != null && fContents == input)
+ return fContents.toArray();
+ return new Object[0];
+ }
+
+ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
+ if(newInput instanceof List) {
+ fContents = (List) newInput;
+ } else {
+ fContents = null;
+ // we use a fixed set.
+ }
+ }
+
+ public void dispose() {
+ }
+
+ public boolean isDeleted(Object o) {
+ return fContents != null && !fContents.contains(o);
+ }
+ }
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/messages.properties b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/messages.properties
new file mode 100644
index 00000000..6c4053d5
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/messages.properties
@@ -0,0 +1,20 @@
+AbstractPomRefactoring_error=Problems during refactoring
+AbstractPomRefactoring_loading=Loading {0}
+AbstractPomRefactoring_task=Refactoring
+ExcludeRefactoring_error_parent=Parent dependency not found for {0}:{1}
+ExcludeRefactoring_name=Exclude Maven Artifact
+ExcludeRefactoring_task_loading=Loading dependency tree
+ExcludeRefactoring_title=Excluding {0}:{1} from {2}
+MavenRenameWizardPage_cbRenameWorkspace=&Rename Eclipse project in Workspace
+MavenRenameWizardPage_desc=Specify new group Id, artifact Id or version
+MavenRenameWizardPage_lblArtifactId=&Artifact Id:
+MavenRenameWizardPage_lblGroupId=&Group Id:
+MavenRenameWizardPage_lblVersion=&Version:
+MavenRenameWizardPage_title=Rename Maven Artifact
+RefactoringMavenMenuCreator_action_exclude=Exclude Maven artifact...
+RenameRefactoring_1=getVersion
+RenameRefactoring_name=Rename Maven Artifact
+RenameRefactoring_title=Renaming {0}
+SaveDirtyFilesDialog_message_not_saved=All modified resources must be saved before this operation.
+SaveDirtyFilesDialog_title=Save All Modified Resources
+SaveDirtyFilesDialog_title_error=Error
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/MavenRenameWizard.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/MavenRenameWizard.java
new file mode 100644
index 00000000..401ce95b
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/MavenRenameWizard.java
@@ -0,0 +1,40 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring.rename;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
+import org.eclipse.m2e.model.edit.pom.Model;
+import org.eclipse.m2e.refactoring.AbstractPomRefactoring;
+
+
+/**
+ * @author Anton Kraev
+ */
+public class MavenRenameWizard extends RefactoringWizard {
+
+ private static MavenRenameWizardPage page1 = new MavenRenameWizardPage();
+
+ public MavenRenameWizard(IFile file) {
+ super(new RenameRefactoring(file, page1), DIALOG_BASED_USER_INTERFACE);
+ }
+
+ @Override
+ protected void addUserInputPages() {
+ setDefaultPageTitle(getRefactoring().getName());
+ addPage(page1);
+ Model model = ((AbstractPomRefactoring) getRefactoring()).createModel();
+ page1.initialize(model.getGroupId(), model.getArtifactId(), model.getVersion());
+ model.eResource().unload();
+ }
+
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/MavenRenameWizardPage.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/MavenRenameWizardPage.java
new file mode 100644
index 00000000..19d47b00
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/MavenRenameWizardPage.java
@@ -0,0 +1,159 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring.rename;
+
+import org.eclipse.jface.dialogs.Dialog;
+import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
+import org.eclipse.m2e.refactoring.Messages;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.ModifyEvent;
+import org.eclipse.swt.events.ModifyListener;
+import org.eclipse.swt.events.SelectionAdapter;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.layout.GridData;
+import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Text;
+
+
+/**
+ * @author Anton Kraev
+ */
+public class MavenRenameWizardPage extends UserInputWizardPage {
+ private Text groupIdText;
+ private Text artifactIdText;
+ private Text versionText;
+ private Button renameCheckbox;
+
+ private String groupId;
+ private String artifactId;
+ private String version;
+ private String newGroupId = ""; //$NON-NLS-1$
+ private String newArtifactId = ""; //$NON-NLS-1$
+ private String newVersion = ""; //$NON-NLS-1$
+ private boolean renamed;
+
+ protected MavenRenameWizardPage() {
+ super("MavenRenameWizardPage"); //$NON-NLS-1$
+ setDescription(Messages.MavenRenameWizardPage_desc);
+ setTitle(Messages.MavenRenameWizardPage_title);
+ }
+
+ public void initialize(String groupId, String artifactID, String version) {
+ this.groupId = newGroupId = nvl(groupId);
+ this.artifactId = newArtifactId = nvl(artifactID);
+ this.version = newVersion = nvl(version);
+ }
+
+ public String getNewGroupId() {
+ return newGroupId;
+ }
+
+ public String getNewArtifactId() {
+ return newArtifactId;
+ }
+
+ public String getNewVersion() {
+ return newVersion;
+ }
+
+ @Override
+ public boolean isPageComplete() {
+ boolean renamedArtifact = !newArtifactId.equals(artifactId);
+ renameCheckbox.setEnabled(renamedArtifact);
+ if (!renamedArtifact) {
+ renameCheckbox.setSelection(false);
+ renamed = false;
+ }
+ return !newGroupId.equals(groupId) //
+ || renamedArtifact //
+ || !newVersion.equals(version) //
+ || !isCurrentPage();
+ }
+
+ public void createControl(Composite parent) {
+ Composite composite = new Composite(parent, SWT.NONE);
+ GridLayout gridLayout = new GridLayout(2, false);
+ gridLayout.marginWidth = 10;
+ gridLayout.marginHeight = 10;
+ composite.setLayout(gridLayout);
+ initializeDialogUnits(composite);
+ Dialog.applyDialogFont(composite);
+ setControl(composite);
+
+ Label groupIdLabel = new Label(composite, SWT.NONE);
+ groupIdLabel.setLayoutData(new GridData());
+ groupIdLabel.setText(Messages.MavenRenameWizardPage_lblGroupId);
+
+ groupIdText = new Text(composite, SWT.BORDER);
+ groupIdText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ groupIdText.setData("name", "groupId"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ Label artifactIdLabel = new Label(composite, SWT.NONE);
+ artifactIdLabel.setLayoutData(new GridData());
+ artifactIdLabel.setText(Messages.MavenRenameWizardPage_lblArtifactId);
+
+ artifactIdText = new Text(composite, SWT.BORDER);
+ artifactIdText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ artifactIdText.setData("name", "artifactId"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ Label versionLabel = new Label(composite, SWT.NONE);
+ versionLabel.setLayoutData(new GridData());
+ versionLabel.setText(Messages.MavenRenameWizardPage_lblVersion);
+
+ versionText = new Text(composite, SWT.BORDER);
+ versionText.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ versionText.setData("name", "version"); //$NON-NLS-1$ //$NON-NLS-2$
+
+ new Label(composite, SWT.NONE);
+
+ renameCheckbox = new Button(composite, SWT.CHECK);
+ renameCheckbox.setText(Messages.MavenRenameWizardPage_cbRenameWorkspace);
+ renameCheckbox.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
+ renameCheckbox.setData("name", "rename"); //$NON-NLS-1$ //$NON-NLS-2$
+ renameCheckbox.setEnabled(false);
+ renameCheckbox.addSelectionListener(new SelectionAdapter() {
+ public void widgetSelected(SelectionEvent e) {
+ renamed = renameCheckbox.getSelection();
+ getWizard().getContainer().updateButtons();
+ }
+ });
+
+ ModifyListener listener = new ModifyListener() {
+ public void modifyText(ModifyEvent e) {
+ newGroupId = groupIdText.getText();
+ newArtifactId = artifactIdText.getText();
+ newVersion = versionText.getText();
+ getWizard().getContainer().updateButtons();
+ }
+ };
+
+ groupIdText.setText(groupId);
+ artifactIdText.setText(artifactId);
+ versionText.setText(version);
+
+ groupIdText.addModifyListener(listener);
+ artifactIdText.addModifyListener(listener);
+ versionText.addModifyListener(listener);
+ }
+
+ private String nvl(String str) {
+ return str == null ? "" : str; //$NON-NLS-1$
+ }
+
+ public boolean getRenameEclipseProject() {
+ return renamed;
+ }
+
+}
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/RenameArtifactAction.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/RenameArtifactAction.java
new file mode 100644
index 00000000..0556df63
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/RenameArtifactAction.java
@@ -0,0 +1,79 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring.rename;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.resources.IProject;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.viewers.IStructuredSelection;
+import org.eclipse.ltk.ui.refactoring.RefactoringWizardOpenOperation;
+import org.eclipse.m2e.core.core.MavenLogger;
+import org.eclipse.m2e.refactoring.internal.SaveDirtyFilesDialog;
+import org.eclipse.swt.widgets.Event;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.PlatformUI;
+import org.eclipse.ui.actions.ActionDelegate;
+import org.eclipse.ui.internal.ObjectPluginAction;
+
+
+/**
+ * @author Anton Kraev
+ */
+@SuppressWarnings("restriction")
+public class RenameArtifactAction extends ActionDelegate {
+
+ @Override
+ public void init(IAction action) {
+ super.init(action);
+ }
+
+ @Override
+ public void run(IAction action) {
+ doRun(action);
+ }
+
+ @Override
+ public void runWithEvent(IAction action, Event event) {
+ doRun(action);
+ }
+
+ public void doRun(IAction action) {
+ Object element = ((IStructuredSelection) ((ObjectPluginAction) action).getSelection()).getFirstElement();
+ if(element instanceof IFile) {
+ rename((IFile) element);
+ } else if (element instanceof IProject) {
+ IProject project = (IProject) element;
+ IFile file = project.getFile("pom.xml"); //$NON-NLS-1$
+ if(file!=null) {
+ rename(file);
+ }
+ }
+ }
+
+ private void rename(IFile file) {
+ try {
+ // get the model from existing file
+ Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
+ boolean rc = SaveDirtyFilesDialog.saveDirtyFiles("pom.xml"); //$NON-NLS-1$
+ if (!rc)
+ return;
+ MavenRenameWizard wizard = new MavenRenameWizard(file);
+ RefactoringWizardOpenOperation op = new RefactoringWizardOpenOperation(wizard);
+ String titleForFailedChecks = ""; //$NON-NLS-1$
+ op.run(shell, titleForFailedChecks);
+ } catch(Exception e) {
+ MavenLogger.log("Unable to rename " + file, e);
+ }
+ }
+
+}
+
diff --git a/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/RenameRefactoring.java b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/RenameRefactoring.java
new file mode 100644
index 00000000..a0e495d5
--- /dev/null
+++ b/org.eclipse.m2e.refactoring/src/org/eclipse/m2e/refactoring/rename/RenameRefactoring.java
@@ -0,0 +1,332 @@
+/*******************************************************************************
+ * Copyright (c) 2008-2010 Sonatype, Inc.
+ * 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:
+ * Sonatype, Inc. - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.m2e.refactoring.rename;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+
+import org.eclipse.core.resources.IFile;
+import org.eclipse.core.runtime.CoreException;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.OperationCanceledException;
+import org.eclipse.emf.common.command.CompoundCommand;
+import org.eclipse.emf.ecore.EObject;
+import org.eclipse.emf.ecore.EStructuralFeature;
+import org.eclipse.emf.edit.command.SetCommand;
+import org.eclipse.emf.edit.domain.AdapterFactoryEditingDomain;
+import org.eclipse.ltk.core.refactoring.RefactoringStatus;
+import org.eclipse.m2e.core.MavenPlugin;
+import org.eclipse.m2e.model.edit.pom.Model;
+import org.eclipse.m2e.model.edit.pom.util.PomResourceImpl;
+import org.eclipse.m2e.refactoring.AbstractPomRefactoring;
+import org.eclipse.m2e.refactoring.Messages;
+import org.eclipse.m2e.refactoring.PomVisitor;
+import org.eclipse.m2e.refactoring.RefactoringModelResources;
+import org.eclipse.m2e.refactoring.RefactoringModelResources.PropertyInfo;
+import org.eclipse.osgi.util.NLS;
+
+
+/**
+ * Rename artifact refactoring implementation
+ *
+ * @author Anton Kraev
+ */
+@SuppressWarnings("unchecked")
+public class RenameRefactoring extends AbstractPomRefactoring {
+ private static final Object[] EMPTY_OBJECT_ARRAY = new Object[] {};
+ private static final String VERSION = "version"; //$NON-NLS-1$
+ private static final String GETVERSION = Messages.RenameRefactoring_1;
+ private static final String ARTIFACT_ID = "artifactId"; //$NON-NLS-1$
+ private static final String GETARTIFACT_ID = "getArtifactId"; //$NON-NLS-1$
+ private static final String GROUP_ID = "groupId"; //$NON-NLS-1$
+ private static final String GETGROUP_ID = "getGroupId"; //$NON-NLS-1$
+
+ // this page contains new values
+ MavenRenameWizardPage page;
+
+ // old values
+ String oldGroupId;
+ String oldArtifactId;
+ String oldVersion;
+
+ public RenameRefactoring(IFile file, MavenRenameWizardPage page) {
+ super(file);
+ this.page = page;
+ }
+
+ // gets element from effective model based on path
+ private Object getElement(Object root, Path path) {
+ if (path == null || path.path.size() == 0) {
+ return root;
+ }
+
+ PathElement current = path.path.remove(0);
+ String getterName = "get" + current.element; //$NON-NLS-1$
+
+ try {
+ Method getter = root.getClass().getMethod(getterName, new Class[] {});
+ root = getElement(getter.invoke(root, EMPTY_OBJECT_ARRAY), path);
+ if (root instanceof List) {
+ List children = (List) root;
+ for (int i=0; i<children.size(); i++) {
+ Object child = children.get(i);
+ Method artifact = child.getClass().getMethod(GETARTIFACT_ID, new Class[] {});
+ String artifactId = (String) artifact.invoke(child, EMPTY_OBJECT_ARRAY);
+ if (current.artifactId != null && !current.artifactId.equals(artifactId))
+ continue;
+
+ //found, names are correct
+ return getElement(child, path);
+ }
+ } else {
+ return getElement(root, path);
+ }
+ return null;
+ } catch(Exception ex) {
+ return null;
+ }
+ }
+
+ /**
+ * Finds all potential matched objects in model
+ */
+ private List<EObjectWithPath> scanModel(Model model, String groupId, String artifactId, String version, boolean processRoot) {
+ List<EObjectWithPath> res = new ArrayList<EObjectWithPath>();
+ Path path = new Path();
+ if(processRoot) {
+ scanObject(path, model, groupId, artifactId, version, res);
+ } else {
+ scanChildren(path, model, groupId, artifactId, version, res);
+ }
+ return res;
+ }
+
+ // add candidate objects with same artifactId
+ private List<EObjectWithPath> scanObject(Path current, EObject obj, String groupId, String artifactId, String version, List<EObjectWithPath> res) {
+ if (scanFeature(obj, ARTIFACT_ID, artifactId)) {
+ // System.out.println("found object " + obj + " : " + current);
+ res.add(new EObjectWithPath(obj, current));
+ }
+ scanChildren(current, obj, groupId, artifactId, version, res);
+ return res;
+ }
+
+ private List<EObjectWithPath> scanChildren(Path current, EObject obj, String groupId, String artifactId, String version, List<EObjectWithPath> res) {
+ Iterator<EObject> it = obj.eContents().iterator();
+ while(it.hasNext()) {
+ obj = it.next();
+ Path child = current.clone();
+ String element = obj.eContainingFeature().getName();
+ element = element.substring(0, 1).toUpperCase() + element.substring(1);
+ child.addElement(element, artifactId);
+ scanObject(child, obj, groupId, artifactId, version, res);
+ }
+ return res;
+ }
+
+ private boolean scanFeature(EObject obj, String featureName, String value) {
+ //not searching on this
+ if(value == null) {
+ return false;
+ }
+ EStructuralFeature feature = obj.eClass().getEStructuralFeature(featureName);
+ if(feature == null) {
+ return false;
+ }
+ String val = obj.eGet(feature) == null ? null : obj.eGet(feature).toString();
+ if(value.equals(val)) {
+ return true;
+ }
+ return false;
+ }
+
+ private String getValue(EObject obj, String featureName) {
+ EStructuralFeature feature = obj.eClass().getEStructuralFeature(featureName);
+ if(feature == null) {
+ return null;
+ }
+ return obj.eGet(feature) == null ? null : obj.eGet(feature).toString();
+ }
+
+ public String getNewProjectName() {
+ return page.getRenameEclipseProject()? page.getNewArtifactId(): null;
+ }
+
+ /**
+ * Applies new values in model
+ * @param editingDomain
+ * @param renameProject
+ * @throws NoSuchMethodException
+ * @throws Exception
+ */
+ public CompoundCommand applyModel(RefactoringModelResources model,
+ String newGroupId, String newArtifactId, String newVersion, boolean processRoot) throws Exception {
+ // find all affected objects in EMF model
+ List<EObjectWithPath> affected = scanModel(model.getTmpModel(), this.oldGroupId, this.oldArtifactId, this.oldVersion, processRoot);
+
+ // go through all affected objects, check in effective model
+ Iterator<EObjectWithPath> i = affected.iterator();
+ CompoundCommand command = new CompoundCommand();
+ while (i.hasNext()) {
+ EObjectWithPath obj = i.next();
+ Object effectiveObj = getElement(model.getEffective(), obj.path.clone());
+ if (effectiveObj == null) {
+ // System.out.println("cannot find effective for: " + obj.object);
+ continue;
+ }
+ Method method = effectiveObj.getClass().getMethod(GETVERSION, new Class[] {});
+ String effectiveVersion = (String) method.invoke(effectiveObj, EMPTY_OBJECT_ARRAY);
+ method = effectiveObj.getClass().getMethod(GETGROUP_ID, new Class[] {});
+ String effectiveGroupId = (String) method.invoke(effectiveObj, EMPTY_OBJECT_ARRAY);
+ // if version from effective POM is different from old version, skip it
+ if (this.oldVersion != null && !this.oldVersion.equals(effectiveVersion)) {
+ continue;
+ }
+
+ // only set groupId if effective group id is the same as old group id
+ if (oldGroupId != null && oldGroupId.equals(effectiveGroupId))
+ applyFeature(editingDomain, model, GROUP_ID, newGroupId, command, obj);
+ // set artifact id unconditionally
+ applyFeature(editingDomain, model, ARTIFACT_ID, newArtifactId, command, obj);
+ // only set version if effective version is the same (already checked by the above)
+ // and new version is not empty
+ if (!"".equals(newVersion)) { //$NON-NLS-1$
+ applyFeature(editingDomain, model, VERSION, newVersion, command, obj);
+ }
+ }
+
+ return command.isEmpty()? null: command;
+ }
+
+ // apply the value, considering properties
+ private void applyFeature(AdapterFactoryEditingDomain editingDomain, RefactoringModelResources model,
+ String feature, String newValue, CompoundCommand command, EObjectWithPath obj) {
+ PropertyInfo info = null;
+ String old = getValue(obj.object, feature);
+ if (old != null && old.startsWith("${")) { //$NON-NLS-1$
+ // this is a property, go find it
+ String pName = old.substring(2);
+ pName = pName.substring(0, pName.length() - 1).trim();
+ info = model.getProperties().get(pName);
+ }
+ if (info != null)
+ info.setNewValue(new SetCommand(editingDomain, info.getPair(), info.getPair().eClass().getEStructuralFeature("value"), newValue)); //$NON-NLS-1$
+ else
+ applyObject(editingDomain, command, obj.object, feature, newValue);
+ }
+
+ private void applyObject(AdapterFactoryEditingDomain editingDomain, CompoundCommand command, EObject obj,
+ String featureName, String value) {
+ EStructuralFeature feature = obj.eClass().getEStructuralFeature(featureName);
+ if(feature == null) {
+ return;
+ }
+ Object old = obj.eGet(feature);
+ if(old == null || old.equals(value)) {
+ return;
+ }
+ command.append(new SetCommand(editingDomain, obj, feature, value));
+ }
+
+ @Override
+ public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException {
+ PomResourceImpl resource = MavenPlugin.getDefault().getMavenModelManager().loadResource(file);
+ try {
+ Model model = (Model)resource.getContents().get(0);
+ this.oldArtifactId = model.getArtifactId();
+ this.oldGroupId = model.getGroupId();
+ this.oldVersion = model.getVersion();
+ } finally {
+ resource.unload();
+ }
+ RefactoringStatus res = new RefactoringStatus();
+ return res;
+ }
+
+ @Override
+ public String getName() {
+ return Messages.RenameRefactoring_name;
+ }
+
+ @Override
+ public PomVisitor getVisitor() {
+ return new PomVisitor() {
+
+ public CompoundCommand applyChanges(RefactoringModelResources current, IProgressMonitor pm) throws Exception {
+ //process <project> element only for the refactored file itself
+ boolean processRoot = current.getPomFile().equals(file);
+ return RenameRefactoring.this.applyModel(current, page.getNewGroupId(),
+ page.getNewArtifactId(), page.getNewVersion(), processRoot);
+ }
+ };
+ }
+
+ static class Path {
+ List<PathElement> path = new ArrayList<PathElement>();
+
+ public void addElement(String element, String artifactId) {
+ path.add(new PathElement(element, artifactId));
+ }
+
+ public String toString() {
+ return path.toString();
+ }
+
+ public Path clone() {
+ Path res = new Path();
+ res.path = new ArrayList<PathElement>(this.path);
+ return res;
+ }
+ }
+
+ // path (built during traversal of EMF model, used to find in effective model)
+ static class PathElement {
+ String element;
+ String artifactId;
+
+ public PathElement(String element, String artifactId) {
+ this.element = element;
+ this.artifactId = artifactId;
+ }
+
+ public String toString() {
+ return "/" + element + "[artifactId=" + artifactId + "]"; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ }
+ }
+
+ static class EObjectWithPath {
+ public EObject object;
+ public Path path;
+
+ public EObjectWithPath(EObject object, Path path) {
+ this.object = object;
+ this.path = path;
+ }
+ }
+
+ // XXX move stuff UP after implementing another refactoring
+ // after moving up, use this
+ interface ScanVisitor {
+ public boolean interested(EObject obj);
+ }
+
+ public boolean scanAllArtifacts() {
+ return true;
+ }
+
+ public String getTitle() {
+ return NLS.bind(Messages.RenameRefactoring_title, file.getParent().getName());
+ }
+
+}

Back to the top