View Javadoc

1   package org.apache.maven.release;
2   
3   /* ====================================================================
4    *   Copyright 2001-2004 The Apache Software Foundation.
5    *
6    *   Licensed under the Apache License, Version 2.0 (the "License");
7    *   you may not use this file except in compliance with the License.
8    *   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, software
13   *   distributed under the License is distributed on an "AS IS" BASIS,
14   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *   See the License for the specific language governing permissions and
16   *   limitations under the License.
17   * ====================================================================
18   */
19  
20  import java.io.File;
21  import java.io.FileOutputStream;
22  import java.io.OutputStream;
23  import java.io.PrintStream;
24  import java.util.ArrayList;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Map;
28  
29  import org.apache.commons.io.FileUtils;
30  import org.dom4j.Document;
31  import org.dom4j.Namespace;
32  import org.dom4j.Node;
33  import org.dom4j.io.OutputFormat;
34  import org.dom4j.io.SAXReader;
35  import org.dom4j.io.XMLWriter;
36  import org.jaxen.XPath;
37  import org.jaxen.dom4j.Dom4jXPath;
38  import org.xml.sax.Attributes;
39  import org.xml.sax.SAXException;
40  import org.xml.sax.helpers.XMLFilterImpl;
41  
42  /**
43   * This is the base class for any tool that attempts to transform fields
44   * in the POM. Currently we are using the XML form of the POM and using Jaxen
45   * but eventually we will be able to perform the same transformations on
46   * POM beans. Jaxen needs to be modified and some serious cleanup needs to
47   * go on in Maven internally, but this will serve as a start. An attempt is
48   * made to make this tool GUI friendly.
49   *
50   * @author <a href="mailto:jason@zenplex.com">Jason van Zyl</a>
51   *
52   * @version $Id: AbstractPomTransformer.java 356373 2005-12-12 21:02:38Z fgiust $
53   */
54  public abstract class AbstractPomTransformer
55      implements PomTransformer
56  {
57      /** POM document */
58      private File project;
59  
60      /** Dom4j document. */
61      private Document document;
62  
63      /** Output file. */
64      private File outputFile;
65  
66      /** Properties used in transformNode */
67      private Map variables;
68  
69      /** Nodes selected for transformation using xpath. */
70      private List selectedNodes;
71  
72      private List transformations;
73  
74      // -------------------------------------------------------------------------
75      // Accessors
76      // -------------------------------------------------------------------------
77  
78      /**
79       *
80       * @return
81       */
82      public Map getVariables()
83      {
84          return variables;
85      }
86  
87      /**
88       *
89       * @param variables
90       */
91      public void setVariables( Map variables )
92      {
93          this.variables = variables;
94      }
95  
96      /**
97       *
98       * @param project
99       */
100     public void setProject( File project )
101     {
102         this.project = project;
103     }
104 
105     /**
106      *
107      * @return
108      */
109     public File getProject()
110     {
111         return project;
112     }
113 
114     /**
115      *
116      * @return
117      */
118     public Document getDocument()
119     {
120         return document;
121     }
122 
123     /**
124      *
125      * @param document
126      */
127     public void setDocument( Document document )
128     {
129         this.document = document;
130     }
131 
132     /**
133      *
134      * @return
135      */
136     public File getOutputFile()
137     {
138         return outputFile;
139     }
140 
141     /**
142      *
143      * @param outputFile
144      */
145     public void setOutputFile( File outputFile )
146     {
147         this.outputFile = outputFile;
148     }
149 
150     /**
151      *
152      * @return
153      */
154     public List getSelectedNodes()
155     {
156         if ( selectedNodes == null )
157         {
158             try
159             {
160                 selectNodes();
161             }
162             catch ( Exception e )
163             {
164                 // do nothing.
165             }
166         }
167         return selectedNodes;
168     }
169 
170     /**
171      *
172      * @param selectedNodes
173      */
174     public void setSelectedNodes( List selectedNodes )
175     {
176         this.selectedNodes = selectedNodes;
177     }
178 
179     /**
180      *
181      * @return
182      */
183     public int getSelectedNodeCount()
184     {
185         return getSelectedNodes().size();
186     }
187 
188     /**
189      *
190      * @return
191      */
192     public List getTransformations()
193     {
194         if ( transformations == null )
195         {
196             createTransformations();
197         }
198 
199         return transformations;
200     }
201 
202     /**
203      *
204      */
205     public void createTransformations()
206     {
207         transformations = new ArrayList();
208 
209         for ( Iterator i = getSelectedNodes().iterator(); i.hasNext(); )
210         {
211             Object o = i.next();
212 
213             if ( o instanceof Node )
214             {
215                 Transformation transformation = new Transformation( this );
216                 transformation.setNode( (Node) o );
217                 transformations.add( transformation );
218             }
219         }
220     }
221 
222     /**
223      * This is the automated way of transforming the nodes if there is
224      * no user interaction involved.
225      *
226      * @throws Exception If an error occurs while transforming the nodes.
227      */
228     public void transformNodes()
229         throws Exception
230     {
231         for ( Iterator i = getSelectedNodes().iterator(); i.hasNext(); )
232         {
233             Object o = i.next();
234 
235             if ( o instanceof Node )
236             {
237                 transformNode( (Node) o );
238             }
239         }
240     }
241 
242     // ----------------------------------------------------------------------
243     // Implementation
244     // ----------------------------------------------------------------------
245 
246     /**
247      *
248      * @return
249      */
250     public abstract String selectNodesXPathExpression();
251 
252     /**
253      *
254      * @param node
255      * @throws Exception
256      */
257     public abstract void transformNode( Node node )
258         throws Exception;
259 
260     /**
261      * Update the snapshot version identifiers with actual timestamp versions
262      * and write out the POM in its updated form.
263      *
264      * @throws Exception
265      */
266     public void selectNodes()
267         throws Exception
268     {
269         SAXReader reader = new SAXReader();
270 
271         // make xpath expressions worh with poms with or without namespace
272         reader.setXMLFilter( new XMLFilterImpl()
273         {
274 
275             public void endElement( String uri, String localName, String qName )
276                 throws SAXException
277             {
278                 super.endElement( "", localName, "" );
279             }
280 
281             public void startElement( String uri, String localName, String qName, Attributes atts )
282                 throws SAXException
283             {
284                 super.startElement( "", localName, "", atts );
285             }
286 
287         } );
288         setDocument( reader.read( getProject() ) );
289 
290         // The selecting nodes with the xpath expression will give us a list
291         // of dependencies elements where the version element is equal to 'SNAPSHOT'.
292         // So we can get any information we need, and alter anything we need to before writing
293         // the dom4j document back out.
294         XPath xpath = new Dom4jXPath( selectNodesXPathExpression() );
295         setSelectedNodes( xpath.selectNodes( getDocument() ) );
296     }
297 
298     /**
299      *
300      * @throws Exception
301      */
302     public void write()
303         throws Exception
304     {
305         write( null );
306     }
307 
308     /**
309      *
310      * @throws Exception
311      */
312     public void write( String encoding )
313         throws Exception
314     {
315         OutputStream os = null;
316 
317         if ( getOutputFile() != null )
318         {
319             // Backup the original first.
320             FileUtils.copyFile( getOutputFile(), new File( getOutputFile() + ".backup" ) );
321 
322             // Now hand of the os.
323             os = new FileOutputStream( getOutputFile() );
324         }
325         else
326         {
327             os = new PrintStream( System.out );
328         }
329 
330         OutputFormat format = new OutputFormat();
331         format.setIndentSize( 2 );
332         format.setNewlines( true );
333         format.setTrimText( true );
334         if ( encoding != null )
335         {
336             format.setEncoding( encoding );
337         }
338 
339         XMLWriter writer = new XMLWriter( format )
340         {
341             protected boolean isNamespaceDeclaration( Namespace ns )
342             {
343                 // this will filter out empty namespaces, only the correct POM ns is allowed
344                 return "http://maven.apache.org/POM/3.0.0".equals( ns.getURI() );
345             }
346         };
347 
348         writer.setOutputStream( os );
349         writer.write( getDocument() );
350         writer.flush();
351         writer.close();
352     }
353 }