001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *   http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing,
013 * software distributed under the License is distributed on an
014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 * KIND, either express or implied.  See the License for the
016 * specific language governing permissions and limitations
017 * under the License.
018 */
019package org.apache.maven.tools.plugin.generator;
020
021import java.io.File;
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.InputStreamReader;
025import java.io.OutputStreamWriter;
026import java.io.StringWriter;
027import java.io.Writer;
028
029import org.apache.maven.project.MavenProject;
030import org.apache.velocity.VelocityContext;
031import org.codehaus.plexus.util.io.CachingOutputStream;
032import org.codehaus.plexus.velocity.VelocityComponent;
033
034import static java.nio.charset.StandardCharsets.UTF_8;
035
036/**
037 * Generates an <code>HelpMojo</code> class from <code>help-class-source.vm</code> template.
038 * The generated mojo reads help content from <code>META-INF/maven/${groupId}/${artifactId}/plugin-help.xml</code>
039 * resource, which is generated by this {@link PluginDescriptorFilesGenerator}.
040 *
041 * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
042 * @since 2.4
043 */
044public class PluginHelpGenerator {
045    /**
046     * Default generated class name
047     */
048    private static final String HELP_MOJO_CLASS_NAME = "HelpMojo";
049
050    private String helpPackageName;
051    private String goalPrefix;
052    private MavenProject mavenProject;
053    private boolean useMaven4Api;
054    private VelocityComponent velocityComponent;
055
056    /**
057     * Default constructor
058     */
059    public PluginHelpGenerator() {
060        // nop
061    }
062
063    // ----------------------------------------------------------------------
064    // Public methods
065    // ----------------------------------------------------------------------
066
067    public void execute(File destinationDirectory) throws GeneratorException {
068        String helpImplementation = getImplementation();
069
070        useMaven4Api = mavenProject.getDependencies().stream()
071                .anyMatch(dep ->
072                        "org.apache.maven".equals(dep.getGroupId()) && "maven-api-core".equals(dep.getArtifactId()));
073
074        try {
075            String sourcePath = helpImplementation.replace('.', File.separatorChar) + ".java";
076
077            File helpClass = new File(destinationDirectory, sourcePath);
078            helpClass.getParentFile().mkdirs();
079
080            String helpClassSources = getHelpClassSources(getPluginHelpPath(mavenProject));
081
082            try (Writer w = new OutputStreamWriter(new CachingOutputStream(helpClass), UTF_8)) {
083                w.write(helpClassSources);
084            }
085        } catch (IOException e) {
086            throw new GeneratorException(e.getMessage(), e);
087        }
088    }
089
090    public PluginHelpGenerator setHelpPackageName(String helpPackageName) {
091        this.helpPackageName = helpPackageName;
092        return this;
093    }
094
095    public PluginHelpGenerator setVelocityComponent(VelocityComponent velocityComponent) {
096        this.velocityComponent = velocityComponent;
097        return this;
098    }
099
100    public PluginHelpGenerator setGoalPrefix(String goalPrefix) {
101        this.goalPrefix = goalPrefix;
102        return this;
103    }
104
105    public PluginHelpGenerator setMavenProject(MavenProject mavenProject) {
106        this.mavenProject = mavenProject;
107        return this;
108    }
109
110    // ----------------------------------------------------------------------
111    // Private methods
112    // ----------------------------------------------------------------------
113
114    private String getHelpClassSources(String pluginHelpPath) throws IOException {
115        VelocityContext context = new VelocityContext();
116
117        context.put("helpPackageName", helpPackageName);
118        context.put("pluginHelpPath", pluginHelpPath);
119        context.put("artifactId", mavenProject.getArtifactId());
120        // TODO: evaluate prefix from deserialized plugin
121        context.put("goalPrefix", goalPrefix);
122
123        StringWriter stringWriter = new StringWriter();
124
125        // plugin-tools sources are UTF-8 (and even ASCII in this case))
126        try (InputStream is = Thread.currentThread()
127                        .getContextClassLoader()
128                        .getResourceAsStream(useMaven4Api ? "help-class-source-v4.vm" : "help-class-source.vm"); //
129                InputStreamReader isReader = new InputStreamReader(is, UTF_8)) {
130            // isReader =
131            velocityComponent.getEngine().evaluate(context, stringWriter, "", isReader);
132        }
133        // Apply OS lineSeparator instead of template's lineSeparator to have consistent separators for
134        // all source files.
135        return stringWriter.toString().replaceAll("(\r\n|\n|\r)", System.lineSeparator());
136    }
137
138    /**
139     * @return The implementation.
140     */
141    private String getImplementation() {
142        return (helpPackageName == null || helpPackageName.isEmpty())
143                ? HELP_MOJO_CLASS_NAME
144                : helpPackageName + '.' + HELP_MOJO_CLASS_NAME;
145    }
146
147    static String getPluginHelpPath(MavenProject mavenProject) {
148        return mavenProject.getGroupId() + "/" + mavenProject.getArtifactId() + "/plugin-help.xml";
149    }
150}