blob: 69e08089054e13e25983f574025fe91dee0da7b1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2018 Sonatype, Inc. and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*******************************************************************************/
package org.eclipse.m2e.core.ui.internal.editing;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.ARTIFACT_ID;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.CLASSIFIER;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.DEPENDENCIES;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.DEPENDENCY;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.GROUP_ID;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.PLUGIN;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.SCOPE;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.TYPE;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.VERSION;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.childEquals;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.createElement;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.createElementWithText;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.findChild;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.findChilds;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.format;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.getChild;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.performOnDOMDocument;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.removeChild;
import static org.eclipse.m2e.core.ui.internal.editing.PomEdits.setText;
import java.util.List;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.text.IDocument;
import org.eclipse.ltk.core.refactoring.TextChange;
import org.eclipse.ltk.core.refactoring.TextFileChange;
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.apache.maven.model.Dependency;
import org.eclipse.m2e.core.ui.internal.M2EUIPluginActivator;
import org.eclipse.m2e.core.ui.internal.Messages;
import org.eclipse.m2e.core.ui.internal.editing.PomEdits.Operation;
import org.eclipse.m2e.core.ui.internal.editing.PomEdits.OperationTuple;
public final class PomHelper {
private static final Logger LOG = LoggerFactory.getLogger(PomHelper.class);
/*
* Return the Element matching the dependency or null,
* PLEASE NOTE: the dependency values are resolved, while the xml content is not, which makes the method
* not as reliable as the signature suggests
*/
public static Element findDependency(Document document, Dependency dependency) {
Element dependenciesElement = findChild(document.getDocumentElement(), DEPENDENCIES);
return findChild(dependenciesElement, DEPENDENCY, childEquals(GROUP_ID, dependency.getGroupId()),
childEquals(ARTIFACT_ID, dependency.getArtifactId()));
}
private static boolean isOpened(IDocument document) {
for(IWorkbenchWindow window : PlatformUI.getWorkbench().getWorkbenchWindows()) {
for(IWorkbenchPage page : window.getPages()) {
//page.getEditors() - this call restores all the pages content, didn't feel like doing so, unless
// we can bring to life only the maven pom editors..
for(IEditorReference ref : page.getEditorReferences()) {
IEditorPart editor = ref.getEditor(false);
if(editor != null) {
IDocument doc = editor.getAdapter(IDocument.class);
if(doc != null && doc.equals(document)) {
return true;
}
}
}
}
}
return false;
}
/**
* @param file
* @param operation
* @param label
* @param forceSave if true will save all files, no matter if associated document is opened in editor area or not.
* @return
* @throws CoreException
*/
@SuppressWarnings("restriction")
public static TextChange createChange(IFile file, Operation operation, String label, boolean forceSave)
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 = new ChangeCreator(!forceSave && existing ? null : file, document, tempDocument, label)
.createChange();
if(forceSave)
assert change instanceof TextFileChange; //if assert not fullfilled, we will not get the file saved..
if(forceSave && change instanceof TextFileChange) {
((TextFileChange) change).setSaveMode(TextFileChange.FORCE_SAVE);
}
return change;
} catch(Exception exc) {
LOG.error(Messages.PomHelper_errorCreatingChange, exc);
throw new CoreException(new Status(IStatus.ERROR, M2EUIPluginActivator.PLUGIN_ID,
Messages.PomHelper_errorCreatingChange, exc));
} finally {
if(model != null) {
model.releaseFromRead();
}
}
}
/**
* by default will create a change that won't save files with opened documents
*
* @param file
* @param operation
* @param label
* @return
* @throws CoreException
*/
public static TextChange createChange(IFile file, Operation operation, String label) throws CoreException {
return createChange(file, operation, label, false);
}
/**
* creates and adds new plugin to the parent. Formats the result.
*
* @param parentList
* @param groupId null or value
* @param artifactId never null
* @param version null or value
* @return
*/
public static Element createPlugin(Element parentList, String groupId, String artifactId, String version) {
Document doc = parentList.getOwnerDocument();
Element plug = doc.createElement(PLUGIN);
parentList.appendChild(plug);
if(groupId != null) {
createElementWithText(plug, GROUP_ID, groupId);
}
createElementWithText(plug, ARTIFACT_ID, artifactId);
if(version != null) {
createElementWithText(plug, VERSION, version);
}
format(plug);
return plug;
}
/**
* creates and adds new dependency to the parent. formats the result.
*
* @param parentList
* @param groupId null or value
* @param artifactId never null
* @param version null or value
* @return
*/
public static Element createDependency(Element parentList, String groupId, String artifactId, String version) {
Element dep = createElement(parentList, DEPENDENCY);
if(groupId != null) {
createElementWithText(dep, GROUP_ID, groupId);
}
createElementWithText(dep, ARTIFACT_ID, artifactId);
if(version != null) {
createElementWithText(dep, VERSION, version);
}
format(dep);
return dep;
}
/**
* node is expected to be the node containing <dependencies> node, so <project>, <dependencyManagement> etc..
*
* @param node
* @return
*/
public static List<Element> findDependencies(Element node) {
return findChilds(findChild(node, DEPENDENCIES), DEPENDENCY);
}
/**
* null in any value parameter mean remove the element.
*
* @param depsEl
* @param groupId
* @param artifactId
* @param version
* @param type
* @param scope
* @param classifier
* @return the root xml element of the dependency
*/
public static Element addOrUpdateDependency(Element depsEl, String groupId, String artifactId, String version,
String type, String scope, String classifier) {
Element dep = findChild(depsEl, DEPENDENCY, childEquals(GROUP_ID, groupId), childEquals(ARTIFACT_ID, artifactId));
if(dep == null) {
dep = createDependency(depsEl, groupId, artifactId, version);
} else {
//only set version if already exists
if(version != null) {
setText(getChild(dep, VERSION), version);
} else {
removeChild(dep, findChild(dep, VERSION));
}
}
if(type != null //
&& !"jar".equals(type) // //$NON-NLS-1$
&& !"null".equals(type)) { // guard against MNGECLIPSE-622 //$NON-NLS-1$
setText(getChild(dep, TYPE), type);
} else {
removeChild(dep, findChild(dep, TYPE));
}
if(classifier != null) {
setText(getChild(dep, CLASSIFIER), classifier);
} else {
removeChild(dep, findChild(dep, CLASSIFIER));
}
if(scope != null && !"compile".equals(scope)) { //$NON-NLS-1$
setText(getChild(dep, SCOPE), scope);
} else {
removeChild(dep, findChild(dep, SCOPE));
}
return dep;
}
}