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