View Javadoc
1   package org.codehaus.mojo.natives;
2   
3   /*
4    * The MIT License
5    *
6    * Copyright (c) 2004, The Codehaus
7    *
8    * Permission is hereby granted, free of charge, to any person obtaining a copy of
9    * this software and associated documentation files (the "Software"), to deal in
10   * the Software without restriction, including without limitation the rights to
11   * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12   * of the Software, and to permit persons to whom the Software is furnished to do
13   * so, subject to the following conditions:
14   * 
15   * The above copyright notice and this permission notice shall be included in all
16   * copies or substantial portions of the Software.
17   * 
18   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24   * SOFTWARE.
25   */
26  
27  import org.codehaus.mojo.natives.parser.Parser;
28  
29  import java.util.Iterator;
30  import java.util.ArrayList;
31  
32  import java.io.BufferedReader;
33  import java.io.File;
34  import java.io.FileReader;
35  import java.io.IOException;
36  import java.io.Reader;
37  
38  /**
39   * Dependency analizer of a native source file
40   * 
41   * @author <a href="mailto:dantran@gmail.com">Dan Tran</a>
42   * @version $Id$
43   */
44  
45  public class Dependency
46  {
47      /**
48       * Field source
49       */
50      private String source;
51  
52      /**
53       * Field lastModified
54       */
55      private long lastModified = 0;
56  
57      /**
58       * Field dependencies
59       */
60      private java.util.List dependencies;
61  
62      private Parser parser;
63  
64      private File[] includePaths;
65  
66      Dependency parent;
67  
68      public Dependency( Dependency parent, File source, Parser parser, File[] includePaths )
69      {
70          init( parent, source, parser, includePaths );
71      }
72  
73      public Dependency( File source, Parser parser, File[] includePaths )
74      {
75          init( null, source, parser, includePaths );
76      }
77  
78      private void init( Dependency parent, File source, Parser parser, File[] includePaths )
79      {
80          this.parent = parent;
81  
82          this.source = source.getPath();
83  
84          this.lastModified = source.lastModified();
85  
86          this.parser = parser;
87  
88          if ( includePaths == null )
89          {
90              this.includePaths = new File[0];
91          }
92          else
93          {
94              this.includePaths = includePaths;
95          }
96      }
97  
98      public void analyze()
99          throws IOException
100     {
101         String[] includeNames = getIncludeNames();
102 
103         File[] resolvedIncludeFiles = resolveIncludeNames( includeNames );
104 
105         for ( int i = 0; i < resolvedIncludeFiles.length; ++i )
106         {
107             File fileName = resolvedIncludeFiles[i];
108 
109             Dependency depend = new Dependency( this, fileName, this.parser, this.includePaths );
110 
111             if ( !this.getRoot().contains( depend ) )
112             {
113                 this.addDependency( depend );
114             }
115         }
116 
117         for ( int i = 0; i < this.getDependencies().size(); ++i )
118         {
119             Dependency depend = (Dependency) this.getDependencies().get( i );
120             depend.analyze();
121         }
122 
123     }
124 
125     private Dependency getRoot()
126     {
127         Dependency root = this;
128 
129         while ( root.getParent() != null )
130         {
131             root = root.getParent();
132         }
133 
134         return root;
135     }
136 
137     public Dependency getParent()
138     {
139         return this.parent;
140     }
141 
142     public long getCompositeLastModified()
143     {
144         long currentLastModify = this.lastModified;
145 
146         Iterator iterator = this.getDependencies().iterator();
147 
148         while ( iterator.hasNext() )
149         {
150             Dependency dependency = (Dependency) iterator.next();
151 
152             long lastModified = dependency.getCompositeLastModified();
153 
154             if ( lastModified > currentLastModify )
155             {
156                 currentLastModify = lastModified;
157             }
158         }
159 
160         return currentLastModify;
161     }
162 
163     private String[] getIncludeNames()
164         throws IOException
165     {
166         Reader reader = null;
167 
168         try
169         {
170             reader = new BufferedReader( new FileReader( this.source ) );
171             parser.parse( reader );
172 
173             return parser.getIncludes();
174         }
175         finally
176         {
177             if ( reader != null )
178             {
179                 reader.close();
180             }
181         }
182     }
183 
184     /**
185      * @param includeNames
186      * @return
187      * @throws IOException
188      */
189     private File[] resolveIncludeNames( String[] includeNames )
190         throws IOException
191     {
192         ArrayList resolvedIncludeFiles = new ArrayList( includeNames.length );
193 
194         for ( int i = 0; i < includeNames.length; ++i )
195         {
196             File resolvedFile = resolveSingleIncludeName( includeNames[i] );
197 
198             if ( resolvedFile != null )
199             {
200                 resolvedIncludeFiles.add( resolvedFile );
201             }
202         }
203 
204         File[] arrayResolvedIncludeFiles = new File[resolvedIncludeFiles.size()];
205 
206         for ( int j = 0; j < arrayResolvedIncludeFiles.length; ++j )
207         {
208             arrayResolvedIncludeFiles[j] = (File) resolvedIncludeFiles.get( j );
209         }
210 
211         return arrayResolvedIncludeFiles;
212     }
213 
214     /**
215      * Search for file that matches an include name with all available include paths
216      * 
217      * @param includeName
218      * @return an file or null when it is not found in user include path
219      * @throws IOException
220      */
221 
222     private File resolveSingleIncludeName( String includeName )
223         throws IOException
224     {
225         File includeFile = null;
226 
227         File[] sourcePath = new File[1];
228 
229         sourcePath[0] = new File( new File( this.source ).getParent() ); // TODO
230 
231         includeFile = this.resolveSingleIncludeNameFromPaths( includeName, sourcePath );
232 
233         if ( includeFile == null )
234         {
235             includeFile = this.resolveSingleIncludeNameFromPaths( includeName, this.includePaths );
236         }
237 
238         return includeFile;
239     }
240 
241     /**
242      * Translate an include file
243      * 
244      * @param includeName
245      * @param includePath
246      * @return
247      * @throws IOException
248      */
249     private File resolveSingleIncludeNameFromPaths( String includeName, File[] includePath )
250         throws IOException
251     {
252         File includeFile = null;
253 
254         for ( int i = 0; i < includePath.length; i++ )
255         {
256             File tmpFile = new File( includePath[i], includeName );
257 
258             // make sure we dont pickup directory like STL which has no extension
259             if ( tmpFile.exists() && tmpFile.isFile() )
260             {
261                 includeFile = tmpFile;
262 
263                 break;
264             }
265         }
266 
267         return includeFile;
268     }
269 
270     /**
271      * Method addDependency
272      * 
273      * @param dependency
274      */
275     public void addDependency( Dependency dependency )
276     {
277         getDependencies().add( dependency );
278     }
279 
280     /**
281      * Method getDependencies
282      */
283     public java.util.List getDependencies()
284     {
285         if ( this.dependencies == null )
286         {
287             this.dependencies = new java.util.ArrayList();
288         }
289 
290         return this.dependencies;
291     }
292 
293     /**
294      * Method getLastModified
295      */
296     public long getLastModified()
297     {
298         return this.lastModified;
299     }
300 
301     /**
302      * Method getSource
303      */
304     public String getSource()
305     {
306         return this.source;
307     }
308 
309     // helper for testing only
310     boolean contains( Dependency dependent )
311     {
312         if ( this.source.equals( dependent.getSource() ) )
313         {
314             return true;
315         }
316 
317         for ( int i = 0; i < this.getDependencies().size(); ++i )
318         {
319             Dependency node = (Dependency) this.getDependencies().get( i );
320             if ( node.contains( dependent ) )
321             {
322                 return true;
323             }
324         }
325 
326         return false;
327     }
328 
329     int getDeepDependencyCount()
330     {
331         int ret = this.getDependencies().size();
332         for ( int i = 0; i < this.getDependencies().size(); ++i )
333         {
334             Dependency node = (Dependency) this.getDependencies().get( i );
335             ret += node.getDeepDependencyCount();
336         }
337 
338         return ret;
339     }
340 }