View Javadoc

1   package org.apache.maven.plugin.resource.loader;
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.BufferedInputStream;
23  import java.io.File;
24  import java.io.FileInputStream;
25  import java.io.FileNotFoundException;
26  import java.io.InputStream;
27  import java.util.Hashtable;
28  import java.util.Vector;
29  
30  import org.apache.commons.collections.ExtendedProperties;
31  import org.apache.velocity.exception.ResourceNotFoundException;
32  import org.apache.velocity.runtime.resource.Resource;
33  import org.apache.velocity.runtime.resource.loader.ResourceLoader;
34  import org.apache.velocity.util.StringUtils;
35  
36  /**
37   * Resource Loader for external projects.
38   * 
39   * @version $Id: ProjectResourceLoader.html 816584 2012-05-08 12:33:35Z hboutemy $
40   */
41  public class ProjectResourceLoader
42      extends ResourceLoader
43  {
44      /**
45       * The paths to search for templates.
46       */
47      private Vector paths = null;
48  
49      /**
50       * Used to map the path that a template was found on
51       * so that we can properly check the modification
52       * times of the files.
53       */
54      private Hashtable templatePaths = new Hashtable();
55  
56      public void init( ExtendedProperties configuration )
57      {
58          rsvc.info( "ProjectResourceLoader : initialization starting." );
59  
60          String separator = System.getProperty( "file.separator" );
61  
62          String path = System.getProperty( "user.dir" ) + separator + "src" + separator + "main" + separator
63              + "resources" + separator;
64  
65          rsvc.info( "path :" + path );
66  
67          paths = new Vector();
68  
69          paths.add( path );
70  
71          int sz = paths.size();
72  
73          for ( int i = 0; i < sz; i++ )
74          {
75              rsvc.info( "ProjectResourceLoader : adding path '" + (String) paths.get( i ) + "'" );
76          }
77          rsvc.info( "ProjectResourceLoader : initialization complete." );
78      }
79  
80      /**
81       * Get an InputStream so that the Runtime can build a
82       * template with it.
83       *
84       * @param templateName name of template to get
85       * @return InputStream containing the template
86       * @throws ResourceNotFoundException if template not found
87       *         in the file template path.
88       */
89      public synchronized InputStream getResourceStream( String templateName )
90          throws ResourceNotFoundException
91      {
92          /*
93           * Make sure we have a valid templateName.
94           */
95          if ( templateName == null || templateName.length() == 0 )
96          {
97              /*
98               * If we don't get a properly formed templateName then
99               * there's not much we can do. So we'll forget about
100              * trying to search any more paths for the template.
101              */
102             throw new ResourceNotFoundException( "Need to specify a file name or file path!" );
103         }
104 
105         String template = StringUtils.normalizePath( templateName );
106         if ( template == null || template.length() == 0 )
107         {
108             String msg = "Project Resource loader error : argument " + template
109                 + " contains .. and may be trying to access " + "content outside of template root.  Rejected.";
110 
111             rsvc.error( "ProjectResourceLoader : " + msg );
112 
113             throw new ResourceNotFoundException( msg );
114         }
115 
116         /*
117          *  if a / leads off, then just nip that :)
118          */
119         if ( template.startsWith( "/" ) )
120         {
121             template = template.substring( 1 );
122         }
123 
124         int size = paths.size();
125         for ( int i = 0; i < size; i++ )
126         {
127             String path = (String) paths.get( i );
128             InputStream inputStream = findTemplate( path, template );
129 
130             if ( inputStream != null )
131             {
132                 /*
133                  * Store the path that this template came
134                  * from so that we can check its modification
135                  * time.
136                  */
137 
138                 templatePaths.put( templateName, path );
139                 return inputStream;
140             }
141         }
142 
143         /*
144          * We have now searched all the paths for
145          * templates and we didn't find anything so
146          * throw an exception.
147          */
148         String msg = "ProjectResourceLoader Error: cannot find resource " + template;
149 
150         throw new ResourceNotFoundException( msg );
151     }
152 
153     /**
154      * Try to find a template given a normalized path.
155      * 
156      * @param path a normalized path
157      * @return InputStream input stream that will be parsed
158      *
159      */
160     private InputStream findTemplate( String path, String template )
161     {
162         try
163         {
164             File file = new File( path, template );
165 
166             if ( file.canRead() )
167             {
168                 return new BufferedInputStream( new FileInputStream( file.getAbsolutePath() ) );
169             }
170             else
171             {
172                 return null;
173             }
174         }
175         catch ( FileNotFoundException fnfe )
176         {
177             /*
178              *  log and convert to a general Velocity ResourceNotFoundException
179              */
180             return null;
181         }
182     }
183 
184     /**
185      * How to keep track of all the modified times
186      * across the paths.  Note that a file might have
187      * appeared in a directory which is earlier in the
188      * path; so we should search the path and see if
189      * the file we find that way is the same as the one
190      * that we have cached.
191      */
192     public boolean isSourceModified( Resource resource )
193     {
194         /*
195          * we assume that the file needs to be reloaded; 
196          * if we find the original file and it's unchanged,
197          * then we'll flip this.
198          */
199         boolean modified = true;
200 
201         String fileName = resource.getName();
202         String path = (String) templatePaths.get( fileName );
203         File currentFile = null;
204 
205         for ( int i = 0; currentFile == null && i < paths.size(); i++ )
206         {
207             String testPath = (String) paths.get( i );
208             File testFile = new File( testPath, fileName );
209             if ( testFile.canRead() )
210             {
211                 currentFile = testFile;
212             }
213         }
214         File file = new File( path, fileName );
215         if ( currentFile == null || !file.exists() )
216         {
217             /*
218              * noop: if the file is missing now (either the cached
219              * file is gone, or the file can no longer be found)
220              * then we leave modified alone (it's set to true); a 
221              * reload attempt will be done, which will either use
222              * a new template or fail with an appropriate message
223              * about how the file couldn't be found.
224              */
225         }
226         else if ( currentFile.equals( file ) && file.canRead() )
227         {
228             /*
229              * if only if currentFile is the same as file and
230              * file.lastModified() is the same as
231              * resource.getLastModified(), then we should use the
232              * cached version.
233              */
234             modified = ( file.lastModified() != resource.getLastModified() );
235         }
236 
237         /*
238          * rsvc.debug("isSourceModified for " + fileName + ": " + modified);
239          */
240         return modified;
241     }
242 
243     public long getLastModified( Resource resource )
244     {
245         String path = (String) templatePaths.get( resource.getName() );
246         File file = new File( path, resource.getName() );
247 
248         if ( file.canRead() )
249         {
250             return file.lastModified();
251         }
252         else
253         {
254             return 0;
255         }
256     }
257 }