Commit patch of the Felix-413 issue.
Add the licence header.
Improve javadoc, comments, and error messages.

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@590935 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrCleanRepo.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrCleanRepo.java
new file mode 100644
index 0000000..e3446a2
--- /dev/null
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrCleanRepo.java
@@ -0,0 +1,271 @@
+/* 

+ * 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.felix.sandbox.obr.plugin;

+

+import java.io.File;

+import java.io.FileNotFoundException;

+import java.io.FileOutputStream;

+import java.io.IOException;

+import java.net.URI;

+import java.net.URISyntaxException;

+import java.text.SimpleDateFormat;

+import java.util.ArrayList;

+import java.util.Date;

+import java.util.List;

+import java.util.Properties;

+

+import javax.xml.parsers.DocumentBuilder;

+import javax.xml.parsers.DocumentBuilderFactory;

+import javax.xml.parsers.ParserConfigurationException;

+import javax.xml.transform.Result;

+import javax.xml.transform.Transformer;

+import javax.xml.transform.TransformerConfigurationException;

+import javax.xml.transform.TransformerException;

+import javax.xml.transform.TransformerFactory;

+import javax.xml.transform.dom.DOMSource;

+import javax.xml.transform.stream.StreamResult;

+

+import org.apache.maven.artifact.repository.ArtifactRepository;

+import org.apache.maven.plugin.AbstractMojo;

+import org.apache.maven.plugin.MojoExecutionException;

+import org.w3c.dom.Document;

+import org.w3c.dom.Element;

+import org.w3c.dom.Node;

+import org.w3c.dom.NodeList;

+import org.xml.sax.SAXException;

+

+/**

+ * Clean an OBR repository by finding and removing missing resources. 

+ * @goal clean

+ * @phase install

+ * @requiresDependencyResolution compile

+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>

+ */

+public class ObrCleanRepo extends AbstractMojo {

+

+    /**

+     * OBR Repository.

+     * 

+     * @parameter expression="${obrRepository}"

+     */

+    private String obrRepository;

+

+    /**

+     * Local Repository.

+     * 

+     * @parameter expression="${localRepository}"

+     * @required

+     * @readonly

+     */

+    private ArtifactRepository localRepository;

+

+    public void execute() throws MojoExecutionException {

+        // If no OBR repository, return

+        if ("NONE".equalsIgnoreCase(obrRepository)) {

+            return;

+        }

+

+        try {

+            // Compute local repository location

+            String localRepoPath = localRepository.getBasedir();

+            PathFile repositoryXml = normalizeRepositoryPath(obrRepository, localRepoPath);

+

+            // Check if the file exist

+            if (!repositoryXml.isExists()) {

+                getLog().error("The repository file " + repositoryXml.getAbsoluteFilename() + " does not exist");

+                return;

+            }

+

+            Document doc = parseFile(repositoryXml.getFile(), initConstructor());

+            Node finalDocument = cleanDocument(doc.getDocumentElement()); //Analyze existing repository.

+

+            if (finalDocument == null) {

+                getLog().info("Nothing to clean in " + repositoryXml.getAbsoluteFilename());

+            } else {

+                getLog().info("Cleaning...");

+                writeToFile(repositoryXml.getUri(), finalDocument);  // Write the new file

+                getLog().info("Repository " + repositoryXml.getAbsoluteFilename() + " updated");

+            }

+        } catch (Exception e) {

+            getLog().error("Exception while cleaning the OBR repository file : " + e.getLocalizedMessage(), e);

+        }

+    }

+

+    /**

+     * Analyze the given XML tree (DOM of the repository file) and remove missing resources.

+     * @param elem : the input XML tree

+     * @return the cleaned XML tree

+     */

+    private Element cleanDocument(Element elem) {

+        NodeList nodes = elem.getElementsByTagName("resource");

+        List toRemove = new ArrayList();

+        

+        // First, look for missing resources

+        for (int i = 0; i < nodes.getLength(); i++) {

+            Element n = (Element) nodes.item(i);

+            String value = n.getAttribute("uri");

+

+            String localRepoPath = localRepository.getBasedir();

+            File file = new File(localRepoPath, value);

+

+            if (!file.exists()) {

+                getLog().info(

+                        "The bundle " + n.getAttribute("presentationname") + " - " + n.getAttribute("version")

+                                + " will be removed");

+                toRemove.add(n);

+            }

+        }

+

+        if (toRemove.size() > 0) {

+            // Then remove missing resources.

+            for (int i = 0; i < toRemove.size(); i++) {

+                elem.removeChild((Node) toRemove.get(i));

+            }

+            

+            // If we have to remove resources, we need to update  'lastmodified' attribute

+            SimpleDateFormat format = new SimpleDateFormat("yyyyMMddHHmmss.SSS");

+            Date d = new Date();

+            d.setTime(System.currentTimeMillis());

+            elem.setAttribute("lastmodified", format.format(d));

+            return elem;

+        } else {

+            return null;

+        }

+    }

+

+    /**

+     * Initialize the document builder from Xerces.

+     * @return DocumentBuilder ready to create new document

+     * @throws MojoExecutionException : occurs when the instantiation of the document builder fails

+     */

+    private DocumentBuilder initConstructor() throws MojoExecutionException {

+        DocumentBuilder constructor = null;

+        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();

+        try {

+            constructor = factory.newDocumentBuilder();

+        } catch (ParserConfigurationException e) {

+            getLog().error("Unable to create a new xml document");

+            throw new MojoExecutionException("Cannot create the Document Builder : " + e.getMessage());

+        }

+        return constructor;

+    }

+

+    /**

+     * Open an XML file.

+     * @param filename : XML file path

+     * @param constructor DocumentBuilder get from xerces

+     * @return Document which describes this file

+     * @throws MojoExecutionException occurs when the given file cannot be opened or is a valid XML file.

+     */

+    private Document parseFile(File file, DocumentBuilder constructor) throws MojoExecutionException {

+        if (constructor == null) {

+            return null;

+        }

+        // The document is the root of the DOM tree.

+        getLog().info("Parsing " + file.getAbsolutePath());

+        Document doc = null;

+        try {

+            doc = constructor.parse(file);

+        } catch (SAXException e) {

+            getLog().error("Cannot parse " + file.getAbsolutePath() + " : " + e.getMessage());

+            throw new MojoExecutionException("Cannot parse " + file.getAbsolutePath() + " : " + e.getMessage());

+        } catch (IOException e) {

+            getLog().error("Cannot open " + file.getAbsolutePath() + " : " + e.getMessage());

+            throw new MojoExecutionException("Cannot open " + file.getAbsolutePath() + " : " + e.getMessage());

+        }

+        return doc;

+    }

+

+    /**

+     * write a Node in a xml file.

+     * @param outputFilename URI to the output file

+     * @param treeToBeWrite Node root of the tree to be write in file

+     * @throws MojoExecutionException if the plugin failed

+     */

+    private void writeToFile(URI outputFilename, Node treeToBeWrite) throws MojoExecutionException {

+        // init the transformer

+        Transformer transformer = null;

+        TransformerFactory tfabrique = TransformerFactory.newInstance();

+        try {

+            transformer = tfabrique.newTransformer();

+        } catch (TransformerConfigurationException e) {

+            getLog().error("Unable to write to file: " + outputFilename.toString());

+            throw new MojoExecutionException("Unable to write to file: " + outputFilename.toString() + " : " + e.getMessage());

+        }

+        Properties proprietes = new Properties();

+        proprietes.put("method", "xml");

+        proprietes.put("version", "1.0");

+        proprietes.put("encoding", "ISO-8859-1");

+        proprietes.put("standalone", "yes");

+        proprietes.put("indent", "yes");

+        proprietes.put("omit-xml-declaration", "no");

+        transformer.setOutputProperties(proprietes);

+

+        DOMSource input = new DOMSource(treeToBeWrite);

+

+        File fichier = new File(outputFilename);

+        FileOutputStream flux = null;

+        try {

+            flux = new FileOutputStream(fichier);

+        } catch (FileNotFoundException e) {

+            getLog().error("Unable to write to file: " + fichier.getName());

+            throw new MojoExecutionException("Unable to write to file: " + fichier.getName() + " : " + e.getMessage());

+        }

+        Result output = new StreamResult(flux);

+        try {

+            transformer.transform(input, output);

+        } catch (TransformerException e) {

+            throw new MojoExecutionException("Unable to write to file: " + outputFilename.toString() + " : " + e.getMessage());

+        }

+

+        try {

+            flux.flush();

+            flux.close();

+        } catch (IOException e) {

+            throw new MojoExecutionException("IOException when closing file : " + e.getMessage());

+        }

+

+    }

+

+    private static PathFile normalizeRepositoryPath(String obrPath, String mavenPath) {

+        if (null == obrPath || obrPath.length() == 0) {

+            obrPath = mavenPath + File.separatorChar + "repository.xml";

+        } else if (!obrPath.endsWith(".xml")) {

+            obrPath = obrPath + File.separatorChar + "repository.xml";

+        }

+

+        URI uri;

+        try {

+            uri = new URI(obrPath);

+        } catch (URISyntaxException e) {

+            uri = null;

+        }

+

+        if (null == uri || !uri.isAbsolute()) {

+            File file = new File(obrPath);

+            if (!file.isAbsolute()) {

+                file = new File(mavenPath, obrPath);

+            }

+

+            uri = file.toURI();

+        }

+

+        return new PathFile(uri.toASCIIString());

+    }

+}

diff --git a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrUpdate.java b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrUpdate.java
index 6bb0da4..4809951 100644
--- a/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrUpdate.java
+++ b/maven-obr-plugin/src/main/java/org/apache/felix/sandbox/obr/plugin/ObrUpdate.java
@@ -216,7 +216,7 @@
 

         if (!walkOnTree(m_root)) {

             // the correct resource node was not found, we must create it

-            // we calcul the new id

+            // we compute the new id

             int id = -1;

             for (int i = 1; i < m_idTab.length; i++) {

                 if (!m_idTab[i]) {

@@ -252,7 +252,7 @@
     }

 

     /**

-     * Parse the reporitory descriptor file.

+     * Parse the repository descriptor file.

      * 

      * @return 0 if the bundle is already in the descriptor, else -1

      * @throws MojoExecutionException if the plugin failed

@@ -293,7 +293,6 @@
 

         m_root = (Element) m_repoDoc.getDocumentElement();

         return 0;

-

     }

 

     /**