blob: 677dd429a0345727b0e25b34540cdfe5858e7870 [file] [log] [blame]
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +00001/*
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +00002 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
Stuart McCullochc792b372008-02-17 16:12:24 +000019package org.apache.felix.obrplugin;
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +000020
21
22import java.io.File;
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +000023import java.io.FileOutputStream;
24import java.io.IOException;
25import java.net.URI;
26import java.text.SimpleDateFormat;
27import java.util.ArrayList;
28import java.util.Date;
29import java.util.List;
30import java.util.Properties;
31
32import javax.xml.parsers.DocumentBuilder;
33import javax.xml.parsers.DocumentBuilderFactory;
34import javax.xml.parsers.ParserConfigurationException;
35import javax.xml.transform.Result;
36import javax.xml.transform.Transformer;
37import javax.xml.transform.TransformerConfigurationException;
38import javax.xml.transform.TransformerException;
39import javax.xml.transform.TransformerFactory;
40import javax.xml.transform.dom.DOMSource;
41import javax.xml.transform.stream.StreamResult;
42
43import org.apache.maven.artifact.repository.ArtifactRepository;
44import org.apache.maven.plugin.AbstractMojo;
45import org.apache.maven.plugin.MojoExecutionException;
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +000046import org.apache.maven.plugins.annotations.LifecyclePhase;
47import org.apache.maven.plugins.annotations.Mojo;
48import org.apache.maven.plugins.annotations.Parameter;
Stuart McCulloch88129022009-09-03 02:52:58 +000049import org.codehaus.plexus.util.FileUtils;
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +000050import org.w3c.dom.Document;
51import org.w3c.dom.Element;
52import org.w3c.dom.Node;
53import org.w3c.dom.NodeList;
54import org.xml.sax.SAXException;
55
56
57/**
58 * Clean an OBR repository by finding and removing missing resources.
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +000059 *
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +000060 * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
61 */
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +000062@Mojo( name = "clean", requiresProject = false, defaultPhase = LifecyclePhase.CLEAN )
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +000063public class ObrCleanRepo extends AbstractMojo
64{
65 /**
66 * OBR Repository.
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +000067 */
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +000068 @Parameter( property = "obrRepository" )
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +000069 private String obrRepository;
70
71 /**
72 * Local Repository.
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +000073 */
Carsten Ziegeler318c2cb2015-03-09 13:57:23 +000074 @Parameter( defaultValue = "${localRepository}", readonly = true, required = true )
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +000075 private ArtifactRepository localRepository;
76
77
78 public void execute()
79 {
Stuart McCulloch5d6cb732008-02-18 05:24:46 +000080 if ( "NONE".equalsIgnoreCase( obrRepository ) || "false".equalsIgnoreCase( obrRepository ) )
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +000081 {
Stuart McCulloch5d6cb732008-02-18 05:24:46 +000082 getLog().info( "Local OBR clean disabled (enable with -DobrRepository)" );
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +000083 return;
84 }
85
86 try
87 {
88 // Compute local repository location
89 URI repositoryXml = ObrUtils.findRepositoryXml( localRepository.getBasedir(), obrRepository );
90 if ( !"file".equals( repositoryXml.getScheme() ) )
91 {
92 getLog().error( "The repository URI " + repositoryXml + " is not a local file" );
93 return;
94 }
95
96 File repositoryFile = new File( repositoryXml );
97
98 // Check if the file exist
99 if ( !repositoryFile.exists() )
100 {
101 getLog().error( "The repository file " + repositoryFile + " does not exist" );
102 return;
103 }
104
105 getLog().info( "Cleaning..." );
106
107 Document doc = parseFile( repositoryFile, initConstructor() );
108 Node finalDocument = cleanDocument( doc.getDocumentElement() ); // Analyze existing repository.
109
110 if ( finalDocument == null )
111 {
112 getLog().info( "Nothing to clean in " + repositoryFile );
113 }
114 else
115 {
116 writeToFile( repositoryXml, finalDocument ); // Write the new file
117 getLog().info( "Repository " + repositoryFile + " cleaned" );
118 }
119 }
120 catch ( Exception e )
121 {
122 getLog().error( "Exception while cleaning local OBR: " + e.getLocalizedMessage(), e );
123 }
124 }
125
126
127 /**
128 * Analyze the given XML tree (DOM of the repository file) and remove missing resources.
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000129 *
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +0000130 * @param elem : the input XML tree
131 * @return the cleaned XML tree
132 */
133 private Element cleanDocument( Element elem )
134 {
135 String localRepoPath = localRepository.getBasedir();
Stuart McCullochf5f52852011-06-24 19:19:35 +0000136 URI baseURI = new File( localRepoPath + '/' ).toURI();
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +0000137 NodeList nodes = elem.getElementsByTagName( "resource" );
138 List toRemove = new ArrayList();
139
140 // First, look for missing resources
141 for ( int i = 0; i < nodes.getLength(); i++ )
142 {
143 Element n = ( Element ) nodes.item( i );
144 String value = n.getAttribute( "uri" );
145
Stuart McCullochf5f52852011-06-24 19:19:35 +0000146 URI resource;
147 try
148 {
149 resource = baseURI.resolve( value );
150 }
151 catch ( IllegalArgumentException e )
152 {
153 getLog().error( "Malformed URL when creating the resource absolute URI : " + e.getMessage() );
154 return null;
155 }
156
157 if ( "file".equals( resource.getScheme() ) && !new File( resource ).exists() )
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +0000158 {
159 getLog().info(
160 "The bundle " + n.getAttribute( "presentationname" ) + " - " + n.getAttribute( "version" )
161 + " will be removed" );
162 toRemove.add( n );
163 }
164 }
165
166 Date d = new Date();
167 if ( toRemove.size() > 0 )
168 {
169 // Then remove missing resources.
170 for ( int i = 0; i < toRemove.size(); i++ )
171 {
172 elem.removeChild( ( Node ) toRemove.get( i ) );
173 }
174
175 // If we have to remove resources, we need to update 'lastmodified' attribute
176 SimpleDateFormat format = new SimpleDateFormat( "yyyyMMddHHmmss.SSS" );
177 d.setTime( System.currentTimeMillis() );
178 elem.setAttribute( "lastmodified", format.format( d ) );
179 return elem;
180 }
181
182 return null;
183 }
184
185
186 /**
187 * Initialize the document builder from Xerces.
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000188 *
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +0000189 * @return DocumentBuilder ready to create new document
190 * @throws MojoExecutionException : occurs when the instantiation of the document builder fails
191 */
192 private DocumentBuilder initConstructor() throws MojoExecutionException
193 {
194 DocumentBuilder constructor = null;
195 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
196 try
197 {
198 constructor = factory.newDocumentBuilder();
199 }
200 catch ( ParserConfigurationException e )
201 {
202 getLog().error( "Unable to create a new xml document" );
203 throw new MojoExecutionException( "Cannot create the Document Builder : " + e.getMessage() );
204 }
205 return constructor;
206 }
207
208
209 /**
210 * Open an XML file.
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000211 *
Guillaume Nodet8d5faf62010-03-19 15:32:17 +0000212 * @param file : XML file path
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +0000213 * @param constructor DocumentBuilder get from xerces
214 * @return Document which describes this file
215 * @throws MojoExecutionException occurs when the given file cannot be opened or is a valid XML file.
216 */
217 private Document parseFile( File file, DocumentBuilder constructor ) throws MojoExecutionException
218 {
219 if ( constructor == null )
220 {
221 return null;
222 }
223 // The document is the root of the DOM tree.
224 File targetFile = file.getAbsoluteFile();
225 getLog().info( "Parsing " + targetFile );
226 Document doc = null;
227 try
228 {
229 doc = constructor.parse( targetFile );
230 }
231 catch ( SAXException e )
232 {
233 getLog().error( "Cannot parse " + targetFile + " : " + e.getMessage() );
234 throw new MojoExecutionException( "Cannot parse " + targetFile + " : " + e.getMessage() );
235 }
236 catch ( IOException e )
237 {
238 getLog().error( "Cannot open " + targetFile + " : " + e.getMessage() );
239 throw new MojoExecutionException( "Cannot open " + targetFile + " : " + e.getMessage() );
240 }
241 return doc;
242 }
243
244
245 /**
246 * write a Node in a xml file.
Carsten Ziegeler0a4eff12015-05-12 06:04:41 +0000247 *
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +0000248 * @param outputFilename URI to the output file
249 * @param treeToBeWrite Node root of the tree to be write in file
250 * @throws MojoExecutionException if the plugin failed
251 */
252 private void writeToFile( URI outputFilename, Node treeToBeWrite ) throws MojoExecutionException
253 {
254 // init the transformer
255 Transformer transformer = null;
256 TransformerFactory tfabrique = TransformerFactory.newInstance();
257 try
258 {
259 transformer = tfabrique.newTransformer();
260 }
261 catch ( TransformerConfigurationException e )
262 {
263 getLog().error( "Unable to write to file: " + outputFilename.toString() );
264 throw new MojoExecutionException( "Unable to write to file: " + outputFilename.toString() + " : "
265 + e.getMessage() );
266 }
267 Properties proprietes = new Properties();
268 proprietes.put( "method", "xml" );
269 proprietes.put( "version", "1.0" );
270 proprietes.put( "encoding", "ISO-8859-1" );
271 proprietes.put( "standalone", "yes" );
272 proprietes.put( "indent", "yes" );
273 proprietes.put( "omit-xml-declaration", "no" );
274 transformer.setOutputProperties( proprietes );
275
276 DOMSource input = new DOMSource( treeToBeWrite );
277
Stuart McCulloch88129022009-09-03 02:52:58 +0000278 File fichier = null;
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +0000279 FileOutputStream flux = null;
280 try
281 {
Stuart McCulloch88129022009-09-03 02:52:58 +0000282 fichier = File.createTempFile( "repository", ".xml" );
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +0000283 flux = new FileOutputStream( fichier );
284 }
Stuart McCulloch88129022009-09-03 02:52:58 +0000285 catch ( IOException e )
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +0000286 {
287 getLog().error( "Unable to write to file: " + fichier.getName() );
288 throw new MojoExecutionException( "Unable to write to file: " + fichier.getName() + " : " + e.getMessage() );
289 }
290 Result output = new StreamResult( flux );
291 try
292 {
293 transformer.transform( input, output );
294 }
295 catch ( TransformerException e )
296 {
297 throw new MojoExecutionException( "Unable to write to file: " + outputFilename.toString() + " : "
298 + e.getMessage() );
299 }
300
301 try
302 {
303 flux.flush();
304 flux.close();
Stuart McCulloch88129022009-09-03 02:52:58 +0000305
306 FileUtils.rename( fichier, new File( outputFilename ) );
Stuart McCullochbb8b9fa2008-02-17 16:07:14 +0000307 }
308 catch ( IOException e )
309 {
310 throw new MojoExecutionException( "IOException when closing file : " + e.getMessage() );
311 }
312 }
313}