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
138
139
140 private MavenProject project;
141
142
143
144
145
146
147
148
149 private Settings settings;
150
151
152
153
154
155
156 private WagonManager m_wagonManager;
157
158
159 public void execute() throws MojoExecutionException
160 {
161 String projectType = project.getPackaging();
162
163
164 if ( !supportedProjectTypes.contains( projectType ) )
165 {
166 getLog().warn(
167 "Ignoring project type " + projectType + " - supportedProjectTypes = " + supportedProjectTypes );
168 return;
169 }
170 else if ( "NONE".equalsIgnoreCase( remoteOBR ) || "false".equalsIgnoreCase( remoteOBR ) )
171 {
172 getLog().info( "Remote OBR update disabled (enable with -DremoteOBR)" );
173 return;
174 }
175
176
177 if ( null == remoteOBR || remoteOBR.trim().length() == 0 || "true".equalsIgnoreCase( remoteOBR ) )
178 {
179 remoteOBR = obrRepository;
180 }
181
182 URI tempURI = ObrUtils.findRepositoryXml( "", remoteOBR );
183 String repositoryName = new File( tempURI.getSchemeSpecificPart() ).getName();
184
185 Log log = getLog();
186
187 RemoteFileManager remoteFile = new RemoteFileManager( m_wagonManager, settings, log );
188 openRepositoryConnection( remoteFile );
189 if ( null == prefixUrl )
190 {
191 prefixUrl = remoteFile.toString();
192 }
193
194
195 log.info( "LOCK " + remoteFile + '/' + repositoryName );
196 remoteFile.lockFile( repositoryName, ignoreLock );
197 File downloadedRepositoryXml = null;
198
199 try
200 {
201
202 log.info( "Downloading " + repositoryName );
203 downloadedRepositoryXml = remoteFile.get( repositoryName, ".xml" );
204
205 URI repositoryXml = downloadedRepositoryXml.toURI();
206
207 Config userConfig = new Config();
208 userConfig.setRemoteFile( true );
209
210
211 Document doc = parseFile( new File( repositoryXml ), initConstructor() );
212 Node finalDocument = cleanDocument( doc.getDocumentElement() );
213
214 if ( finalDocument == null )
215 {
216 getLog().info( "Nothing to clean in " + repositoryName );
217 }
218 else
219 {
220 writeToFile( repositoryXml, finalDocument );
221 getLog().info( "Repository " + repositoryName + " cleaned" );
222
223 log.info( "Uploading " + repositoryName );
224 remoteFile.put( downloadedRepositoryXml, repositoryName );
225 }
226 }
227 catch ( Exception e )
228 {
229 log.warn( "Exception while updating remote OBR: " + e.getLocalizedMessage(), e );
230 }
231 finally
232 {
233
234 log.info( "UNLOCK " + remoteFile + '/' + repositoryName );
235 remoteFile.unlockFile( repositoryName );
236 remoteFile.disconnect();
237
238 if ( null != downloadedRepositoryXml )
239 {
240 downloadedRepositoryXml.delete();
241 }
242 }
243 }
244
245 private static final Pattern ALT_REPO_SYNTAX_PATTERN = Pattern.compile( "(.+)::(.+)::(.+)" );
246
247
248 private void openRepositoryConnection( RemoteFileManager remoteFile ) throws MojoExecutionException
249 {
250
251 if ( obrDeploymentRepository != null )
252 {
253 altDeploymentRepository = obrDeploymentRepository;
254 }
255
256 if ( deploymentRepository == null && altDeploymentRepository == null )
257 {
258 String msg = "Deployment failed: repository element was not specified in the pom inside"
259 + " distributionManagement element or in -DaltDeploymentRepository=id::layout::url parameter";
260
261 throw new MojoExecutionException( msg );
262 }
263
264 if ( altDeploymentRepository != null )
265 {
266 getLog().info( "Using alternate deployment repository " + altDeploymentRepository );
267
268 Matcher matcher = ALT_REPO_SYNTAX_PATTERN.matcher( altDeploymentRepository );
269 if ( !matcher.matches() )
270 {
271 throw new MojoExecutionException( "Invalid syntax for alternative repository \""
272 + altDeploymentRepository + "\". Use \"id::layout::url\"." );
273 }
274
275 remoteFile.connect( matcher.group( 1 ).trim(), matcher.group( 3 ).trim() );
276 }
277 else
278 {
279 remoteFile.connect( deploymentRepository.getId(), deploymentRepository.getUrl() );
280 }
281 }
282
283
284
285
286
287
288
289
290 private Element cleanDocument( Element elem )
291 {
292 NodeList nodes = elem.getElementsByTagName( "resource" );
293 List toRemove = new ArrayList();
294
295
296 for ( int i = 0; i < nodes.getLength(); i++ )
297 {
298 Element n = ( Element ) nodes.item( i );
299 String value = n.getAttribute( "uri" );
300
301 URL url;
302 try
303 {
304 url = new URL( new URL( prefixUrl + '/' ), value );
305 }
306 catch ( MalformedURLException e )
307 {
308 getLog().error( "Malformed URL when creating the resource absolute URI : " + e.getMessage() );
309 return null;
310 }
311
312 try
313 {
314 url.openConnection().getContent();
315 }
316 catch ( IOException e )
317 {
318 getLog().info(
319 "The bundle " + n.getAttribute( "presentationname" ) + " - " + n.getAttribute( "version" )
320 + " will be removed : " + e.getMessage() );
321 toRemove.add( n );
322 }
323 }
324
325 Date d = new Date();
326 if ( toRemove.size() > 0 )
327 {
328 System.out.println( "Do you want to remove these bundles from the repository file [y/N]:" );
329 BufferedReader br = new BufferedReader( new InputStreamReader( System.in ) );
330 String answer = null;
331
332 try
333 {
334 answer = br.readLine();
335 }
336 catch ( IOException ioe )
337 {
338 getLog().error( "IO error trying to read the user confirmation" );
339 return null;
340 }
341
342 if ( answer != null && answer.trim().equalsIgnoreCase( "y" ) )
343 {
344
345 for ( int i = 0; i < toRemove.size(); i++ )
346 {
347 elem.removeChild( ( Node ) toRemove.get( i ) );
348 }
349
350
351 SimpleDateFormat format = new SimpleDateFormat( "yyyyMMddHHmmss.SSS" );
352 d.setTime( System.currentTimeMillis() );
353 elem.setAttribute( "lastmodified", format.format( d ) );
354 return elem;
355 }
356 else
357 {
358 return null;
359 }
360 }
361
362 return null;
363 }
364
365
366
367
368
369
370
371
372 private DocumentBuilder initConstructor() throws MojoExecutionException
373 {
374 DocumentBuilder constructor = null;
375 DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
376 try
377 {
378 constructor = factory.newDocumentBuilder();
379 }
380 catch ( ParserConfigurationException e )
381 {
382 getLog().error( "Unable to create a new xml document" );
383 throw new MojoExecutionException( "Cannot create the Document Builder : " + e.getMessage() );
384 }
385 return constructor;
386 }
387
388
389
390
391
392
393
394
395
396
397 private Document parseFile( File file, DocumentBuilder constructor ) throws MojoExecutionException
398 {
399 if ( constructor == null )
400 {
401 return null;
402 }
403
404 File targetFile = file.getAbsoluteFile();
405 getLog().info( "Parsing " + targetFile );
406 Document doc = null;
407 try
408 {
409 doc = constructor.parse( targetFile );
410 }
411 catch ( SAXException e )
412 {
413 getLog().error( "Cannot parse " + targetFile + " : " + e.getMessage() );
414 throw new MojoExecutionException( "Cannot parse " + targetFile + " : " + e.getMessage() );
415 }
416 catch ( IOException e )
417 {
418 getLog().error( "Cannot open " + targetFile + " : " + e.getMessage() );
419 throw new MojoExecutionException( "Cannot open " + targetFile + " : " + e.getMessage() );
420 }
421 return doc;
422 }
423
424
425
426
427
428
429
430
431
432 private void writeToFile( URI outputFilename, Node treeToBeWrite ) throws MojoExecutionException
433 {
434
435 Transformer transformer = null;
436 TransformerFactory tfabrique = TransformerFactory.newInstance();
437 try
438 {
439 transformer = tfabrique.newTransformer();
440 }
441 catch ( TransformerConfigurationException e )
442 {
443 getLog().error( "Unable to write to file: " + outputFilename.toString() );
444 throw new MojoExecutionException( "Unable to write to file: " + outputFilename.toString() + " : "
445 + e.getMessage() );
446 }
447 Properties proprietes = new Properties();
448 proprietes.put( "method", "xml" );
449 proprietes.put( "version", "1.0" );
450 proprietes.put( "encoding", "ISO-8859-1" );
451 proprietes.put( "standalone", "yes" );
452 proprietes.put( "indent", "yes" );
453 proprietes.put( "omit-xml-declaration", "no" );
454 transformer.setOutputProperties( proprietes );
455
456 DOMSource input = new DOMSource( treeToBeWrite );
457
458 File fichier = new File( outputFilename );
459 FileOutputStream flux = null;
460 try
461 {
462 flux = new FileOutputStream( fichier );
463 }
464 catch ( FileNotFoundException e )
465 {
466 getLog().error( "Unable to write to file: " + fichier.getName() );
467 throw new MojoExecutionException( "Unable to write to file: " + fichier.getName() + " : " + e.getMessage() );
468 }
469 Result output = new StreamResult( flux );
470 try
471 {
472 transformer.transform( input, output );
473 }
474 catch ( TransformerException e )
475 {
476 throw new MojoExecutionException( "Unable to write to file: " + outputFilename.toString() + " : "
477 + e.getMessage() );
478 }
479
480 try
481 {
482 flux.flush();
483 flux.close();
484 }
485 catch ( IOException e )
486 {
487 throw new MojoExecutionException( "IOException when closing file : " + e.getMessage() );
488 }
489 }
490 }