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