1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.felix.obrplugin;
20
21
22 import java.io.BufferedReader;
23 import java.io.File;
24 import java.io.FileNotFoundException;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.InputStreamReader;
28 import java.net.MalformedURLException;
29 import java.net.URI;
30 import java.net.URL;
31 import java.text.SimpleDateFormat;
32 import java.util.ArrayList;
33 import java.util.Arrays;
34 import java.util.Date;
35 import java.util.List;
36 import java.util.Properties;
37 import java.util.regex.Matcher;
38 import java.util.regex.Pattern;
39
40 import javax.xml.parsers.DocumentBuilder;
41 import javax.xml.parsers.DocumentBuilderFactory;
42 import javax.xml.parsers.ParserConfigurationException;
43 import javax.xml.transform.Result;
44 import javax.xml.transform.Transformer;
45 import javax.xml.transform.TransformerConfigurationException;
46 import javax.xml.transform.TransformerException;
47 import javax.xml.transform.TransformerFactory;
48 import javax.xml.transform.dom.DOMSource;
49 import javax.xml.transform.stream.StreamResult;
50
51 import org.apache.maven.artifact.manager.WagonManager;
52 import org.apache.maven.artifact.repository.ArtifactRepository;
53 import org.apache.maven.plugin.AbstractMojo;
54 import org.apache.maven.plugin.MojoExecutionException;
55 import org.apache.maven.plugin.logging.Log;
56 import org.apache.maven.project.MavenProject;
57 import org.apache.maven.settings.Settings;
58 import org.w3c.dom.Document;
59 import org.w3c.dom.Element;
60 import org.w3c.dom.Node;
61 import org.w3c.dom.NodeList;
62 import org.xml.sax.SAXException;
63
64
65
66
67
68
69
70
71
72
73
74
75 public final class ObrRemoteClean extends AbstractMojo
76 {
77
78
79
80
81
82 private boolean ignoreLock;
83
84
85
86
87
88
89 private String prefixUrl;
90
91
92
93
94
95
96 private String remoteOBR;
97
98
99
100
101
102
103 private String obrRepository;
104
105
106
107
108
109
110 private List supportedProjectTypes = Arrays.asList( new String[]
111 { "jar", "bundle" } );
112
113
114
115
116
117 private ArtifactRepository deploymentRepository;
118
119
120
121
122
123
124 private String altDeploymentRepository;
125
126
127
128
129
130
131 private String obrDeploymentRepository;
132
133
134
135
136
137 private boolean interactive;
138
139
140
141
142
143
144
145
146 private MavenProject project;
147
148
149
150
151
152
153
154
155 private Settings settings;
156
157
158
159
160
161
162 private WagonManager m_wagonManager;
163
164
165 public void execute() throws MojoExecutionException
166 {
167 String projectType = project.getPackaging();
168
169
170 if ( !supportedProjectTypes.contains( projectType ) )
171 {
172 getLog().warn(
173 "Ignoring project type " + projectType + " - supportedProjectTypes = " + supportedProjectTypes );
174 return;
175 }
176 else if ( "NONE".equalsIgnoreCase( remoteOBR ) || "false".equalsIgnoreCase( remoteOBR ) )
177 {
178 getLog().info( "Remote OBR update disabled (enable with -DremoteOBR)" );
179 return;
180 }
181
182
183 if ( null == remoteOBR || remoteOBR.trim().length() == 0 || "true".equalsIgnoreCase( remoteOBR ) )
184 {
185 remoteOBR = obrRepository;
186 }
187
188 URI tempURI = ObrUtils.findRepositoryXml( "", remoteOBR );
189 String repositoryName = new File( tempURI.getSchemeSpecificPart() ).getName();
190
191 Log log = getLog();
192
193 RemoteFileManager remoteFile = new RemoteFileManager( m_wagonManager, settings, log );
194 openRepositoryConnection( remoteFile );
195 if ( null == prefixUrl )
196 {
197 prefixUrl = remoteFile.toString();
198 }
199
200
201 log.info( "LOCK " + remoteFile + '/' + repositoryName );
202 remoteFile.lockFile( repositoryName, ignoreLock );
203 File downloadedRepositoryXml = null;
204
205 try
206 {
207
208 log.info( "Downloading " + repositoryName );
209 downloadedRepositoryXml = remoteFile.get( repositoryName, ".xml" );
210
211 URI repositoryXml = downloadedRepositoryXml.toURI();
212
213 Config userConfig = new Config();
214 userConfig.setRemoteFile( true );
215
216
217 Document doc = parseFile( new File( repositoryXml ), initConstructor() );
218 Node finalDocument = cleanDocument( doc.getDocumentElement() );
219
220 if ( finalDocument == null )
221 {
222 getLog().info( "Nothing to clean in " + repositoryName );
223 }
224 else
225 {
226 writeToFile( repositoryXml, finalDocument );
227 getLog().info( "Repository " + repositoryName + " cleaned" );
228
229 log.info( "Uploading " + repositoryName );
230 remoteFile.put( downloadedRepositoryXml, repositoryName );
231 }
232 }
233 catch ( Exception e )
234 {
235 log.warn( "Exception while updating remote OBR: " + e.getLocalizedMessage(), e );
236 }
237 finally
238 {
239
240 log.info( "UNLOCK " + remoteFile + '/' + repositoryName );
241 remoteFile.unlockFile( repositoryName );
242 remoteFile.disconnect();
243
244 if ( null != downloadedRepositoryXml )
245 {
246 downloadedRepositoryXml.delete();
247 }
248 }
249 }
250
251 private static final Pattern ALT_REPO_SYNTAX_PATTERN = Pattern.compile( "(.+)::(.+)::(.+)" );
252
253
254 private void openRepositoryConnection( RemoteFileManager remoteFile ) throws MojoExecutionException
255 {
256
257 if ( obrDeploymentRepository != null )
258 {
259 altDeploymentRepository = obrDeploymentRepository;
260 }
261
262 if ( deploymentRepository == null && altDeploymentRepository == null )
263 {
264 String msg = "Deployment failed: repository element was not specified in the pom inside"
265 + " distributionManagement element or in -DaltDeploymentRepository=id::layout::url parameter";
266
267 throw new MojoExecutionException( msg );
268 }
269
270 if ( altDeploymentRepository != null )
271 {
272 getLog().info( "Using alternate deployment repository " + altDeploymentRepository );
273
274 Matcher matcher = ALT_REPO_SYNTAX_PATTERN.matcher( altDeploymentRepository );
275 if ( !matcher.matches() )
276 {
277 throw new MojoExecutionException( "Invalid syntax for alternative repository \""
278 + altDeploymentRepository + "\". Use \"id::layout::url\"." );
279 }
280
281 remoteFile.connect( matcher.group( 1 ).trim(), matcher.group( 3 ).trim() );
282 }
283 else
284 {
285 remoteFile.connect( deploymentRepository.getId(), deploymentRepository.getUrl() );
286 }
287 }
288
289
290
291
292
293
294
295
296 private Element cleanDocument( Element elem )
297 {
298 NodeList nodes = elem.getElementsByTagName( "resource" );
299 List toRemove = new ArrayList();
300
301
302 for ( int i = 0; i < nodes.getLength(); i++ )
303 {
304 Element n = ( Element ) nodes.item( i );
305 String value = n.getAttribute( "uri" );
306
307 URL url;
308 try
309 {
310 url = new URL( new URL( prefixUrl + '/' ), value );
311 }
312 catch ( MalformedURLException e )
313 {
314 getLog().error( "Malformed URL when creating the resource absolute URI : " + e.getMessage() );
315 return null;
316 }
317
318 try
319 {
320 url.openConnection().getContent();
321 }
322 catch ( IOException e )
323 {
324 getLog().info(
325 "The bundle " + n.getAttribute( "presentationname" ) + " - " + n.getAttribute( "version" )
326 + " will be removed : " + e.getMessage() );
327 toRemove.add( n );
328 }
329 }
330
331 Date d = new Date();
332 if ( toRemove.size() > 0 )
333 {
334 String answer = "y";
335 if ( interactive )
336 {
337 System.out.println( "Do you want to remove these bundles from the repository file [y/N]:" );
338 BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );
339
340 try
341 {
342 answer = br.readLine();
343 }
344 catch ( IOException ioe )
345 {
346 getLog().error( "IO error trying to read the user confirmation" );
347 return null;
348 }
349 }
350
351 if ( answer != null && answer.trim().equalsIgnoreCase( "y" ) )
352 {
353
354 for ( int i = 0; i < toRemove.size(); i++ )
355 {
356 elem.removeChild( ( Node ) toRemove.get( i ) );
357 }
358
359
360 SimpleDateFormat format = new SimpleDateFormat( "yyyyMMddHHmmss.SSS" );
361 d.setTime( System.currentTimeMillis() );
362 elem.setAttribute( "lastmodified", format.format( d ) );
363 return elem;
364 }
365 else
366 {
367 return null;
368 }
369 }
370
371 return null;
372 }
373
374
375
376
377
378
379
380
381 private DocumentBuilder initConstructor() throws MojoExecutionException
382 {
383 DocumentBuilder constructor = null;
384 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
385 try
386 {
387 constructor = factory.newDocumentBuilder();
388 }
389 catch ( ParserConfigurationException e )
390 {
391 getLog().error( "Unable to create a new xml document" );
392 throw new MojoExecutionException( "Cannot create the Document Builder : " + e.getMessage() );
393 }
394 return constructor;
395 }
396
397
398
399
400
401
402
403
404
405
406 private Document parseFile( File file, DocumentBuilder constructor ) throws MojoExecutionException
407 {
408 if ( constructor == null )
409 {
410 return null;
411 }
412
413 File targetFile = file.getAbsoluteFile();
414 getLog().info( "Parsing " + targetFile );
415 Document doc = null;
416 try
417 {
418 doc = constructor.parse( targetFile );
419 }
420 catch ( SAXException e )
421 {
422 getLog().error( "Cannot parse " + targetFile + " : " + e.getMessage() );
423 throw new MojoExecutionException( "Cannot parse " + targetFile + " : " + e.getMessage() );
424 }
425 catch ( IOException e )
426 {
427 getLog().error( "Cannot open " + targetFile + " : " + e.getMessage() );
428 throw new MojoExecutionException( "Cannot open " + targetFile + " : " + e.getMessage() );
429 }
430 return doc;
431 }
432
433
434
435
436
437
438
439
440
441 private void writeToFile( URI outputFilename, Node treeToBeWrite ) throws MojoExecutionException
442 {
443
444 Transformer transformer = null;
445 TransformerFactory tfabrique = TransformerFactory.newInstance();
446 try
447 {
448 transformer = tfabrique.newTransformer();
449 }
450 catch ( TransformerConfigurationException e )
451 {
452 getLog().error( "Unable to write to file: " + outputFilename.toString() );
453 throw new MojoExecutionException( "Unable to write to file: " + outputFilename.toString() + " : "
454 + e.getMessage() );
455 }
456 Properties proprietes = new Properties();
457 proprietes.put( "method", "xml" );
458 proprietes.put( "version", "1.0" );
459 proprietes.put( "encoding", "ISO-8859-1" );
460 proprietes.put( "standalone", "yes" );
461 proprietes.put( "indent", "yes" );
462 proprietes.put( "omit-xml-declaration", "no" );
463 transformer.setOutputProperties( proprietes );
464
465 DOMSource input = new DOMSource( treeToBeWrite );
466
467 File fichier = new File( outputFilename );
468 FileOutputStream flux = null;
469 try
470 {
471 flux = new FileOutputStream( fichier );
472 }
473 catch ( FileNotFoundException e )
474 {
475 getLog().error( "Unable to write to file: " + fichier.getName() );
476 throw new MojoExecutionException( "Unable to write to file: " + fichier.getName() + " : " + e.getMessage() );
477 }
478 Result output = new StreamResult( flux );
479 try
480 {
481 transformer.transform( input, output );
482 }
483 catch ( TransformerException e )
484 {
485 throw new MojoExecutionException( "Unable to write to file: " + outputFilename.toString() + " : "
486 + e.getMessage() );
487 }
488
489 try
490 {
491 flux.flush();
492 flux.close();
493 }
494 catch ( IOException e )
495 {
496 throw new MojoExecutionException( "IOException when closing file : " + e.getMessage() );
497 }
498 }
499 }