com.adviser.maven.MergeFeaturesRepoMojo.java Source code

Java tutorial

Introduction

Here is the source code for com.adviser.maven.MergeFeaturesRepoMojo.java

Source

/**
 *
 * 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 com.adviser.maven;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.StringWriter;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.artifact.resolver.ArtifactNotFoundException;
import org.apache.maven.artifact.resolver.ArtifactResolutionException;
import org.apache.maven.plugin.MojoExecutionException;
import org.apache.maven.plugin.MojoFailureException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * Add Features necessary bundles into system folder Repo
 * 
 * @goal merge-features
 * @phase compile
 * @execute phase="compile"
 * @requiresDependencyResolution runtime
 * @inheritByDefault true
 * @description Merge features.xml repos in one repository
 */
public class MergeFeaturesRepoMojo extends MojoSupport {

    /**
     * @parameter
     */
    private List<String> descriptors;

    /**
     * @parameter
     */
    private boolean resolveDefinedRepositoriesRecursively = true;

    /**
     * The file to generate
     * 
     * @parameter default-value="${project.build.directory}/generated/features.xml"
     */
    private File outputFile;

    /**
     * @parameter
     */
    private String mergedRepoName;

    /**
     * @parameter
     */
    private List<String> mergedRepoRepositories;

    /**
     * @parameter
     */
    private List<String> includeFeaturesPrefixes;

    private Map<String, String> visitedDescriptors = new HashMap<String, String>();

    public void execute() throws MojoExecutionException, MojoFailureException {

        try {
            Set<String> bundles = new HashSet<String>();
            Map<String, Feature> featuresMap = new HashMap<String, Feature>();
            for (String uri : descriptors) {
                retrieveDescriptorsRecursively(uri, bundles, featuresMap);
            }
            writeFeatures(featuresMap);

        } catch (MojoExecutionException e) {
            throw e;
        } catch (MojoFailureException e) {
            throw e;
        } catch (Exception e) {
            throw new MojoExecutionException("Error populating repository", e);
        }
    }

    private void writeFeatures(Map<String, Feature> featuresMap) throws MojoExecutionException {
        //        
        try {
            TreeMap<String, Feature> sortedFeatureMap = new TreeMap<String, Feature>(featuresMap);

            File parent = outputFile.getParentFile();
            if (!parent.exists()) {
                parent.mkdirs();
            }

            getLog().info("Generating " + outputFile.getAbsolutePath());

            DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
            Document doc = docBuilder.newDocument();

            Element rootElement = doc.createElement("features");
            rootElement.setAttribute("name", mergedRepoName);
            rootElement.setAttributeNS("http://www.w3.org/2001/XMLSchema-instance", "xsi",
                    "http://karaf.apache.org/xmlns/features/v1.0.0");
            doc.appendChild(rootElement);

            //            out.println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
            //            out.println("<features " + name);
            //            out.println("\txmlns=\"http://karaf.apache.org/xmlns/features/v1.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"");
            //            out.println("\txsi:schemaLocation=\"http://karaf.apache.org/xmlns/features/v1.0.0 http://karaf.apache.org/xmlns/features/v1.0.0\">");
            if (mergedRepoRepositories != null) {
                //                out.println("");
                for (String repo : mergedRepoRepositories) {
                    Element repository = doc.createElement("repository");
                    repository.setTextContent(repo);
                    rootElement.appendChild(repository);
                    //                    out.println("\t<repository>" + repo + "</repository>");
                }
            }
            for (Map.Entry<String, Feature> entry : sortedFeatureMap.entrySet()) {
                Feature feature = entry.getValue();
                if (includeFeaturesPrefixes != null) {
                    for (String prefix : includeFeaturesPrefixes) {
                        if (feature.getName().startsWith(prefix)) {
                            getLog().info(" Generating feature " + feature.getName() + "/" + feature.getVersion()
                                    + " from repo " + feature.getOriginalRepo());
                            rootElement.appendChild(feature.write(doc));
                        }
                    }
                }
            }
            TransformerFactory tf = TransformerFactory.newInstance();
            Transformer transformer = tf.newTransformer();
            transformer.setOutputProperty(OutputKeys.INDENT, "yes");
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2");
            transformer.setOutputProperty(OutputKeys.METHOD, "xml");
            //transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
            //PrintStream out = new PrintStream(new FileOutputStream(outputFile));
            OutputStream out = new FileOutputStream(outputFile);
            transformer.transform(new DOMSource(doc), new StreamResult(out));
            out.close();
            //            out.println("</features>");
            getLog().info("...done!");
        } catch (Exception e) {
            getLog().error(e);
            throw new MojoExecutionException("Unable to create " + outputFile.getAbsolutePath() + " file: " + e, e);
        } finally {
        }

    }

    private void retrieveDescriptorsRecursively(String uri, Set<String> bundles, Map<String, Feature> featuresMap)
            throws Exception {
        if (visitedDescriptors.containsKey(uri)) {
            getLog().debug("Descriptor already visited: " + uri);

            return;
        }
        getLog().info("Reading repository " + uri);
        visitedDescriptors.put(uri, uri);

        Repository repo = new Repository(uri, URI.create(translateFromMaven(uri.replaceAll(" ", "%20"))));
        for (Feature f : repo.getFeatures()) {
            featuresMap.put(f.getName() + "/" + f.getVersion(), f);
        }
        if (resolveDefinedRepositoriesRecursively) {
            for (String r : repo.getDefinedRepositories()) {
                retrieveDescriptorsRecursively(r, bundles, featuresMap);
            }
        }

    }

    // resolves the bundle in question
    // TODO neither remoteRepos nor bundle's Repository are used, only the local repo?????
    //    private void resolveBundle(Artifact bundle, List<ArtifactRepository> remoteRepos) throws IOException, MojoFailureException {
    //        // TODO consider DefaultRepositoryLayout
    //        String dir = bundle.getGroupId().replace('.', '/') + "/" + bundle.getArtifactId() + "/" + bundle.getBaseVersion() + "/";
    //        String name = bundle.getArtifactId() + "-" + bundle.getBaseVersion()
    //                + (bundle.getClassifier() != null ? "-" + bundle.getClassifier() : "") + "." + bundle.getType();
    //
    //        try {
    //            getLog().info("Copying bundle: " + bundle);
    //            resolver.resolve(bundle, remoteRepos, localRepo);
    //            copy(new FileInputStream(bundle.getFile()), repository, name, dir, new byte[8192]);
    //        } catch (ArtifactResolutionException e) {
    //            if (failOnArtifactResolutionError) {
    //                throw new MojoFailureException("Can't resolve bundle " + bundle, e);
    //            }
    //            getLog().error("Can't resolve bundle " + bundle, e);
    //        } catch (ArtifactNotFoundException e) {
    //            if (failOnArtifactResolutionError) {
    //                throw new MojoFailureException("Can't resolve bundle " + bundle, e);
    //            }
    //            getLog().error("Can't resolve bundle " + bundle, e);
    //        }
    //    }

    public static class Feature {

        private String name;
        private String version;
        private List<SimpleArtifact> dependencies = new ArrayList<SimpleArtifact>();
        private List<SimpleArtifact> bundles = new ArrayList<SimpleArtifact>();
        private Map<String, Map<String, String>> configs = new HashMap<String, Map<String, String>>();
        private List<SimpleArtifact> configFiles = new ArrayList<SimpleArtifact>();
        private String originalRepo;

        public Feature(String name) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public String getVersion() {
            return version;
        }

        public void setVersion(String version) {
            this.version = version;
        }

        public String getOriginalRepo() {
            return originalRepo;
        }

        public void setOriginalRepo(String originalRepo) {
            this.originalRepo = originalRepo;
        }

        public List<SimpleArtifact> getDependencies() {
            return dependencies;
        }

        public List<SimpleArtifact> getBundles() {
            return bundles;
        }

        public Map<String, Map<String, String>> getConfigurations() {
            return configs;
        }

        public List<SimpleArtifact> getConfigFiles() {
            return configFiles;
        }

        public void addDependency(SimpleArtifact dependency) {
            dependencies.add(dependency);
        }

        public void addBundle(SimpleArtifact bundle) {
            bundles.add(bundle);
        }

        public void addConfig(String name, Map<String, String> properties) {
            configs.put(name, properties);
        }

        public void addConfigFile(SimpleArtifact configFile) {
            configFiles.add(configFile);
        }

        //        private String writeAttr(String name, String value) {
        //            if (value != null && value.length() > 0) {
        //                return " " + name + "=" + "\"" + value + "\"";
        //            } else {
        //                return "";
        //            }
        //        }

        public Element write(Document doc) {

            final Element feature = doc.createElement("feature");
            feature.setAttribute("name", name);
            feature.setAttribute("version", version);

            //            out.println("\n\t<feature" + writeAttr("name", name) + writeAttr("version", version) + ">");

            for (SimpleArtifact a : dependencies) {
                final Element inFeature = doc.createElement("feature");
                inFeature.setAttribute("version", a.getVersion());
                inFeature.setTextContent(a.getName());
                feature.appendChild(inFeature);
                //                out.println("\t\t<feature" + writeAttr("version", a.getVersion()) + ">" + a.getName() + "</feature>");
            }
            for (SimpleArtifact a : bundles) {
                final Element bundle = doc.createElement("bundle");
                bundle.setTextContent(a.getName());
                feature.appendChild(bundle);
                //                out.println("\t\t<bundle>" + a.getName() + "</bundle>");
            }
            for (SimpleArtifact a : configFiles) {
                final Element configfile = doc.createElement("configfile");
                configfile.setAttribute("finalname", a.getAttr("finalname"));
                configfile.setTextContent(a.getName());
                feature.appendChild(configfile);
                //                out.println("\t\t<configfile" + writeAttr("finalname", a.getAttr("finalname")) + ">" + a.getName()
                //                        + "</configfile>");
            }
            //            out.println("\t</feature>");
            return feature;
        }
    }

    public static class Repository {

        private URI uri;
        private List<Feature> features;
        private List<String> repositories;
        private String urlString;

        public Repository(String urlString, URI uri) {
            this.uri = uri;
            this.urlString = urlString;
        }

        public URI getURI() {
            return uri;
        }

        public Feature[] getFeatures() throws Exception {
            if (features == null) {
                loadFeatures();
            }
            return features.toArray(new Feature[features.size()]);
        }

        public String[] getDefinedRepositories() throws Exception {
            if (repositories == null) {
                loadRepositories();
            }
            return repositories.toArray(new String[repositories.size()]);
        }

        private void loadRepositories() throws IOException {
            try {
                repositories = new ArrayList<String>();
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                Document doc = factory.newDocumentBuilder().parse(uri.toURL().openStream());
                NodeList nodes = doc.getDocumentElement().getChildNodes();
                for (int i = 0; i < nodes.getLength(); i++) {
                    org.w3c.dom.Node node = nodes.item(i);
                    if (!(node instanceof Element) || !"repository".equals(node.getNodeName())) {
                        continue;
                    }
                    Element e = (Element) nodes.item(i);
                    repositories.add(e.getTextContent().trim());
                }
            } catch (SAXException e) {
                throw (IOException) new IOException().initCause(e);
            } catch (ParserConfigurationException e) {
                throw (IOException) new IOException().initCause(e);
            }
        }

        private void loadFeatures() throws IOException {
            try {
                features = new ArrayList<Feature>();
                DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
                Document doc = factory.newDocumentBuilder().parse(uri.toURL().openStream());
                NodeList nodes = doc.getDocumentElement().getChildNodes();
                for (int i = 0; i < nodes.getLength(); i++) {
                    org.w3c.dom.Node node = nodes.item(i);
                    if (!(node instanceof Element) || !"feature".equals(node.getNodeName())) {
                        continue;
                    }
                    Element e = (Element) nodes.item(i);
                    String name = e.getAttribute("name");
                    String version = e.getAttribute("version");
                    Feature f = new Feature(name);
                    f.setVersion(version);
                    f.setOriginalRepo(urlString);
                    NodeList featureNodes = e.getElementsByTagName("feature");
                    for (int j = 0; j < featureNodes.getLength(); j++) {
                        Element b = (Element) featureNodes.item(j);
                        SimpleArtifact a = new SimpleArtifact(b.getTextContent(), b.getAttribute("version"));
                        f.addDependency(a);
                    }
                    NodeList configNodes = e.getElementsByTagName("config");
                    for (int j = 0; j < configNodes.getLength(); j++) {
                        Element c = (Element) configNodes.item(j);
                        String cfgName = c.getAttribute("name");
                        String data = c.getTextContent();
                        Properties properties = new Properties();
                        properties.load(new ByteArrayInputStream(data.getBytes()));
                        Map<String, String> hashtable = new Hashtable<String, String>();
                        for (Object key : properties.keySet()) {
                            String n = key.toString();
                            hashtable.put(n, properties.getProperty(n));
                        }
                        f.addConfig(cfgName, hashtable);
                    }
                    NodeList configFileNodes = e.getElementsByTagName("configfile");
                    for (int j = 0; j < configFileNodes.getLength(); j++) {
                        Element c = (Element) configFileNodes.item(j);
                        SimpleArtifact a = new SimpleArtifact(c.getTextContent());
                        a.addAttr(new SimpleArtifact.Attr("finalname", c.getAttribute("finalname")));
                        f.addConfigFile(a);
                    }
                    NodeList bundleNodes = e.getElementsByTagName("bundle");
                    for (int j = 0; j < bundleNodes.getLength(); j++) {
                        Element b = (Element) bundleNodes.item(j);
                        SimpleArtifact a = new SimpleArtifact(b.getTextContent(), b.getAttribute("version"));
                        f.addBundle(a);
                    }
                    features.add(f);
                }
            } catch (SAXException e) {
                throw (IOException) new IOException().initCause(e);
            } catch (ParserConfigurationException e) {
                throw (IOException) new IOException().initCause(e);
            }
        }

    }

    public static class SimpleArtifact {

        static class Attr {

            public Attr(String name, String value) {
                this.name = name;
                this.value = value;
            }

            String name;
            String value;
        }

        private String name;
        private String version;
        private List<Attr> attributes = new ArrayList<Attr>();

        public SimpleArtifact(String name) {
            this.name = name;
        }

        public SimpleArtifact(String name, String version) {
            this.name = name;
            this.version = version;
        }

        public String getName() {
            return name;
        }

        public String getVersion() {
            return version;
        }

        public void addAttr(Attr attr) {
            attributes.add(attr);
        }

        public String getAttr(String attr) {
            for (Attr a : attributes) {
                if (a.name.equals(attr)) {
                    return a.value;
                }
            }
            return null;
        }

        public List<Attr> getAttributes() {
            return attributes;
        }

        public void setAttributes(List<Attr> attributes) {
            this.attributes = attributes;
        }

    }
}