All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.kantega.reststop.maven.ConfDocMojo Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2018 Kantega AS
 *
 * Licensed 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.kantega.reststop.maven;

import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;
import org.apache.maven.plugins.annotations.ResolutionScope;
import org.kantega.reststop.classloaderutils.config.PluginConfigParam;
import org.kantega.reststop.classloaderutils.config.PluginConfigParams;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import java.io.*;
import java.util.*;
import java.util.function.Predicate;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;

@Mojo(name = "conf-doc", defaultPhase = LifecyclePhase.PROCESS_CLASSES, requiresDependencyResolution = ResolutionScope.COMPILE)
public class ConfDocMojo extends AbstractReststopMojo {

    @Parameter(defaultValue = "${project.build.directory}/example.conf")
    private File exampleConfigFile;

    @Parameter(defaultValue = "${project.build.directory}/config-params.html")
    private File htmlDocumentationFile;

    @Parameter(required = true)
    private String applicationName;

    @Parameter(defaultValue = "${basedir}/src/config")
    private File configDir;

    @Parameter(defaultValue = "false")
    private boolean suppressWarnings;


    @Override
    public void execute() throws MojoExecutionException, MojoFailureException {

        try {
            DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();

            exampleConfigFile.getParentFile().mkdirs();

            Map> configs = findConfigs(documentBuilder);

            Properties properties = validateConfiguration(configs);
            writeExampleConfig(configs);
            writeHtmlDoc(configs, properties);


        } catch (IOException | ParserConfigurationException e) {
            throw new MojoExecutionException(e.getMessage(), e);
        }
    }

    private void writeHtmlDoc(Map> configMap, Properties properties) throws FileNotFoundException, UnsupportedEncodingException {
        try (PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(htmlDocumentationFile), "iso-8859-1"))) {

            out.println("");
            out.print("");
            out.println("");
            out.println("

Configuration

"); out.println(""); out.println(""); out.print(""); out.print(""); out.print(""); out.print(""); out.println(""); for (Map.Entry> entry : configMap.entrySet()) { out.println(""); out.println(""); out.println(""); for (PluginConfig config : entry.getValue()) { Collections.sort(config.getConfigParams(), Comparator.comparing(PluginConfigParam::isOptional).thenComparing(PluginConfigParam::getParamName)); for (PluginConfigParam param : config.getConfigParams()) { out.println(""); out.print(""); out.print(param.getParamName()); out.println(""); out.println(""); out.println(""); out.println(""); out.println(""); } } } out.println("
"); out.print("Property name"); out.println(""); out.print("Description"); out.println(""); out.print("Default"); out.println(""); out.print("Test value"); out.println("
"); out.print(entry.getKey().split(":")[1]); out.println("
"); if (param.hasDocumentation()) { out.print(param.getDoc()); } out.println(""); out.print(param.getDefaultValue()); out.println(""); String value = properties.getProperty(param.getParamName()); if (value != null) { out.print(value); } out.println("
"); out.println(""); out.println(""); } } private Properties validateConfiguration(Map> configMap) throws IOException, MojoFailureException { Properties props = new Properties(); String configFileName = applicationName + ".conf"; props.load(new FileInputStream(new File(configDir, configFileName))); List missingParameters = new ArrayList<>(); Set knownProperties = new HashSet<>(); for (Map.Entry> entry : configMap.entrySet()) { for (PluginConfig config : entry.getValue()) { for (PluginConfigParam param : config.getConfigParams()) { if (param.getType().equals("java.util.Properties")) { continue; } knownProperties.add(param.getParamName()); String value = props.getProperty(param.getParamName()); if (value == null && param.isRequired() && !param.hasDefaultValue()) { missingParameters.add(new ParamContext(entry.getKey(), config, param)); } } } } if (!missingParameters.isEmpty()) { StringBuilder message = new StringBuilder(String.format("Config file %s is missing the following properties:\n", configFileName)); for (ParamContext missingParameter : missingParameters) { message.append(String.format(" '%s' needed by %s\n", missingParameter.getParam().getParamName(), missingParameter.getKey())); } if (!suppressWarnings) throw new MojoFailureException(message.toString()); else getLog().warn(message.toString()); } Set unknownProperties = new TreeSet(); for (String name : props.stringPropertyNames()) { if (!knownProperties.contains(name)) { unknownProperties.add(name); } } if (!unknownProperties.isEmpty()) { StringBuilder message = new StringBuilder(String.format("Config file %s contains the following unused properties:\n", configFileName)); for (String unknownProperty : unknownProperties) { message.append(String.format("'%s'\n", unknownProperty)); } if (!suppressWarnings) throw new MojoFailureException(message.toString()); else getLog().warn(message.toString()); } return props; } private void writeExampleConfig(Map> configs) throws FileNotFoundException, UnsupportedEncodingException { try (PrintWriter out = new PrintWriter(new OutputStreamWriter(new FileOutputStream(exampleConfigFile), "iso-8859-1"))) { for (Map.Entry> entry : configs.entrySet()) { getLog().info("Found plugin " + entry.getKey()); out.println("############################"); out.println("# " + entry.getKey()); out.println("#"); List plugins = entry.getValue(); for (PluginConfig config : plugins) { getLog().info("\tFound plugin class " + config.getClassName()); if (!config.getConfigParams().isEmpty()) { Predicate hasDefaultValue = PluginConfigParam::hasDefaultValue; config.getConfigParams().stream().filter(hasDefaultValue.negate()).forEach(param -> { getLog().info("\t\tFound plugin param " + param.getParamName()); out.println(); document(param, out, "# "); out.print(param.getParamName()); out.print("="); out.println(); }); if (config.getConfigParams().stream().filter(hasDefaultValue).findFirst().isPresent()) { out.println(); out.println("## Parameters with default values: "); config.getConfigParams().stream().filter(hasDefaultValue).forEach(param -> { getLog().info("\t\tFound plugin param " + param.getParamName()); out.println("##"); document(param, out, "## "); out.print("## "); out.print(param.getParamName()); out.print("="); out.println(param.getDefaultValue()); }); } } } } out.println(); out.println(); } } private Map> findConfigs(DocumentBuilder context) throws MojoFailureException, MojoExecutionException, IOException { Map> configs = new LinkedHashMap<>(); for (Plugin plugin : getPlugins()) { File pluginFile = resolveArtifactFile(plugin.getCoords()); List configsForPlugin = readPluginConfigs(pluginFile, context); if (configsForPlugin != null && hasProps(configsForPlugin)) { configs.put(plugin.getCoords(), configsForPlugin); } } return configs; } private void document(PluginConfigParam param, PrintWriter out, String prefix) { if (param.hasDocumentation()) { for (String line : param.getDoc().split("\n")) { out.print(prefix); out.print(line); out.println(":"); } } } private boolean hasProps(List configs) { for (PluginConfig config : configs) { if (!config.getConfigParams().isEmpty()) { return true; } } return false; } private List readPluginConfigs(File pluginFile, DocumentBuilder documentBuilder) throws IOException { List configs = new ArrayList<>(); String path = "META-INF/services/ReststopPlugin/simple.txt"; if (pluginFile.isDirectory()) { File descriptorFile = new File(pluginFile, path); if (descriptorFile.exists()) { try (BufferedReader br = new BufferedReader(new InputStreamReader(new FileInputStream(descriptorFile)))) { String className; while ((className = br.readLine()) != null) { try (InputStream is = new FileInputStream(new File(pluginFile, className.replace('.', '/') + ".config-params"))) { configs.add(new PluginConfig(className, new ParamsUnmarshaller().unmarshal(is, documentBuilder))); } } } } } else { try (JarFile jarFile = new JarFile(pluginFile)) { ZipEntry entry = jarFile.getEntry(path); if (entry != null) { try (BufferedReader br = new BufferedReader(new InputStreamReader(jarFile.getInputStream(entry)))) { String className; while ((className = br.readLine()) != null) { ZipEntry configParamsEntry = jarFile.getEntry(className.replace('.', '/') + ".config-params"); try (InputStream is = jarFile.getInputStream(configParamsEntry)) { configs.add(new PluginConfig(className, new ParamsUnmarshaller().unmarshal(is, documentBuilder))); } } } } } } return configs; } @Override protected List getPlugins() { List plugins = new ArrayList<>(); if (mavenProject.getPackaging().equals("jar")) { if (hasArtifactFileFromPackagePhase()) { Plugin projectPlugin = new Plugin(mavenProject.getGroupId(), mavenProject.getArtifactId(), mavenProject.getVersion()); projectPlugin.setSourceDirectory(mavenProject.getBasedir()); plugins.add(projectPlugin); } { Plugin devConsolePlugin = new Plugin("org.kantega.reststop", "reststop-development-console", pluginVersion); plugins.add(devConsolePlugin); } { Plugin developmentPlugin = new Plugin("org.kantega.reststop", "reststop-development-plugin", pluginVersion); plugins.add(developmentPlugin); } } plugins.addAll(super.getPlugins()); return plugins; } private boolean hasArtifactFileFromPackagePhase() { return mavenProject.getArtifact() != null && mavenProject.getArtifact().getFile() != null && mavenProject.getArtifact().getFile().exists(); } private class ParamContext { private final String key; private final PluginConfig config; private final PluginConfigParam param; public ParamContext(String key, PluginConfig config, PluginConfigParam param) { this.key = key; this.config = config; this.param = param; } public String getKey() { return key; } public PluginConfig getConfig() { return config; } public PluginConfigParam getParam() { return param; } } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy