/************************************************************************************* * Copyright (c) 2014 Red Hat, Inc. and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * JBoss by Red Hat - Initial implementation. ************************************************************************************/ package org.jboss.tools.arquillian.editor.internal.refactoring; import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.performOnDOMDocument; import java.util.ArrayList; import java.util.List; import org.apache.maven.model.Dependency; import org.apache.maven.project.MavenProject; 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.core.resources.IProject; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Status; import org.eclipse.jface.text.IDocument; import org.eclipse.ltk.core.refactoring.Change; import org.eclipse.ltk.core.refactoring.DocumentChange; import org.eclipse.ltk.core.refactoring.Refactoring; import org.eclipse.ltk.core.refactoring.RefactoringStatus; import org.eclipse.ltk.core.refactoring.TextChange; import org.eclipse.ltk.core.refactoring.TextFileChange; import org.eclipse.m2e.core.MavenPlugin; import org.eclipse.m2e.core.internal.IMavenConstants; import org.eclipse.m2e.core.project.IMavenProjectFacade; import org.eclipse.m2e.core.ui.internal.editing.PomEdits.CompoundOperation; import org.eclipse.m2e.core.ui.internal.editing.PomEdits.Operation; import org.eclipse.m2e.core.ui.internal.editing.PomEdits.OperationTuple; import org.eclipse.text.edits.MultiTextEdit; import org.eclipse.text.edits.ReplaceEdit; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.wst.sse.core.StructuredModelManager; import org.eclipse.wst.sse.core.internal.provisional.IStructuredModel; import org.eclipse.wst.xml.core.internal.provisional.document.IDOMModel; import org.jboss.tools.arquillian.ui.ArquillianUIActivator; import org.jboss.tools.arquillian.ui.internal.refactoring.AddDependencies; import org.jboss.tools.arquillian.ui.internal.refactoring.RangeComparator; /** * A refactoring to add Arquillian dependencies to project * * @author snjeza * */ public class AddDependenciesRefactoring extends Refactoring { private IProject project; private List<Dependency> dependencies; /** * @param project */ public AddDependenciesRefactoring(IProject project, List<Dependency> dependencies) { super(); this.project = project; this.dependencies = dependencies; } /* * (non-Javadoc) * * @see org.eclipse.ltk.core.refactoring.Refactoring#getName() */ @Override public String getName() { return "Add Arquillian dependencies"; } /* * (non-Javadoc) * * @see * org.eclipse.ltk.core.refactoring.Refactoring#checkInitialConditions(org * .eclipse.core.runtime.IProgressMonitor) */ @Override public RefactoringStatus checkInitialConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException { boolean isMavenProject = project != null && project.hasNature(IMavenConstants.NATURE_ID); if (!isMavenProject) { IStatus status = new Status(IStatus.ERROR, ArquillianUIActivator.PLUGIN_ID, "The project is not a valid maven project"); return RefactoringStatus.create(status); } return RefactoringStatus.create(Status.OK_STATUS); } /* * (non-Javadoc) * * @see * org.eclipse.ltk.core.refactoring.Refactoring#checkFinalConditions(org * .eclipse.core.runtime.IProgressMonitor) */ @Override public RefactoringStatus checkFinalConditions(IProgressMonitor pm) throws CoreException, OperationCanceledException { RefactoringStatus status = checkInitialConditions(pm); if (!status.isOK()) { return status; } IFile file = getFile(); if (file == null || !file.exists()) { IStatus s = new Status(IStatus.ERROR, ArquillianUIActivator.PLUGIN_ID, "The pom.xml file does not exist"); return RefactoringStatus.create(s); } IMavenProjectFacade facade = MavenPlugin.getMavenProjectRegistry() .create(project, new NullProgressMonitor()); if (facade == null) { IStatus s = new Status(IStatus.ERROR, ArquillianUIActivator.PLUGIN_ID, "The project is not a valid maven project"); return RefactoringStatus.create(s); } return status; } /* * (non-Javadoc) * * @see * org.eclipse.ltk.core.refactoring.Refactoring#createChange(org.eclipse * .core.runtime.IProgressMonitor) */ @Override public Change createChange(IProgressMonitor pm) throws CoreException, OperationCanceledException { IFile file = getFile(); IMavenProjectFacade facade = MavenPlugin.getMavenProjectRegistry().create(project, new NullProgressMonitor()); MavenProject mavenProject = facade.getMavenProject(new NullProgressMonitor()); List<Operation> operations = new ArrayList<Operation>(); if (dependencies != null) { operations.add(new AddDependencies(dependencies, mavenProject)); } CompoundOperation compound = new CompoundOperation(operations.toArray(new Operation[0])); return createChange(file, compound, getName()); } private Change createChange(IFile file, Operation operation, String label) throws CoreException { IStructuredModel model = null; try { model = StructuredModelManager.getModelManager().getModelForRead(file); IDocument document = model.getStructuredDocument(); boolean existing = isOpened(document); IStructuredModel tempModel = StructuredModelManager.getModelManager().createUnManagedStructuredModelFor( "org.eclipse.m2e.core.pomFile"); //$NON-NLS-1$ tempModel.getStructuredDocument().setText(StructuredModelManager.getModelManager(), document.get()); IDocument tempDocument = tempModel.getStructuredDocument(); performOnDOMDocument(new OperationTuple((IDOMModel) tempModel, operation)); TextChange change = createChange(existing ? null : file, document, tempDocument, label); return change; } catch (Exception e) { ArquillianUIActivator.log(e); throw new CoreException(new Status(IStatus.ERROR, ArquillianUIActivator.PLUGIN_ID, "An error occurred creating change", e)); } finally { if (model != null) { model.releaseFromRead(); } } } private TextChange createChange(IFile oldFile, IDocument oldDocument, IDocument newDocument, String label) { TextChange change = oldFile == null ? new DocumentChange(label, oldDocument) : new TextFileChange(label, oldFile); MultiTextEdit textEdit = new MultiTextEdit(); change.setEdit(textEdit); String newText = newDocument.get(); String oldText = oldDocument.get(); if (!newText.equals(oldText)) { IRangeComparator right = new RangeComparator(oldText); IRangeComparator left = new RangeComparator(newText); RangeDifference[] differences = RangeDifferencer.findDifferences(right, left); for (RangeDifference difference : differences) { int rightStart = difference.rightStart(); int rightEnd = difference.rightEnd(); String text = newText.substring(rightStart, rightEnd); int leftStart = difference.leftStart(); int leftLength = difference.leftLength(); textEdit.addChild(new ReplaceEdit(leftStart, leftLength, text)); } } return change; } private static boolean isOpened(IDocument document) { for (IWorkbenchWindow window : PlatformUI.getWorkbench() .getWorkbenchWindows()) { for (IWorkbenchPage page : window.getPages()) { for (IEditorReference ref : page.getEditorReferences()) { IEditorPart editor = ref.getEditor(false); if (editor != null) { IDocument doc = (IDocument) editor .getAdapter(IDocument.class); if (doc != null && doc.equals(document)) { return true; } } } } } return false; } private IFile getFile() throws CoreException { if (project == null || !project.hasNature(IMavenConstants.NATURE_ID)) { return null; } return project.getFile(IMavenConstants.POM_FILE_NAME); } public IProject getProject() { return project; } public List<Dependency> getDependencies() { return dependencies; } public void setDependencies(List<Dependency> dependencies) { this.dependencies = dependencies; } }