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