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 }