package org.springframework.roo.project;
import static org.springframework.roo.project.DependencyScope.COMPILE;
import static org.springframework.roo.support.util.AnsiEscapeCode.FG_CYAN;
import static org.springframework.roo.support.util.AnsiEscapeCode.decorate;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.ReferenceCardinality;
import org.apache.felix.scr.annotations.ReferencePolicy;
import org.apache.felix.scr.annotations.ReferenceStrategy;
import org.springframework.roo.metadata.MetadataService;
import org.springframework.roo.model.JavaPackage;
import org.springframework.roo.process.manager.FileManager;
import org.springframework.roo.project.maven.Pom;
import org.springframework.roo.shell.Shell;
import org.springframework.roo.support.util.CollectionUtils;
import org.springframework.roo.support.util.DomUtils;
import org.springframework.roo.support.util.XmlElementBuilder;
import org.springframework.roo.support.util.XmlUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/**
* Provides common project operations. Should be subclassed by a
* project-specific operations subclass.
*
* @author Ben Alex
* @author Adrian Colyer
* @author Stefan Schmidt
* @author Alan Stewart
* @author Juan Carlos GarcÃa
* @author Paula Navarro
* @since 1.0
*/
//@SuppressWarnings("deprecation")
@Component(componentAbstract = true)
@Reference(name = "feature", strategy = ReferenceStrategy.EVENT, policy = ReferencePolicy.DYNAMIC,
referenceInterface = Feature.class, cardinality = ReferenceCardinality.OPTIONAL_MULTIPLE)
public abstract class AbstractProjectOperations implements ProjectOperations {
private static final String DEFAULT_VALUE_TEXT = "VALUE_TEXT";
static final String ADDED = "added";
static final String CHANGED = "changed";
static final String REMOVED = "removed";
static final String SKIPPED = "skipped";
static final String UPDATED = "updated";
private final Map<String, Feature> features = new HashMap<String, Feature>();
@Reference(policy = ReferencePolicy.DYNAMIC)
protected FileManager fileManager;
@Reference(policy = ReferencePolicy.DYNAMIC)
protected MetadataService metadataService;
@Reference(policy = ReferencePolicy.DYNAMIC)
protected PathResolver pathResolver;
@Reference(policy = ReferencePolicy.DYNAMIC)
protected PomManagementService pomManagementService;
@Reference(policy = ReferencePolicy.DYNAMIC)
protected Shell shell;
/**
* Generates a message about the addition of the given items to the POM
*
* @param action the past tense of the action that was performed
* @param items the items that were acted upon (required, can be empty)
* @param singular the singular of this type of item (required)
* @param plural the plural of this type of item (required)
* @return a non-<code>null</code> message
* @since 1.2.0
*/
static String getDescriptionOfChange(final String action, final Collection<String> items,
final String singular, final String plural) {
if (items.isEmpty()) {
return "";
}
return highlight(action + " " + (items.size() == 1 ? singular : plural)) + " "
+ StringUtils.join(items, ", ");
}
/**
* Highlights the given text
*
* @param text the text to highlight (can be blank)
* @return the highlighted text
*/
static String highlight(final String text) {
return decorate(text, FG_CYAN);
}
@Override
public void addBuildPlugin(final String moduleName, final Plugin plugin) {
addBuildPlugin(moduleName, plugin, true);
}
@Override
public void addBuildPlugin(final String moduleName, final Plugin plugin,
boolean addToPluginManagement) {
Validate.isTrue(isProjectAvailable(moduleName), "Plugin modification prohibited at this time");
Validate.notNull(plugin, "Plugin required");
addBuildPlugins(moduleName, Collections.singletonList(plugin), addToPluginManagement);
}
@Override
public void addBuildPlugins(final String moduleName, final Collection<? extends Plugin> newPlugins) {
addBuildPlugins(moduleName, newPlugins, true);
}
@Override
public void addBuildPlugins(final String moduleName,
final Collection<? extends Plugin> newPlugins, boolean addToPluginManagement) {
Validate.isTrue(isProjectAvailable(moduleName), "Plugin modification prohibited at this time");
Validate.notNull(newPlugins, "Plugins required");
if (CollectionUtils.isEmpty(newPlugins)) {
return;
}
final Pom parentPom = getPomFromModuleName("");
boolean isSamePom = false;
Pom pom = null;
if ("".equals(moduleName)) {
isSamePom = true;
pom = parentPom;
} else {
pom = getPomFromModuleName(moduleName);
}
Validate.notNull(parentPom,
"The parentPom is not available, so plugin addition cannot be performed");
Validate.notNull(pom, "The pom is not available, so plugin addition cannot be performed");
final Document parentDocument =
XmlUtils.readXml(fileManager.getInputStream(parentPom.getPath()));
Document document = null;
if (isSamePom) {
document = parentDocument;
} else {
document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
}
writePluginInPom(newPlugins, parentPom, pom, parentDocument, document,
parentDocument.getDocumentElement(), document.getDocumentElement(), addToPluginManagement,
isSamePom);
}
@Override
public List<Dependency> addDependencies(final String moduleName,
final Collection<? extends Dependency> newDependencies) {
return addDependencies(moduleName, newDependencies, true, false);
}
@Override
public List<Dependency> addDependencies(final String moduleName,
final Collection<? extends Dependency> newDependencies, boolean addToDependencyManagement,
boolean checkFullDependency) {
Validate.isTrue(isProjectAvailable(moduleName),
"Dependency modification prohibited; no such module '%s'", moduleName);
final Pom parentPom = getPomFromModuleName("");
boolean isSamePom = false;
Pom pom = null;
if ("".equals(moduleName)) {
isSamePom = true;
pom = parentPom;
} else {
pom = getPomFromModuleName(moduleName);
}
Validate.notNull(pom, "The pom is not available, so dependencies cannot be added");
final Document parentDocument =
XmlUtils.readXml(fileManager.getInputStream(parentPom.getPath()));
Document document = null;
if (isSamePom) {
document = parentDocument;
} else {
document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
}
return writeDependencyInPom(newDependencies, parentPom, pom, parentDocument, document,
parentDocument.getDocumentElement(), document.getDocumentElement(),
addToDependencyManagement, isSamePom, checkFullDependency);
}
@Override
public Dependency addDependency(final String moduleName, final Dependency dependency) {
return addDependency(moduleName, dependency, true, false);
}
@Override
public Dependency addDependency(final String moduleName, final Dependency dependency,
boolean addToDependencyManagement) {
return addDependency(moduleName, dependency, addToDependencyManagement, false);
}
@Override
public Dependency addDependency(final String moduleName, final Dependency dependency,
boolean addToDependencyManagement, boolean checkFullDependency) {
Validate.isTrue(isProjectAvailable(moduleName),
"Dependency modification prohibited at this time");
Validate.notNull(dependency, "Dependency required");
List<Dependency> result =
addDependencies(moduleName, Collections.singletonList(dependency),
addToDependencyManagement, checkFullDependency);
if (result.isEmpty()) {
return null;
}
return result.get(0);
}
@Override
public final Dependency addDependency(final String moduleName, final String groupId,
final String artifactId, final String version) {
return addDependency(moduleName, groupId, artifactId, version, true);
}
@Override
public final Dependency addDependency(final String moduleName, final String groupId,
final String artifactId, final String version, boolean addToDependencyManagement) {
return addDependency(moduleName, groupId, artifactId, version, COMPILE,
addToDependencyManagement);
}
@Override
public final Dependency addDependency(final String moduleName, final String groupId,
final String artifactId, final String version, final DependencyScope scope) {
return addDependency(moduleName, groupId, artifactId, version, scope, true);
}
@Override
public final Dependency addDependency(final String moduleName, final String groupId,
final String artifactId, final String version, final DependencyScope scope,
boolean addToDependencyManagement) {
return addDependency(moduleName, groupId, artifactId, version, scope, "",
addToDependencyManagement);
}
@Override
public final Dependency addDependency(final String moduleName, final String groupId,
final String artifactId, final String version, DependencyScope scope, final String classifier) {
return addDependency(moduleName, groupId, artifactId, version, scope, classifier, true);
}
@Override
public final Dependency addDependency(final String moduleName, final String groupId,
final String artifactId, final String version, DependencyScope scope,
final String classifier, boolean addToDependencyManagement) {
Validate.isTrue(isProjectAvailable(moduleName),
"Dependency modification prohibited at this time");
Validate.notNull(groupId, "Group ID required");
Validate.notNull(artifactId, "Artifact ID required");
Validate.notBlank(version, "Version required");
if (scope == null) {
scope = COMPILE;
}
final Dependency dependency =
new Dependency(groupId, artifactId, version, DependencyType.JAR, scope, classifier);
return addDependency(moduleName, dependency, addToDependencyManagement, false);
}
public void addFilter(final String moduleName, final Filter filter) {
Validate.isTrue(isProjectAvailable(moduleName), "Filter modification prohibited at this time");
Validate.notNull(filter, "Filter required");
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so filter addition cannot be performed");
if (filter == null || pom.isFilterRegistered(filter)) {
return;
}
final Document document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
final Element root = document.getDocumentElement();
final String descriptionOfChange;
final Element buildElement = XmlUtils.findFirstElement("/project/build", root);
final Element existingFilter =
XmlUtils.findFirstElement("filters/filter['" + filter.getValue() + "']", buildElement);
if (existingFilter == null) {
// No such filter; add it
final Element filtersElement =
DomUtils.createChildIfNotExists("filters", buildElement, document);
filtersElement.appendChild(XmlUtils.createTextElement(document, "filter", filter.getValue()));
descriptionOfChange = highlight(ADDED + " filter") + " '" + filter.getValue() + "'";
} else {
existingFilter.setTextContent(filter.getValue());
descriptionOfChange = highlight(UPDATED + " filter") + " '" + filter.getValue() + "'";
}
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
descriptionOfChange, false);
}
@Override
public void addPackageToPluginExecution(final String moduleName, final Plugin plugin,
String executionId, final String packageName) {
addPackageToPluginExecution(moduleName, plugin, executionId, packageName, true);
}
@Override
public void addPackageToPluginExecution(final String moduleName, final Plugin plugin,
String executionId, final String packageName, boolean addToPluginManagement) {
// Delegates in generic addElementToPluginExecution
addElementToPluginExecution(moduleName, plugin, executionId, "packages", "package",
packageName, addToPluginManagement);
}
@Override
public void addElementToPluginExecution(final String moduleName, final Plugin plugin,
String executionId, String parentElementName, String elementName, final String elementValue) {
addElementToPluginExecution(moduleName, plugin, executionId, parentElementName, elementName,
elementValue, true);
}
@Override
public void addElementToPluginExecution(final String moduleName, final Plugin plugin,
String executionId, String parentElementName, String elementName, String elementValue,
boolean addToPluginManagement) {
Map<String, String> elementValues = new HashMap<String, String>();
elementValues.put(DEFAULT_VALUE_TEXT, elementValue);
addElementToPluginExecution(moduleName, plugin, executionId, parentElementName, elementName,
elementValues, addToPluginManagement);
}
@Override
public void addElementToPluginExecution(final String moduleName, final Plugin plugin,
String executionId, String parentElementName, String elementName,
Map<String, String> elementValues) {
addElementToPluginExecution(moduleName, plugin, executionId, parentElementName, elementName,
elementValues, true);
}
@Override
public void addElementToPluginExecution(final String moduleName, final Plugin plugin,
String executionId, String parentElementName, String elementName,
Map<String, String> elementValues, boolean addToPluginManagement) {
Validate.isTrue(isProjectAvailable(moduleName), "Package modification prohibited at this time");
Validate.notNull(executionId, "Execution id required");
Validate.notNull(plugin, "Plugin required");
Validate.notNull(parentElementName, "parentElementName required");
Validate.notNull(elementName, "elementName required");
Validate.notNull(elementValues, "elementValues required");
String descriptionOfChange;
final Pom parentPom = getPomFromModuleName("");
boolean isSamePom = false;
Pom pom = null;
if ("".equals(moduleName)) {
isSamePom = true;
pom = parentPom;
} else {
pom = getPomFromModuleName(moduleName);
}
Validate.notNull(parentPom,
"The parentPom is not available, so plugin addition cannot be performed");
Validate.notNull(pom, "The pom is not available, so plugin addition cannot be performed");
final Document parentDocument =
XmlUtils.readXml(fileManager.getInputStream(parentPom.getPath()));
Document document = null;
if (isSamePom) {
document = parentDocument;
} else {
document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
}
final Element parentRoot = parentDocument.getDocumentElement();
final Element root = document.getDocumentElement();
// Find plugin
Element pluginsElement = null;
if (addToPluginManagement) {
pluginsElement =
DomUtils.createChildIfNotExists("build/pluginManagement/plugins", parentRoot,
parentDocument);
} else {
pluginsElement = DomUtils.createChildIfNotExists("/project/build/plugins", root, document);
}
final List<Element> existingPluginElements = XmlUtils.findElements("plugin", pluginsElement);
for (final Element existingPluginElement : existingPluginElements) {
final Plugin existingPlugin = new Plugin(existingPluginElement);
if (existingPlugin.hasSameCoordinates(plugin)) {
for (final Execution execution : existingPlugin.getExecutions()) {
if (executionId.equals(execution.getId()) && execution.getConfiguration() != null) {
// Check if element is already added
final Element elementsElement =
DomUtils.createChildIfNotExists(parentElementName, execution.getConfiguration()
.getConfiguration(), document);
final List<Element> existingElements =
XmlUtils.findElements(elementName, elementsElement);
for (Element existingElement : existingElements) {
for (Entry<String, String> element : elementValues.entrySet()) {
if (elementValues.size() == 1 && element.getKey().equals(DEFAULT_VALUE_TEXT)) {
final String elem = DomUtils.getTextContent(existingElement, "");
if (elem.equals(element.getValue())) {
return;
}
} else {
Element childElement =
DomUtils.getChildElementByTagName(existingElement, element.getKey());
if (childElement != null
&& DomUtils.getTextContent(childElement, "").equals(element.getValue())) {
return;
}
}
}
}
// No such package; add it
Element newParentElement = null;
for (Entry<String, String> element : elementValues.entrySet()) {
descriptionOfChange =
highlight(ADDED + " " + elementName + "/" + element.getKey()) + " '"
+ element.getValue() + "'";
if (elementValues.size() == 1 && element.getKey().equals(DEFAULT_VALUE_TEXT)) {
if (!isSamePom && addToPluginManagement) {
elementsElement.appendChild(XmlUtils.createTextElement(parentDocument,
elementName, element.getValue()));
fileManager.createOrUpdateTextFileIfRequired(parentPom.getPath(),
XmlUtils.nodeToString(parentDocument), descriptionOfChange, false);
} else {
elementsElement.appendChild(XmlUtils.createTextElement(document, elementName,
element.getValue()));
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(),
XmlUtils.nodeToString(document), descriptionOfChange, false);
}
} else {
if (!isSamePom && addToPluginManagement) {
if (newParentElement == null) {
newParentElement =
DomUtils.createChildIfNotExists(elementName, execution.getConfiguration()
.getConfiguration(), parentDocument);
elementsElement.appendChild(newParentElement);
}
newParentElement.appendChild(XmlUtils.createTextElement(parentDocument,
element.getKey(), element.getValue()));
fileManager.createOrUpdateTextFileIfRequired(parentPom.getPath(),
XmlUtils.nodeToString(parentDocument), descriptionOfChange, false);
} else {
if (newParentElement == null) {
newParentElement =
DomUtils.createChildIfNotExists(elementName, execution.getConfiguration()
.getConfiguration(), document);
elementsElement.appendChild(newParentElement);
}
newParentElement.appendChild(XmlUtils.createTextElement(document,
element.getKey(), element.getValue()));
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(),
XmlUtils.nodeToString(document), descriptionOfChange, false);
}
}
}
}
}
}
}
}
public void addModuleDependency(final String moduleToDependUpon) {
addModuleDependency(getFocusedModuleName(), moduleToDependUpon, false);
}
public void addModuleDependency(final String moduleName, final String moduleToDependUpon) {
addModuleDependency(moduleName, moduleToDependUpon, false);
}
public void addModuleDependency(final String moduleName, final String moduleToDependUpon,
boolean testDependency) {
Validate.isTrue(isProjectAvailable(moduleName),
"Dependency modification prohibited at this time");
Validate.notNull(moduleToDependUpon, "Dependency required");
if (StringUtils.isBlank(moduleToDependUpon)) {
return; // No need to ever add a dependency upon the root POM
}
final Pom module = getPomFromModuleName(moduleName);
if (module != null && StringUtils.isNotBlank(module.getModuleName())
&& !moduleToDependUpon.equals(module.getModuleName())) {
final ProjectMetadata dependencyProject = getProjectMetadata(moduleToDependUpon);
if (dependencyProject != null) {
final Pom dependencyPom = dependencyProject.getPom();
if (!dependencyPom.getPath().equals(module.getPath())) {
if (testDependency) {
// Add as test-type dependency
final Dependency dependency =
dependencyPom.asDependency(DependencyScope.TEST,
DependencyType.valueOfTypeCode("test-jar"));
detectCircularDependency(module, dependencyPom);
addDependency(module.getModuleName(), dependency);
} else {
// Add as "normal" dependency
final Dependency dependency = dependencyPom.asDependency(COMPILE);
if (!module.hasDependencyExcludingVersion(dependency)) {
detectCircularDependency(module, dependencyPom);
addDependency(module.getModuleName(), dependency);
}
}
}
}
}
}
public void addPluginRepositories(final String moduleName,
final Collection<? extends Repository> repositories) {
Validate.isTrue(isProjectAvailable(moduleName),
"Plugin repository modification prohibited at this time");
Validate.notNull(repositories, "Plugin repositories required");
addRepositories(moduleName, repositories, "pluginRepositories", "pluginRepository");
}
public void addPluginRepository(final String moduleName, final Repository repository) {
Validate.isTrue(isProjectAvailable(moduleName),
"Plugin repository modification prohibited at this time");
Validate.notNull(repository, "Repository required");
addRepository(moduleName, repository, "pluginRepositories", "pluginRepository");
}
public void addProperty(final String moduleName, final Property property) {
Validate
.isTrue(isProjectAvailable(moduleName), "Property modification prohibited at this time");
Validate.notNull(property, "Property to add required");
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so property addition cannot be performed");
if (pom.isPropertyRegistered(property)) {
return;
}
final Document document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
final Element root = document.getDocumentElement();
final String descriptionOfChange;
final Element existing =
XmlUtils.findFirstElement("/project/properties/" + property.getName(), root);
if (existing == null) {
// No existing property of this name; add it
final Element properties =
DomUtils.createChildIfNotExists("properties", document.getDocumentElement(), document);
properties.appendChild(XmlUtils.createTextElement(document, property.getName(),
property.getValue()));
descriptionOfChange =
highlight(ADDED + " property") + " '" + property.getName() + "' = '"
+ property.getValue() + "'";
} else {
// A property of this name exists; update it
existing.setTextContent(property.getValue());
descriptionOfChange =
highlight(UPDATED + " property") + " '" + property.getName() + "' to '"
+ property.getValue() + "'";
}
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
descriptionOfChange, false);
}
public void addRepositories(final String moduleName,
final Collection<? extends Repository> repositories) {
addRepositories(moduleName, repositories, "repositories", "repository");
}
private void addRepositories(final String moduleName,
final Collection<? extends Repository> repositories, final String containingPath,
final String path) {
Validate.isTrue(isProjectAvailable(moduleName),
"Repository modification prohibited at this time");
Validate.notNull(repositories, "Repositories required");
if (CollectionUtils.isEmpty(repositories)) {
return;
}
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so repository addition cannot be performed");
final Document document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
final Element repositoriesElement =
DomUtils.createChildIfNotExists(containingPath, document.getDocumentElement(), document);
if ("pluginRepository".equals(path)) {
if (pom.isAllPluginRepositoriesRegistered(repositories)) {
return;
}
} else if (pom.isAllRepositoriesRegistered(repositories)) {
return;
}
final List<Repository> existingRepositories = new ArrayList<Repository>();
for (Element exisitingRepElement : XmlUtils.findElements(path, repositoriesElement)) {
existingRepositories.add(new Repository(exisitingRepElement));
}
final List<String> addedRepositories = new ArrayList<String>();
for (final Repository repository : repositories) {
if ("pluginRepository".equals(path)) {
if (pom.isPluginRepositoryRegistered(repository)) {
continue;
} else if (existingRepositories.contains(repository)) {
continue;
}
} else {
if (pom.isRepositoryRegistered(repository)) {
continue;
} else if (existingRepositories.contains(repository)) {
continue;
}
}
if (repository != null) {
repositoriesElement.appendChild(repository.getElement(document, path));
addedRepositories.add(repository.getUrl());
}
}
final String message = getDescriptionOfChange(ADDED, addedRepositories, path, containingPath);
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
message, false);
}
public void addRepository(final String moduleName, final Repository repository) {
addRepository(moduleName, repository, "repositories", "repository");
}
private void addRepository(final String moduleName, final Repository repository,
final String containingPath, final String path) {
Validate.isTrue(isProjectAvailable(moduleName),
"Repository modification prohibited at this time");
Validate.notNull(repository, "Repository required");
addRepositories(moduleName, Collections.singletonList(repository), containingPath, path);
}
public void addResource(final String moduleName, final Resource resource) {
Validate
.isTrue(isProjectAvailable(moduleName), "Resource modification prohibited at this time");
Validate.notNull(resource, "Resource to add required");
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so resource addition cannot be performed");
if (pom.isResourceRegistered(resource)) {
return;
}
final Document document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
final Element buildElement =
XmlUtils.findFirstElement("/project/build", document.getDocumentElement());
final Element resourcesElement =
DomUtils.createChildIfNotExists("resources", buildElement, document);
resourcesElement.appendChild(resource.getElement(document));
final String descriptionOfChange =
highlight(ADDED + " resource") + " " + resource.getSimpleDescription();
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
descriptionOfChange, false);
}
protected void bindFeature(final Feature feature) {
if (feature != null) {
features.put(feature.getName(), feature);
}
}
private void detectCircularDependency(final Pom module, final Pom dependencyModule) {
if (hasModuleDependency(dependencyModule, module)) {
throw new IllegalStateException("ERROR: Circular dependency detected, '"
+ dependencyModule.getModuleName() + "' already depends on '" + module.getModuleName()
+ "'.");
}
}
private boolean hasModuleDependency(Pom module, Pom dependencyModule) {
if (module.isDependencyRegistered(dependencyModule.asDependency(COMPILE), false)) {
return true;
}
for (String moduleName : getModuleNames()) {
Pom relatedModule = getPomFromModuleName(moduleName);
if (module.isDependencyRegistered(relatedModule.asDependency(COMPILE), false)
&& hasModuleDependency(relatedModule, dependencyModule)) {
return true;
}
}
return false;
}
public Pom getFocusedModule() {
final ProjectMetadata focusedProjectMetadata = getFocusedProjectMetadata();
if (focusedProjectMetadata == null) {
return null;
}
return focusedProjectMetadata.getPom();
}
public String getFocusedModuleName() {
return pomManagementService.getFocusedModuleName();
}
public ProjectMetadata getFocusedProjectMetadata() {
return getProjectMetadata(getFocusedModuleName());
}
public String getFocusedProjectName() {
return getProjectName(getFocusedModuleName());
}
public JavaPackage getFocusedTopLevelPackage() {
return getTopLevelPackage(getFocusedModuleName());
}
public Pom getModuleForFileIdentifier(final String fileIdentifier) {
return pomManagementService.getModuleForFileIdentifier(fileIdentifier);
}
public Collection<String> getModuleNames() {
return pomManagementService.getModuleNames();
}
public PathResolver getPathResolver() {
return pathResolver;
}
public final Pom getPomFromModuleName(final String moduleName) {
final ProjectMetadata projectMetadata = getProjectMetadata(moduleName);
return projectMetadata == null ? null : projectMetadata.getPom();
}
public Collection<Pom> getPoms() {
return pomManagementService.getPoms();
}
private String getPomDependenciesUpdateMessage(final Collection<String> addedDependencies,
final Collection<String> removedDependencies, final Collection<String> skippedDependencies) {
final List<String> changes = new ArrayList<String>();
changes.add(getDescriptionOfChange(ADDED, addedDependencies, "dependency", "dependencies"));
changes.add(getDescriptionOfChange(REMOVED, removedDependencies, "dependency", "dependencies"));
changes.add(getDescriptionOfChange(SKIPPED, skippedDependencies, "dependency", "dependencies"));
for (final Iterator<String> iter = changes.iterator(); iter.hasNext();) {
if (StringUtils.isBlank(iter.next())) {
iter.remove();
}
}
return StringUtils.join(changes, "; ");
}
private String getPomPluginsUpdateMessage(final Collection<String> addedPlugins,
final Collection<String> removedPlugins) {
final List<String> changes = new ArrayList<String>();
changes.add(getDescriptionOfChange(ADDED, addedPlugins, "plugin", "plugins"));
changes.add(getDescriptionOfChange(REMOVED, removedPlugins, "plugin", "plugins"));
for (final Iterator<String> iter = changes.iterator(); iter.hasNext();) {
if (StringUtils.isBlank(iter.next())) {
iter.remove();
}
}
return StringUtils.join(changes, "; ");
}
public final ProjectMetadata getProjectMetadata(final String moduleName) {
return (ProjectMetadata) metadataService.get(ProjectMetadata.getProjectIdentifier(moduleName));
}
public String getProjectName(final String moduleName) {
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "A pom with module name '%s' could not be found", moduleName);
return pom.getDisplayName();
}
public JavaPackage getTopLevelPackage(final String moduleName) {
final Pom pom = getPomFromModuleName(moduleName);
if (pom != null) {
if (StringUtils.isBlank(moduleName)) {
return new JavaPackage(pom.getGroupId(), moduleName);
} else {
// Module package
return new JavaPackage(pom.getGroupId().concat(".")
.concat(pom.getArtifactId().replace("-", ".")), moduleName);
}
}
return null;
}
public boolean isFeatureInstalled(final String featureName) {
final Feature feature = features.get(featureName);
if (feature == null) {
return false;
}
for (final String moduleName : getModuleNames()) {
if (feature.isInstalledInModule(moduleName)) {
return true;
}
}
return false;
}
public boolean isFeatureInstalled(final String... featureNames) {
for (final String featureName : featureNames) {
if (isFeatureInstalled(featureName)) {
return true;
}
}
return false;
}
public boolean isFeatureInstalled(final Pom module, final String featureName) {
final Feature feature = features.get(featureName);
if (feature == null) {
return false;
}
if (feature.isInstalledInModule(module.getModuleName())) {
return true;
}
return false;
}
public boolean isFocusedProjectAvailable() {
return isProjectAvailable(getFocusedModuleName());
}
public boolean isModuleCreationAllowed() {
return isProjectAvailable("") && isModuleFocusAllowed();
}
public boolean isModuleFocusAllowed() {
return getModuleNames().size() > 1;
}
public boolean isMultimoduleProject() {
return isModuleFocusAllowed();
}
public final boolean isProjectAvailable(final String moduleName) {
return getProjectMetadata(moduleName) != null;
}
public void removeBuildPlugin(final String moduleName, final Plugin plugin) {
Validate.isTrue(isProjectAvailable(moduleName), "Plugin modification prohibited at this time");
Validate.notNull(plugin, "Plugin required");
removeBuildPlugins(moduleName, Collections.singletonList(plugin));
}
public void removeBuildPluginImmediately(final String moduleName, final Plugin plugin) {
Validate.isTrue(isProjectAvailable(moduleName), "Plugin modification prohibited at this time");
Validate.notNull(plugin, "Plugin required");
removeBuildPlugins(moduleName, Collections.singletonList(plugin), true);
}
public void removeBuildPlugins(final String moduleName, final Collection<? extends Plugin> plugins) {
removeBuildPlugins(moduleName, plugins, false);
}
private void removeBuildPlugins(final String moduleName,
final Collection<? extends Plugin> plugins, final boolean writeImmediately) {
Validate.isTrue(isProjectAvailable(moduleName), "Plugin modification prohibited at this time");
Validate.notNull(plugins, "Plugins required");
if (CollectionUtils.isEmpty(plugins)) {
return;
}
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so plugin removal cannot be performed");
if (!pom.isAnyPluginsRegistered(plugins)) {
return;
}
final Document document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
final Element root = document.getDocumentElement();
final Element pluginsElement = XmlUtils.findFirstElement("/project/build/plugins", root);
if (pluginsElement == null) {
return;
}
final List<String> removedPlugins = new ArrayList<String>();
for (final Plugin plugin : plugins) {
// Can't filter the XPath on groupId, as it's optional in the POM
// for Apache-owned plugins
for (final Element candidate : XmlUtils.findElements(
"plugin[artifactId = '" + plugin.getArtifactId() + "' and version = '"
+ plugin.getVersion() + "']", pluginsElement)) {
final Plugin candidatePlugin = new Plugin(candidate);
if (candidatePlugin.getGroupId().equals(plugin.getGroupId())) {
// This element has the same groupId, artifactId, and
// version as the plugin to be removed; remove it
pluginsElement.removeChild(candidate);
removedPlugins.add(candidatePlugin.getSimpleDescription());
// Keep looping in case this plugin is in the POM more than
// once (unlikely)
}
}
}
if (removedPlugins.isEmpty()) {
return;
}
DomUtils.removeTextNodes(pluginsElement);
final String message = getDescriptionOfChange(REMOVED, removedPlugins, "plugin", "plugins");
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
message, writeImmediately);
}
public void removeDependencies(final String moduleName,
final Collection<? extends Dependency> dependenciesToRemove) {
Validate.isTrue(isProjectAvailable(moduleName),
"Dependency modification prohibited at this time");
Validate.notNull(dependenciesToRemove, "Dependencies required");
if (CollectionUtils.isEmpty(dependenciesToRemove)) {
return;
}
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so dependency removal cannot be performed");
if (!pom.isAnyDependenciesRegistered(dependenciesToRemove)) {
return;
}
final Document document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
final Element root = document.getDocumentElement();
final Element dependenciesElement = XmlUtils.findFirstElement("/project/dependencies", root);
if (dependenciesElement == null) {
return;
}
final List<Element> existingDependencyElements =
XmlUtils.findElements("dependency", dependenciesElement);
final List<String> removedDependencies = new ArrayList<String>();
for (final Dependency dependencyToRemove : dependenciesToRemove) {
if (pom.isDependencyRegistered(dependencyToRemove, false)) {
for (final Iterator<Element> iter = existingDependencyElements.iterator(); iter.hasNext();) {
final Element candidate = iter.next();
final Dependency candidateDependency = new Dependency(candidate);
if (candidateDependency.equals(dependencyToRemove)) {
// It's the same dependency; remove it
dependenciesElement.removeChild(candidate);
// Ensure we don't try to remove it again for another
// Dependency
iter.remove();
removedDependencies.add(candidateDependency.getSimpleDescription());
}
// Keep looping in case it's in the POM more than once
}
}
}
if (removedDependencies.isEmpty()) {
return;
}
DomUtils.removeTextNodes(dependenciesElement);
final String message =
getDescriptionOfChange(REMOVED, removedDependencies, "dependency", "dependencies");
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
message, false);
}
public void removeDependency(final String moduleName, final Dependency dependency) {
removeDependency(moduleName, dependency, "/project/dependencies",
"/project/dependencies/dependency");
}
/**
* Removes an element identified by the given dependency, whenever it occurs
* at the given path
*
* @param moduleName the name of the module to remove the dependency from
* @param dependency the dependency to remove
* @param containingPath the path to the dependencies element
* @param path the path to the individual dependency elements
*/
private void removeDependency(final String moduleName, final Dependency dependency,
final String containingPath, final String path) {
Validate.isTrue(isProjectAvailable(moduleName),
"Dependency modification prohibited at this time");
Validate.notNull(dependency, "Dependency to remove required");
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so dependency removal cannot be performed");
if (!pom.isDependencyRegistered(dependency, false)) {
return;
}
final Document document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
final Element root = document.getDocumentElement();
String descriptionOfChange = "";
final Element dependenciesElement = XmlUtils.findFirstElement(containingPath, root);
for (final Element candidate : XmlUtils.findElements(path, root)) {
if (dependency.equals(new Dependency(candidate))) {
dependenciesElement.removeChild(candidate);
descriptionOfChange =
highlight(REMOVED + " dependency") + " " + dependency.getSimpleDescription();
// Stay in the loop, just in case it was in the POM more than
// once
}
}
DomUtils.removeTextNodes(dependenciesElement);
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
descriptionOfChange, false);
}
public final void removeDependency(final String moduleName, final String groupId,
final String artifactId, final String version) {
removeDependency(moduleName, groupId, artifactId, version, "");
}
public final void removeDependency(final String moduleName, final String groupId,
final String artifactId, final String version, final String classifier) {
Validate.isTrue(isProjectAvailable(moduleName),
"Dependency modification prohibited at this time");
Validate.notNull(groupId, "Group ID required");
Validate.notNull(artifactId, "Artifact ID required");
Validate.notBlank(version, "Version required");
final Dependency dependency =
new Dependency(groupId, artifactId, version, DependencyType.JAR, COMPILE, classifier);
removeDependency(moduleName, dependency);
}
/**
* Method that removes version from element if blank or "-"
*
* @param element
* @return Element without version if blank
*/
private Element removeVersionIfBlank(Element element) {
NodeList elementAttributes = element.getChildNodes();
for (int i = 0; i < elementAttributes.getLength(); i++) {
Element elementAttribute = (Element) elementAttributes.item(i);
if (elementAttribute != null
&& elementAttribute.getTagName().equals("version")
&& (elementAttribute.getTextContent() == null
|| "-".equals(elementAttribute.getTextContent()) || "".equals(elementAttribute
.getTextContent()))) {
element.removeChild(elementAttributes.item(i));
break;
}
}
return element;
}
/**
* Method that removes version from element if blank or "-"
*
* @param element
* @return Element without version if blank
*/
private Element removeAllItems(Element element) {
element = removeManagementConfiguration(element);
NodeList elementAttributes = element.getChildNodes();
List<Node> elementsToRemove = new ArrayList<Node>();
for (int i = 0; i < elementAttributes.getLength(); i++) {
Element elementAttribute = (Element) elementAttributes.item(i);
if (elementAttribute != null && elementAttribute.getTagName().equals("executions")) {
elementsToRemove.add(elementAttributes.item(i));
}
if (elementAttribute != null && elementAttribute.getTagName().equals("configuration")) {
elementsToRemove.add(elementAttributes.item(i));
}
if (elementAttribute != null && elementAttribute.getTagName().equals("dependencies")) {
elementsToRemove.add(elementAttributes.item(i));
}
}
for (Node child : elementsToRemove) {
element.removeChild(child);
}
return element;
}
/**
* Method that removes version, scope and exclusions from provided element.
*
* @param element
* @return Element without version, scope nor exclusions
*/
private Element removeManagementConfiguration(Element element) {
NodeList elementAttributes = element.getChildNodes();
List<Node> elementsToRemove = new ArrayList<Node>();
for (int i = 0; i < elementAttributes.getLength(); i++) {
Element elementAttribute = (Element) elementAttributes.item(i);
if (elementAttribute != null && elementAttribute.getTagName().equals("version")) {
elementsToRemove.add(elementAttributes.item(i));
}
if (elementAttribute != null && elementAttribute.getTagName().equals("scope")) {
elementsToRemove.add(elementAttributes.item(i));
}
if (elementAttribute != null && elementAttribute.getTagName().equals("exclusions")) {
elementsToRemove.add(elementAttributes.item(i));
}
}
for (Node child : elementsToRemove) {
element.removeChild(child);
}
return element;
}
public void removeFilter(final String moduleName, final Filter filter) {
Validate.isTrue(isProjectAvailable(moduleName), "Filter modification prohibited at this time");
Validate.notNull(filter, "Filter required");
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so filter removal cannot be performed");
if (filter == null || !pom.isFilterRegistered(filter)) {
return;
}
final Document document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
final Element root = document.getDocumentElement();
final Element filtersElement = XmlUtils.findFirstElement("/project/build/filters", root);
if (filtersElement == null) {
return;
}
String descriptionOfChange = "";
for (final Element candidate : XmlUtils.findElements("filter", filtersElement)) {
if (filter.equals(new Filter(candidate))) {
filtersElement.removeChild(candidate);
descriptionOfChange = highlight(REMOVED + " filter") + " '" + filter.getValue() + "'";
// We will not break the loop (even though we could
// theoretically), just in case it was in the POM more than once
}
}
final List<Element> filterElements = XmlUtils.findElements("filter", filtersElement);
if (filterElements.isEmpty()) {
filtersElement.getParentNode().removeChild(filtersElement);
}
DomUtils.removeTextNodes(root);
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
descriptionOfChange, false);
}
public void removePluginRepository(final String moduleName, final Repository repository) {
Validate.isTrue(isProjectAvailable(moduleName),
"Plugin repository modification prohibited at this time");
Validate.notNull(repository, "Repository required");
removeRepository(moduleName, repository, "/project/pluginRepositories/pluginRepository");
}
public void removeProperty(final String moduleName, final Property property) {
Validate
.isTrue(isProjectAvailable(moduleName), "Property modification prohibited at this time");
Validate.notNull(property, "Property to remove required");
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so property removal cannot be performed");
if (!pom.isPropertyRegistered(property)) {
return;
}
final Document document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
final Element root = document.getDocumentElement();
final Element propertiesElement = XmlUtils.findFirstElement("/project/properties", root);
String descriptionOfChange = "";
for (final Element candidate : XmlUtils.findElements("/project/properties/*",
document.getDocumentElement())) {
if (property.equals(new Property(candidate))) {
propertiesElement.removeChild(candidate);
descriptionOfChange = highlight(REMOVED + " property") + " " + property.getName();
// Stay in the loop just in case it was in the POM more than
// once
}
}
DomUtils.removeTextNodes(propertiesElement);
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
descriptionOfChange, false);
}
public void removeRepository(final String moduleName, final Repository repository) {
removeRepository(moduleName, repository, "/project/repositories/repository");
}
private void removeRepository(final String moduleName, final Repository repository,
final String path) {
Validate.isTrue(isProjectAvailable(moduleName),
"Repository modification prohibited at this time");
Validate.notNull(repository, "Repository required");
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so repository removal cannot be performed");
if ("pluginRepository".equals(path)) {
if (!pom.isPluginRepositoryRegistered(repository)) {
return;
}
} else {
if (!pom.isRepositoryRegistered(repository)) {
return;
}
}
final Document document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
final Element root = document.getDocumentElement();
String descriptionOfChange = "";
for (final Element candidate : XmlUtils.findElements(path, root)) {
if (repository.equals(new Repository(candidate))) {
candidate.getParentNode().removeChild(candidate);
descriptionOfChange = highlight(REMOVED + " repository") + " " + repository.getUrl();
// We stay in the loop just in case it was in the POM more than
// once
}
}
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
descriptionOfChange, false);
}
public void removeResource(final String moduleName, final Resource resource) {
Validate
.isTrue(isProjectAvailable(moduleName), "Resource modification prohibited at this time");
Validate.notNull(resource, "Resource required");
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so resource removal cannot be performed");
if (!pom.isResourceRegistered(resource)) {
return;
}
final Document document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
final Element root = document.getDocumentElement();
final Element resourcesElement = XmlUtils.findFirstElement("/project/build/resources", root);
if (resourcesElement == null) {
return;
}
String descriptionOfChange = "";
for (final Element candidate : XmlUtils.findElements(
"resource[directory = '" + resource.getDirectory() + "']", resourcesElement)) {
if (resource.equals(new Resource(candidate))) {
resourcesElement.removeChild(candidate);
descriptionOfChange =
highlight(REMOVED + " resource") + " " + resource.getSimpleDescription();
// Stay in the loop just in case it was in the POM more than
// once
}
}
final List<Element> resourceElements = XmlUtils.findElements("resource", resourcesElement);
if (resourceElements.isEmpty()) {
resourcesElement.getParentNode().removeChild(resourcesElement);
}
DomUtils.removeTextNodes(root);
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
descriptionOfChange, false);
}
public void setModule(final Pom module) {
// Update window title with project name
shell.flash(Level.FINE, "Spring Roo: " + getTopLevelPackage(module.getModuleName()),
Shell.WINDOW_TITLE_SLOT);
pomManagementService.setFocusedModule(module);
}
protected void unbindFeature(final Feature feature) {
if (feature != null) {
features.remove(feature.getName());
}
}
public void updateBuildPlugin(final String moduleName, final Plugin plugin) {
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so plugins cannot be modified at this time");
Validate.notNull(plugin, "Plugin required");
for (final Plugin existingPlugin : pom.getBuildPlugins()) {
if (existingPlugin.equals(plugin)) {
// Already exists, so just quit
return;
}
}
// Delete any existing plugin with a different version
removeBuildPlugin(moduleName, plugin);
// Add the plugin
addBuildPlugin(moduleName, plugin);
}
public void updateDependencyScope(final String moduleName, final Dependency dependency,
final DependencyScope dependencyScope) {
Validate.isTrue(isProjectAvailable(moduleName),
"Dependency modification prohibited at this time");
Validate.notNull(dependency, "Dependency to update required");
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so updating a dependency cannot be performed");
if (!pom.isDependencyRegistered(dependency, false)) {
return;
}
final Document document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
final Element root = document.getDocumentElement();
final Element dependencyElement =
XmlUtils.findFirstElement(
"/project/dependencies/dependency[groupId = '" + dependency.getGroupId()
+ "' and artifactId = '" + dependency.getArtifactId() + "' and version = '"
+ dependency.getVersion() + "']", root);
if (dependencyElement == null) {
return;
}
final Element scopeElement = XmlUtils.findFirstElement("scope", dependencyElement);
final String descriptionOfChange;
if (scopeElement == null) {
if (dependencyScope != null) {
dependencyElement.appendChild(new XmlElementBuilder("scope", document).setText(
dependencyScope.name().toLowerCase()).build());
descriptionOfChange =
highlight(ADDED + " scope") + " " + dependencyScope.name().toLowerCase()
+ " to dependency " + dependency.getSimpleDescription();
} else {
descriptionOfChange = null;
}
} else {
if (dependencyScope != null) {
scopeElement.setTextContent(dependencyScope.name().toLowerCase());
descriptionOfChange =
highlight(CHANGED + " scope") + " to " + dependencyScope.name().toLowerCase()
+ " in dependency " + dependency.getSimpleDescription();
} else {
dependencyElement.removeChild(scopeElement);
descriptionOfChange =
highlight(REMOVED + " scope") + " from dependency " + dependency.getSimpleDescription();
}
}
if (descriptionOfChange != null) {
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
descriptionOfChange, false);
}
}
public void updateProjectType(final String moduleName, final ProjectType projectType) {
Validate.notNull(projectType, "Project type required");
final Pom pom = getPomFromModuleName(moduleName);
Validate.notNull(pom, "The pom is not available, so the project type cannot be changed");
final Document document = XmlUtils.readXml(fileManager.getInputStream(pom.getPath()));
final Element packaging =
DomUtils.createChildIfNotExists("packaging", document.getDocumentElement(), document);
if (packaging.getTextContent().equals(projectType.getType())) {
return;
}
packaging.setTextContent(projectType.getType());
final String descriptionOfChange =
highlight(UPDATED + " project type") + " to " + projectType.getType();
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
descriptionOfChange, false);
}
/**
* Write the dependencies provided in specified pom, as children of the provided
* Element (usually 'dependencies' or 'dependencyManagement').
*
* @param newDependencies the collection of Dependency to be added.
* @param parentPom the parent module which the dependencies should be added.
* @param pom the module which the dependencies should be added.
* @param parentDocument the parent Document to act upon.
* @param document the Document to act upon.
* @param parentElement the element where append the collection of dependencies as
* children.
* @param element the element where append the collection of dependencies as
* children.
* @param addToDependencyManagement boolean that indicates if is necessary to include
* the dependency in dependencyManagement section
* @param isSamePom boolean that indicates if parentPom and pom is the same
* @param checkFullDependency whether should check the existence with full
* dependency element or only compare 'artifactId' and 'groupId'.
* @return the list of added dependencies.
*/
private List<Dependency> writeDependencyInPom(
final Collection<? extends Dependency> newDependencies, final Pom parentPom, final Pom pom,
final Document parentDocument, final Document document, final Element parentElement,
final Element element, final boolean addToDependencyManagement, final boolean isSamePom,
final boolean checkFullDependency) {
final List<Dependency> finalDependencies = new ArrayList<Dependency>();
final List<String> addedDependencies = new ArrayList<String>();
final List<String> removedDependencies = new ArrayList<String>();
final List<String> skippedDependencies = new ArrayList<String>();
if (addToDependencyManagement) {
// Include dependency in dependencyManagement element if needed
final Element dependencyManagementElement =
DomUtils.createChildIfNotExists("dependencyManagement/dependencies", parentElement,
parentDocument);
final List<Element> existingDependencyManagementElements =
XmlUtils.findElements("dependency", dependencyManagementElement);
for (final Dependency newDependency : newDependencies) {
// First, check if this dependency has version. If not, is not possible
// to include it on dependencyManagement element
if (StringUtils.isEmpty(newDependency.getVersion())) {
continue;
}
// ROO-3465: Prevent version changes adding checkVersion to false
// when check if is possible to add the new dependency
if (!parentPom.canAddDependencyToDependencyManagement(newDependency, checkFullDependency)) {
continue;
}
boolean inserted = false;
// Look for any existing instances of this dependency
for (final Element existingDependencyElement : existingDependencyManagementElements) {
final Dependency existingDependency = new Dependency(existingDependencyElement);
if (existingDependency.hasSameCoordinates(newDependency)) {
inserted = true;
break;
}
}
if (!inserted) {
// We didn't encounter any existing dependencies with the
// same coordinates; add it now
Element newDependencyElement =
removeVersionIfBlank(newDependency.getElement(parentDocument));
dependencyManagementElement.appendChild(newDependencyElement);
finalDependencies.add(newDependency);
addedDependencies.add(newDependency.getSimpleDescription());
}
}
}
// Include dependency to pom file
final Element dependenciesElement =
DomUtils.createChildIfNotExists("dependencies", element, document);
final List<Element> existingDependencyElements =
XmlUtils.findElements("dependency", dependenciesElement);
for (final Dependency newDependency : newDependencies) {
// ROO-3465: Prevent version changes adding checkVersion to false
// when check if is possible to add the new dependency
if (pom.canAddDependency(newDependency, checkFullDependency)) {
// Look for any existing instances of this dependency
boolean inserted = false;
for (final Element existingDependencyElement : existingDependencyElements) {
final Dependency existingDependency = new Dependency(existingDependencyElement);
if (existingDependency.hasSameCoordinates(newDependency)) {
// It's the same artifact, but might have a different
// version, exclusions, etc.
if (!inserted) {
// We haven't added the new one yet; do so now
// ROO-3685: Check if current dependency has version when is added again
Element newDependencyElement = null;
if (addToDependencyManagement && !StringUtils.isEmpty(newDependency.getVersion())) {
// If this dependency has been added to dependencyManagement, is not necessary
// to include version, scope or exclusions
newDependencyElement =
removeManagementConfiguration(newDependency.getElement(document));
} else {
// If this dependency has not been added to dependencyManagement, is necessary
// to include version, only if it's not blank or null.
newDependencyElement = removeVersionIfBlank(newDependency.getElement(document));
}
dependenciesElement.insertBefore(newDependencyElement, existingDependencyElement);
inserted = true;
Dependency newDependencyWithoutVersion = new Dependency(newDependencyElement);
if (!newDependencyWithoutVersion.getVersion().equals(existingDependency.getVersion())) {
// It's a genuine version change => mention the
// old and new versions in the message
finalDependencies.add(newDependency);
addedDependencies.add(newDependency.getSimpleDescription());
removedDependencies.add(existingDependency.getSimpleDescription());
}
}
// Either way, we remove the previous one in case it was
// different in any way
dependenciesElement.removeChild(existingDependencyElement);
}
// Keep looping in case it's present more than once
}
if (!inserted) {
// We didn't encounter any existing dependencies with the
// same coordinates; add it now
// ROO-3660: Check if current dependency has version. If
// not, remove version attribute
Element newDependencyElement = null;
if (addToDependencyManagement && !StringUtils.isEmpty(newDependency.getVersion())) {
// If this dependency has been added to dependencyManagement, is not necessary
// to include version, scope or exclusions
newDependencyElement =
removeManagementConfiguration(newDependency.getElement(document));
} else {
// If this dependency has not been added to dependencyManagement, is necessary
// to include version, only if it's not blank or null.
newDependencyElement = removeVersionIfBlank(newDependency.getElement(document));
}
dependenciesElement.appendChild(newDependencyElement);
finalDependencies.add(newDependency);
addedDependencies.add(newDependency.getSimpleDescription());
}
} else {
skippedDependencies.add(newDependency.getSimpleDescription());
finalDependencies.add(newDependency);
}
}
if (!newDependencies.isEmpty() || !skippedDependencies.isEmpty()) {
final String message =
getPomDependenciesUpdateMessage(addedDependencies, removedDependencies,
skippedDependencies);
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
message, false);
// If parent pom is different, is necessary to add dependencies to dependencyManagement
if (!isSamePom && addToDependencyManagement) {
fileManager.createOrUpdateTextFileIfRequired(parentPom.getPath(),
XmlUtils.nodeToString(parentDocument), message, false);
}
}
return finalDependencies;
}
/**
* Write the provided plugins in specified pom, as children of the provided
* Element (usually 'dependencies' or 'dependencyManagement').
*
* @param newPlugins the collection of Plugin to be added.
* @param parentPom the parent pom which the plugins should be added to pluginManagement.
* @param pom the pom which the plugins should be added.
* @param parentDocument the parent Document to act upon.
* @param document the Document to act upon.
* @param parentElement the element where append the collection of plugins on parentPom.
* @param element the element where append the collection of plugins as children.
* @param addToPluginManagement boolean that indicates if plugin should be added to pluginManagement
* section.
* @param isSamePom boolean that indicates if parentPom and pom is the same
*/
private void writePluginInPom(final Collection<? extends Plugin> newPlugins, final Pom parentPom,
final Pom pom, final Document parentDocument, final Document document,
final Element parentElement, final Element element, boolean addToPluginManagement,
boolean isSamePom) {
final List<String> addedPlugins = new ArrayList<String>();
final List<String> removedPlugins = new ArrayList<String>();
if (addToPluginManagement) {
// Include dependency in pluginManagement element if needed
final Element pluginManagementElement =
DomUtils.createChildIfNotExists("build/pluginManagement/plugins", parentElement,
parentDocument);
final List<Element> existingPluginManagementElements =
XmlUtils.findElements("plugin", pluginManagementElement);
for (final Plugin newPlugin : newPlugins) {
// First, check if this plugin has version. If not, is not possible
// to include it on pluginManagement element
if (StringUtils.isEmpty(newPlugin.getVersion())) {
continue;
}
// ROO-3465: Prevent version changes adding checkVersion to false
// when check if is possible to add the new plugin
if (!parentPom.canAddPluginToPluginManagement(newPlugin, false)) {
continue;
}
boolean inserted = false;
// Look for any existing instances of this plugin
for (final Element existingPluginElement : existingPluginManagementElements) {
final Plugin existingPlugin = new Plugin(existingPluginElement);
if (existingPlugin.hasSameCoordinates(newPlugin)) {
inserted = true;
break;
}
}
if (!inserted) {
// We didn't encounter any existing plugins with the
// same coordinates; add it now
Element newPluginElement = removeVersionIfBlank(newPlugin.getElement(parentDocument));
pluginManagementElement.appendChild(newPluginElement);
addedPlugins.add(newPlugin.getSimpleDescription());
}
}
}
// Include plugin to pom file
final Element root = document.getDocumentElement();
final Element pluginsElement = DomUtils.createChildIfNotExists("build/plugins", root, document);
final List<Element> existingPluginElements = XmlUtils.findElements("plugin", pluginsElement);
for (final Plugin newPlugin : newPlugins) {
if (newPlugin != null) {
// Look for any existing instances of this plugin
boolean inserted = false;
for (final Element existingPluginElement : existingPluginElements) {
final Plugin existingPlugin = new Plugin(existingPluginElement);
if (existingPlugin.hasSameCoordinates(newPlugin)) {
// It's the same artifact, but might have a different
// version, exclusions, etc.
if (!inserted) {
Element newPluginElement = null;
if (addToPluginManagement && !StringUtils.isEmpty(newPlugin.getVersion())) {
// If this dependency has been added to pluginManagement, is not necessary
// to include version
newPluginElement = removeAllItems(newPlugin.getElement(document));
} else {
// If this dependency has not been added to pluginManagement, is necessary
// to include version, only if it's not blank or null.
newPluginElement = removeVersionIfBlank(newPlugin.getElement(document));
}
// We haven't added the new one yet; do so now
pluginsElement.insertBefore(newPluginElement, existingPluginElement);
inserted = true;
if (!newPlugin.getVersion().equals(existingPlugin.getVersion())) {
// It's a genuine version change => mention the
// old and new versions in the message
addedPlugins.add(newPlugin.getSimpleDescription());
removedPlugins.add(existingPlugin.getSimpleDescription());
}
}
// Either way, we remove the previous one in case it was
// different in any way
pluginsElement.removeChild(existingPluginElement);
}
// Keep looping in case it's present more than once
}
if (!inserted) {
// We didn't encounter any existing plugins with the
// same coordinates; add it now
Element newPluginElement = null;
if (addToPluginManagement && !StringUtils.isEmpty(newPlugin.getVersion())) {
// If this dependency has been added to pluginManagement, is not necessary
// to include version
newPluginElement = removeAllItems(newPlugin.getElement(document));
} else {
// If this dependency has not been added to pluginManagement, is necessary
// to include version, only if it's not blank or null.
newPluginElement = removeVersionIfBlank(newPlugin.getElement(document));
}
pluginsElement.appendChild(newPluginElement);
addedPlugins.add(newPlugin.getSimpleDescription());
}
}
}
if (!newPlugins.isEmpty()) {
final String message = getPomPluginsUpdateMessage(addedPlugins, removedPlugins);
fileManager.createOrUpdateTextFileIfRequired(pom.getPath(), XmlUtils.nodeToString(document),
message, false);
// If parent pom is different, is necessary to add plugins to pluginManagement
if (!isSamePom && addToPluginManagement) {
fileManager.createOrUpdateTextFileIfRequired(parentPom.getPath(),
XmlUtils.nodeToString(parentDocument), message, false);
}
}
}
}