package org.fenixedu.bennu.maven; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.SortedSet; import org.apache.maven.artifact.Artifact; import org.apache.maven.plugin.AbstractMojo; import org.apache.maven.plugin.MojoExecutionException; import org.apache.maven.plugin.MojoFailureException; import org.apache.maven.plugins.annotations.Mojo; import org.apache.maven.plugins.annotations.Parameter; import org.apache.maven.plugins.annotations.ResolutionScope; import org.apache.maven.project.MavenProject; import org.fenixedu.commons.configuration.ConfigurationInvocationHandler; import org.fenixedu.commons.configuration.ConfigurationManager; import org.fenixedu.commons.configuration.ConfigurationProperty; import org.reflections.ReflectionUtils; import org.reflections.Reflections; import org.reflections.util.ConfigurationBuilder; import com.google.common.base.Predicates; import com.google.common.collect.Sets; import com.google.common.io.Files; @Mojo(name = "generate-configuration", requiresDependencyResolution = ResolutionScope.RUNTIME) public class GenerateConfigurationMojo extends AbstractMojo { @Parameter(defaultValue = "${project}", required = true, readonly = true) private MavenProject project; @Parameter(property = "bennu.config.location", defaultValue = "src/main/resources") private File location; @Override public void execute() throws MojoExecutionException, MojoFailureException { getLog().info("Generating configuration.properties for project " + project.getArtifactId()); try { File outputFile = new File(location, "configuration.properties"); if (outputFile.exists()) { getLog().error(outputFile + " exists, not generating!"); throw new MojoFailureException("Output file already exists"); } Files.write(generateConfiguration(), outputFile, Charset.defaultCharset()); getLog().info("Written configuration to: " + outputFile); } catch (IOException e) { throw new MojoExecutionException("Could not write properties to file", e); } } private String generateConfiguration() throws MojoExecutionException { Reflections reflections = new ConfigurationBuilder().filterInputsBy(Predicates.alwaysTrue()).setUrls(getURLs()).build(); StringBuilder properties = new StringBuilder(); for (Class<?> type : reflections.getTypesAnnotatedWith(ConfigurationManager.class)) { properties.append("################### Properties for " + type.getAnnotation(ConfigurationManager.class).description() + " ###################\n\n"); for (Method method : sortedMethods(type)) { ConfigurationProperty property = method.getAnnotation(ConfigurationProperty.class); if (!property.description().isEmpty()) { properties.append("# "); properties.append(property.description().replace("\n", "\n#")); properties.append('\n'); } properties.append(property.key()); properties.append(" = "); properties.append(property.defaultValue().equals(ConfigurationInvocationHandler.NULL_DEFAULT) ? "" : property .defaultValue()); properties.append('\n'); } properties.append("\n\n"); } return properties.toString(); } private Collection<URL> getURLs() throws MojoExecutionException { try { Collection<URL> urls = new ArrayList<>(project.getArtifacts().size() + 1); for (Artifact artifact : project.getArtifacts()) { urls.add(artifact.getFile().toURI().toURL()); } urls.add(new File(project.getBuild().getOutputDirectory()).toURI().toURL()); URLClassLoader loader = URLClassLoader .newInstance(urls.toArray(new URL[urls.size()]), Thread.currentThread().getContextClassLoader()); Thread.currentThread().setContextClassLoader(loader); return urls; } catch (MalformedURLException e) { throw new MojoExecutionException("Could not properly define the classloader", e); } } @SuppressWarnings("unchecked") private Iterable<Method> sortedMethods(Class<?> type) { SortedSet<Method> methods = Sets.newTreeSet(new Comparator<Method>() { @Override public int compare(Method o1, Method o2) { return o1.getAnnotation(ConfigurationProperty.class).key() .compareTo(o2.getAnnotation(ConfigurationProperty.class).key()); } }); for (Method method : ReflectionUtils.getAllMethods(type)) { if (method.isAnnotationPresent(ConfigurationProperty.class)) { methods.add(method); } } return methods; } }