View Javadoc
1   package org.apache.maven.shared.release.util;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  
25  import org.apache.maven.model.Model;
26  import org.apache.maven.model.Parent;
27  import org.apache.maven.model.io.xpp3.MavenXpp3Reader;
28  import org.codehaus.plexus.logging.Logger;
29  import org.codehaus.plexus.util.IOUtil;
30  import org.codehaus.plexus.util.ReaderFactory;
31  import org.codehaus.plexus.util.xml.XmlStreamReader;
32  import org.codehaus.plexus.util.xml.pull.XmlPullParserException;
33  
34  /**
35   * <p>This utility class helps with finding a maven pom file
36   * which got parsed previously. It uses the fact that the
37   * combination of any parent ids plus the ids of the current
38   * pom itself is unique.</p>
39   * <p>This is e.g. needed for SCM systems which do not support
40   * sparse checkout but only can checkout the repository as whole
41   * like e.g. GIT. If the module which we are going to release is
42   * not in the parent directory, we first need to search for the
43   * 'right' sub directory in this case.
44   * subdirectory </p>
45   *
46   * <h3>Usage:</h3>
47   * <p>PomFinder is a statefull class. One instance of this class intended
48   * for a singular use! You need to create a new instance if you like
49   * to search for another pom.</p
50   * <ol>
51   *   <li>
52   *     Parse an origin pom in a given directory with {@link #parsePom(java.io.File)}
53   *     This will act as the information about what to search for.
54   *   </li>
55   *   <li>
56   *      Search for the matching pom in a given tree using
57   *      {@link #findMatchingPom(java.io.File)}
58   *   </li>
59   * </ol>
60   *
61   * @author <a href="mailto:struberg@yahoo.de">Mark Struberg</a>
62   */
63  public class PomFinder
64  {
65  
66      private Logger log;
67      private PomInfo foundPomInfo;
68  
69      public PomFinder( Logger log )
70      {
71          this.log = log;
72      }
73  
74      /**
75       *
76       * @param originPom the pom File which should be used as blueprint for the search
77       * @return <code>true</code> if a pom got parsed successfully, <code>false</code> otherwise
78       */
79      public boolean parsePom( File originPom )
80      {
81          if ( !originPom.exists() )
82          {
83              return false;
84          }
85  
86          try
87          {
88              foundPomInfo = readPomInfo( originPom );
89          }
90          catch ( Exception e )
91          {
92              log.warn( "Error while parsing pom file", e );
93              return false;
94          }
95  
96          return foundPomInfo != null;
97      }
98  
99      /**
100      * Search for the previously with {@link #parsePom(java.io.File)}
101      * parsed pom in the given directory.
102      * @param startDirectory
103      * @return the pom file which matches the previously parsed pom or <code>null</code>
104      *         if no matching pom file could have been found.
105      */
106     public File findMatchingPom( File startDirectory )
107     {
108         if ( !startDirectory.exists() )
109         {
110             return null;
111         }
112 
113         if ( !startDirectory.isDirectory() )
114         {
115             log.error( "PomFinder must be started with a directory! Got " + startDirectory.getAbsolutePath() );
116             return null;
117         }
118 
119         if ( foundPomInfo == null )
120         {
121             log.error( "Please run parsePom first!" );
122             return null;
123         }
124 
125         // look for the file in the current directory
126         File matchingPom = new File( startDirectory, foundPomInfo.getFileName() );
127         if ( matchingPom.exists() )
128         {
129             PomInfo pi = null;
130             try
131             {
132                 pi = readPomInfo( matchingPom );
133             }
134             catch ( Exception e )
135             {
136                 log.warn( "Error while parsing pom file", e );
137                 // do nothing, just continue with the search
138                 // this might happen if a build contains unfinished pom.xml
139                 // files in integration tests, etc
140             }
141 
142             if  ( pi == null || !pi.equals( foundPomInfo ) )
143             {
144                 matchingPom = null;
145             }
146         }
147         else
148         {
149             matchingPom = null;
150         }
151 
152         if ( matchingPom == null )
153         {
154             String[] childFiles = startDirectory.list();
155             for ( int i = 0; i < childFiles.length; i++ )
156             {
157                 String childFile = childFiles[ i ];
158 
159                 File subDir = new File( startDirectory, childFile );
160                 if ( subDir.isDirectory() && !subDir.isHidden() )
161                 {
162                     matchingPom = findMatchingPom( subDir );
163                 }
164 
165                 if ( matchingPom != null )
166                 {
167                     break;
168                 }
169             }
170         }
171 
172         return matchingPom;
173     }
174 
175 
176     /**
177      * Read the {@link PomInfo} from the given pom file
178      * @param pomFile pom.xml file
179      * @return the PomInfo or <code>null</code
180      */
181     private PomInfo readPomInfo( File pomFile )
182             throws IOException, XmlPullParserException
183     {
184         if ( !pomFile.exists() || !pomFile.isFile() )
185         {
186             return null;
187         }
188 
189         PomInfo pomInfo = null;
190 
191         MavenXpp3Reader reader = new MavenXpp3Reader();
192         XmlStreamReader xmlReader = null;
193         Model model = null;
194         try
195         {
196             xmlReader = ReaderFactory.newXmlReader( pomFile );
197             model = reader.read( xmlReader );
198         }
199         finally
200         {
201             IOUtil.close( xmlReader );
202         }
203         if ( model != null )
204         {
205             pomInfo = new PomInfo();
206             pomInfo.setArtifactId( model.getArtifactId() );
207             pomInfo.setGroupId( model.getGroupId() );
208 
209             Parent parent = model.getParent();
210             if ( parent != null )
211             {
212                 pomInfo.setParentArtifactId( parent.getArtifactId() );
213                 pomInfo.setParentGroupId( parent.getGroupId() );
214             }
215 
216             pomInfo.setFileName( pomFile.getName() );
217         }
218         return pomInfo;
219     }
220 
221     /***
222      * Data container which helds information about a pom.
223      * Information may partially be empty.
224      */
225     private static class PomInfo
226     {
227         private String fileName;
228         private String artifactId;
229         private String groupId;
230         private String parentArtifactId;
231         private String parentGroupId;
232 
233         public String getFileName()
234         {
235             return fileName;
236         }
237 
238         public void setFileName( String fileName )
239         {
240             this.fileName = fileName;
241         }
242 
243         public String getArtifactId()
244         {
245             return artifactId;
246         }
247 
248         public void setArtifactId( String artifactId )
249         {
250             this.artifactId = artifactId;
251         }
252 
253         public String getGroupId()
254         {
255             return groupId;
256         }
257 
258         public void setGroupId( String groupId )
259         {
260             this.groupId = groupId;
261         }
262 
263         public String getParentArtifactId()
264         {
265             return parentArtifactId;
266         }
267 
268         public void setParentArtifactId( String parentArtifactId )
269         {
270             this.parentArtifactId = parentArtifactId;
271         }
272 
273         public String getParentGroupId()
274         {
275             return parentGroupId;
276         }
277 
278         public void setParentGroupId( String parentGroupId )
279         {
280             this.parentGroupId = parentGroupId;
281         }
282 
283         public boolean equals( Object o )
284         {
285             if ( this == o )
286             {
287                 return true;
288             }
289 
290             if ( o == null || getClass() != o.getClass() )
291             {
292                 return false;
293             }
294 
295             PomInfo pomInfo = (PomInfo) o;
296 
297             if ( artifactId != null ? !artifactId.equals( pomInfo.artifactId ) : pomInfo.artifactId != null )
298             {
299                 return false;
300             }
301             if ( groupId != null ? !groupId.equals( pomInfo.groupId ) : pomInfo.groupId != null )
302             {
303                 return false;
304             }
305             if ( parentArtifactId != null ? !parentArtifactId.equals( pomInfo.parentArtifactId )
306                             : pomInfo.parentArtifactId != null )
307             {
308                 return false;
309             }
310             if ( parentGroupId != null ? !parentGroupId.equals( pomInfo.parentGroupId ) : pomInfo.parentGroupId != null )
311             {
312                 return false;
313             }
314 
315             return true;
316         }
317 
318         public int hashCode()
319         {
320             int result = artifactId != null ? artifactId.hashCode() : 0;
321             result = 31 * result + ( groupId != null ? groupId.hashCode() : 0 );
322             result = 31 * result + ( parentArtifactId != null ? parentArtifactId.hashCode() : 0 );
323             result = 31 * result + ( parentGroupId != null ? parentGroupId.hashCode() : 0 );
324             return result;
325         }
326     }
327 }