Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -20,66 +20,40 @@

import javax.xml.XMLConstants;

import java.io.File;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Properties;
import java.util.Set;

import org.apache.maven.project.ProjectBuilder;
import org.codehaus.plexus.util.xml.XMLWriter;
import org.codehaus.plexus.util.xml.XmlWriterUtil;
import org.eclipse.aether.RepositorySystem;
import org.jdom2.Document;
import org.jdom2.JDOMException;
import org.jdom2.input.SAXBuilder;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;

/**
* Base class with common utilities to write effective Pom/settings.
* Utility class with common utilities to write effective Pom/settings.
*
* @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
* @since 2.1
*/
public abstract class AbstractEffectiveMojo extends AbstractHelpMojo {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can't remove existing public API. You need to deprecate this instead.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this an agreement on all ASF repo's? I thought this was mainly for maven-core API's.

I don't know, but do ASF-plugins support extensions of plugin public API's, do people do this? A quick search on GitHub on this class only seems to result in forks.

Alternatively I can e.g. deprecate it and change the implementation to point to the new class.
When will it be removed, and does this require a new ticket?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Commit 042a98f could be reverted if it's decided to change it. Otherwise, the commit should revert the breaking change.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do ASF-plugins support extensions of plugin public API's, do people do this? A quick search on GitHub on this class only seems to result in forks.

My opinion is similar. This plugin is not library, and its API are goals and their parameters. I would not consider such change to require deprecation.

This class being public does not make it public API.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

exactly - plugin is not library

public final class EffectiveMojoUtils {

protected AbstractEffectiveMojo(ProjectBuilder projectBuilder, RepositorySystem repositorySystem) {
super(projectBuilder, repositorySystem);
}

/**
* Utility method to write an XML content to a given file.
*
* @param output is the wanted output file.
* @param content contains the XML content to be written to the file.
* @throws IOException if any
* @see AbstractHelpMojo#writeFile(File, String) if encoding is null.
*/
protected static void writeXmlFile(File output, String content) throws IOException {
if (output == null) {
return;
}

output.getParentFile().mkdirs();
try (Writer out = Files.newBufferedWriter(output.toPath())) {
out.write(content);
}
}
private EffectiveMojoUtils() {}

/**
* Write comments in the Effective POM/settings header.
*
* @param writer not null
*/
protected static void writeHeader(XMLWriter writer) {
public static void writeHeader(XMLWriter writer) {
XmlWriterUtil.writeCommentLineBreak(writer);
XmlWriterUtil.writeComment(writer, " ");
XmlWriterUtil.writeComment(writer, "Generated by Maven Help Plugin");
Expand All @@ -91,10 +65,10 @@ protected static void writeHeader(XMLWriter writer) {
/**
* Write comments in a normalize way.
*
* @param writer not null
* @param writer not null
* @param comment not null
*/
protected static void writeComment(XMLWriter writer, String comment) {
public static void writeComment(XMLWriter writer, String comment) {
XmlWriterUtil.writeCommentLineBreak(writer);
XmlWriterUtil.writeComment(writer, " ");
XmlWriterUtil.writeComment(writer, comment);
Expand All @@ -103,12 +77,12 @@ protected static void writeComment(XMLWriter writer, String comment) {
}

/**
* @param effectiveModel not null
* @param encoding not null
* @param effectiveModel not null
* @param encoding not null
* @param omitDeclaration whether the XML declaration should be omitted from the effective pom
* @return pretty format of the xml or the original {@code effectiveModel} if an error occurred.
*/
protected static String prettyFormat(String effectiveModel, String encoding, boolean omitDeclaration) {
public static String prettyFormat(String effectiveModel, String encoding, boolean omitDeclaration) {
SAXBuilder builder = new SAXBuilder();
builder.setProperty(XMLConstants.ACCESS_EXTERNAL_DTD, "");
builder.setProperty(XMLConstants.ACCESS_EXTERNAL_SCHEMA, "");
Expand All @@ -132,14 +106,26 @@ protected static String prettyFormat(String effectiveModel, String encoding, boo
}
}

public static Properties sortProperties(Properties properties) {
Properties sortedProperties = new SortedProperties();
for (Object key : properties.keySet()) {
sortedProperties.put(key, properties.get(key));
}
return sortedProperties;
}

/**
* Properties which provides a sorted keySet().
*/
protected static class SortedProperties extends Properties {
/** serialVersionUID */
private static class SortedProperties extends Properties {
/**
* serialVersionUID
*/
static final long serialVersionUID = -8985316072702233744L;

/** {@inheritDoc} */
/**
* {@inheritDoc}
*/
@SuppressWarnings({"rawtypes", "unchecked"})
@Override
public Set<Object> keySet() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,14 +45,19 @@
import org.codehaus.plexus.util.xml.XmlWriterUtil;
import org.eclipse.aether.RepositorySystem;

import static org.apache.maven.plugins.help.EffectiveMojoUtils.prettyFormat;
import static org.apache.maven.plugins.help.EffectiveMojoUtils.sortProperties;
import static org.apache.maven.plugins.help.EffectiveMojoUtils.writeComment;
import static org.apache.maven.plugins.help.EffectiveMojoUtils.writeHeader;

/**
* Displays the effective POM as an XML for this build, with the active profiles factored in, or a specified artifact.
* If <code>verbose</code>, a comment is added to each XML element describing the origin of the line.
*
* @since 2.0
*/
@Mojo(name = "effective-pom", aggregator = true)
public class EffectivePomMojo extends AbstractEffectiveMojo {
public class EffectivePomMojo extends AbstractHelpMojo {
// ----------------------------------------------------------------------
// Mojo parameters
// ----------------------------------------------------------------------
Expand Down Expand Up @@ -132,7 +137,7 @@ public void execute() throws MojoExecutionException {

if (output != null) {
try {
writeXmlFile(output, effectivePom);
writeFile(output, effectivePom);
} catch (IOException e) {
throw new MojoExecutionException("Cannot write effective-POM to output: " + output, e);
}
Expand Down Expand Up @@ -208,9 +213,8 @@ private void writeEffectivePom(MavenProject project, XMLWriter writer) throws Mo
* @param pom not null
*/
private static void cleanModel(Model pom) {
Properties properties = new SortedProperties();
properties.putAll(pom.getProperties());
pom.setProperties(properties);
Properties sortedProperties = sortProperties(pom.getProperties());
pom.setProperties(sortedProperties);
}

private static class InputLocationStringFormatter extends InputLocation.StringFormatter {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,19 @@
import org.codehaus.plexus.util.xml.XmlWriterUtil;
import org.eclipse.aether.RepositorySystem;

import static org.apache.maven.plugins.help.EffectiveMojoUtils.prettyFormat;
import static org.apache.maven.plugins.help.EffectiveMojoUtils.sortProperties;
import static org.apache.maven.plugins.help.EffectiveMojoUtils.writeComment;
import static org.apache.maven.plugins.help.EffectiveMojoUtils.writeHeader;

/**
* Displays the calculated settings as XML for this project, given any profile enhancement and the inheritance
* of the global settings into the user-level settings.
*
* @since 2.0
*/
@Mojo(name = "effective-settings", requiresProject = false)
public class EffectiveSettingsMojo extends AbstractEffectiveMojo {
public class EffectiveSettingsMojo extends AbstractHelpMojo {
// ----------------------------------------------------------------------
// Mojo parameters
// ----------------------------------------------------------------------
Expand Down Expand Up @@ -108,7 +113,7 @@ public void execute() throws MojoExecutionException {

if (output != null) {
try {
writeXmlFile(output, effectiveSettings);
writeFile(output, effectiveSettings);
} catch (IOException e) {
throw new MojoExecutionException("Cannot write effective-settings to output: " + output, e);
}
Expand Down Expand Up @@ -232,8 +237,7 @@ private static void writeEffectiveSettings(Settings settings, XMLWriter writer)
private static void cleanSettings(Settings settings) {
List<Profile> profiles = settings.getProfiles();
for (Profile profile : profiles) {
Properties properties = new SortedProperties();
properties.putAll(profile.getProperties());
Properties properties = sortProperties(profile.getProperties());
profile.setProperties(properties);
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.plugins.help;

import java.io.StringWriter;
import java.nio.charset.Charset;
import java.util.Properties;

import org.codehaus.plexus.util.StringUtils;
import org.codehaus.plexus.util.xml.PrettyPrintXMLWriter;
import org.codehaus.plexus.util.xml.XMLWriter;
import org.codehaus.plexus.util.xml.XmlWriterUtil;
import org.junit.jupiter.api.Test;

import static java.lang.String.format;
import static org.junit.jupiter.api.Assertions.assertEquals;

class EffectiveMojoUtilsTest {

private final StringWriter w = new StringWriter();
private final String encoding = Charset.defaultCharset().displayName();
private final XMLWriter writer = new PrettyPrintXMLWriter(
w, StringUtils.repeat(" ", XmlWriterUtil.DEFAULT_INDENTATION_SIZE), encoding, null);

@Test
void writeHeaderShouldWriteHeaderComments() {
EffectiveMojoUtils.writeHeader(writer);

assertEquals(
format("<?xml version=\"1.0\" encoding=\"%s\"?>%n", encoding)
+ format("<!-- ====================================================================== -->%n")
+ format("<!-- -->%n")
+ format("<!-- Generated by Maven Help Plugin -->%n")
+ format("<!-- See: https://maven.apache.org/plugins/maven-help-plugin/ -->%n")
+ format("<!-- -->%n")
+ format("<!-- ====================================================================== -->%n"),
w.toString());
}

@Test
void writeCommentShouldWriteGivenComment() {
EffectiveMojoUtils.writeComment(writer, "This is a comment");

assertEquals(
format("<?xml version=\"1.0\" encoding=\"%s\"?>%n", encoding)
+ format("<!-- ====================================================================== -->%n")
+ format("<!-- -->%n")
+ format("<!-- This is a comment -->%n")
+ format("<!-- -->%n")
+ format("<!-- ====================================================================== -->%n"),
w.toString());
}

@Test
void sortPropertiesShouldSortProperties() {
final Properties props = new Properties();
props.setProperty("z", "last");
props.setProperty("a", "first");
props.setProperty("g", "middle");

final Properties sortedProps = EffectiveMojoUtils.sortProperties(props);

final Object[] sortedValues = sortedProps.values().toArray();
assertEquals("first", sortedValues[0]);
assertEquals("middle", sortedValues[1]);
assertEquals("last", sortedValues[2]);

final Object[] sortedKeys = sortedProps.keySet().toArray();
assertEquals("a", sortedKeys[0]);
assertEquals("g", sortedKeys[1]);
assertEquals("z", sortedKeys[2]);
}

@Test
void prettyFormatShouldFormatXmlString() {
final String xml = "<root><child><subchild>value</subchild></child></root>";

final String prettyXml = EffectiveMojoUtils.prettyFormat(xml, encoding, false);

assertEquals(
format("<?xml version=\"1.0\" encoding=\"%s\"?>%n", encoding)
+ format("<root>%n")
+ format(" <child>%n")
+ format(" <subchild>value</subchild>%n")
+ format(" </child>%n")
+ format("</root>%n"),
prettyXml);
}

@Test
void prettyFormatShouldOmitDeclarationWhenSpecified() {
final String xml = "<root><child><subchild>value</subchild></child></root>";

final String prettyXml = EffectiveMojoUtils.prettyFormat(xml, encoding, true);

assertEquals(
format("<root>%n")
+ format(" <child>%n")
+ format(" <subchild>value</subchild>%n")
+ format(" </child>%n")
+ format("</root>%n"),
prettyXml);
}
}