/* | |
* 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()); | |
} | |
} |