blob: 47583ecf8d018890f36bd28e69f8d3f442967baf [file] [log] [blame]
package org.apache.maven.plugin.resource.loader;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import org.apache.commons.collections.ExtendedProperties;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.apache.velocity.runtime.resource.Resource;
import org.apache.velocity.runtime.resource.loader.ResourceLoader;
import org.apache.velocity.util.StringUtils;
/**
* Resource Loader for external projects.
*
* @version $Id$
*/
public class ProjectResourceLoader
extends ResourceLoader
{
/**
* The paths to search for templates.
*/
private List<String> paths = null;
/**
* Used to map the path that a template was found on so that we can properly check the modification times of the
* files.
*/
private Hashtable<String, String> templatePaths = new Hashtable<String, String>();
public void init( ExtendedProperties configuration )
{
rsvc.getLog().info( "ProjectResourceLoader : initialization starting." );
String separator = System.getProperty( "file.separator" );
String path = System.getProperty( "user.dir" ) + separator + "src" + separator + "main" + separator
+ "resources" + separator;
rsvc.getLog().info( "path :" + path );
paths = new ArrayList<String>();
paths.add( path );
for ( String path1 : paths )
{
rsvc.getLog().info( "ProjectResourceLoader : adding path '" + path1 + "'" );
}
rsvc.getLog().info( "ProjectResourceLoader : initialization complete." );
}
/**
* Get an InputStream so that the Runtime can build a template with it.
*
* @param templateName name of template to get
* @return InputStream containing the template
* @throws ResourceNotFoundException if template not found in the file template path.
*/
public synchronized InputStream getResourceStream( String templateName )
throws ResourceNotFoundException
{
/*
* Make sure we have a valid templateName.
*/
if ( templateName == null || templateName.length() == 0 )
{
/*
* If we don't get a properly formed templateName then there's not much we can do. So we'll forget about
* trying to search any more paths for the template.
*/
throw new ResourceNotFoundException( "Need to specify a file name or file path!" );
}
String template = StringUtils.normalizePath( templateName );
if ( template == null || template.length() == 0 )
{
String msg = "Project Resource loader error : argument " + template
+ " contains .. and may be trying to access " + "content outside of template root. Rejected.";
rsvc.getLog().error( "ProjectResourceLoader : " + msg );
throw new ResourceNotFoundException( msg );
}
/*
* if a / leads off, then just nip that :)
*/
if ( template.startsWith( "/" ) )
{
template = template.substring( 1 );
}
// MCHANGES-118 adding the basedir path
paths.add( (String) rsvc.getApplicationAttribute( "baseDirectory" ) );
for ( String path : paths )
{
InputStream inputStream = findTemplate( path, template );
if ( inputStream != null )
{
/*
* Store the path that this template came from so that we can check its modification time.
*/
templatePaths.put( templateName, path );
return inputStream;
}
}
/*
* We have now searched all the paths for templates and we didn't find anything so throw an exception.
*/
String msg = "ProjectResourceLoader Error: cannot find resource " + template;
throw new ResourceNotFoundException( msg );
}
/**
* Try to find a template given a normalized path.
*
* @param path a normalized path
* @return InputStream input stream that will be parsed
*/
private InputStream findTemplate( String path, String template )
{
try
{
File file = new File( path, template );
if ( file.canRead() )
{
return new BufferedInputStream( new FileInputStream( file.getAbsolutePath() ) );
}
else
{
return null;
}
}
catch ( FileNotFoundException fnfe )
{
/*
* log and convert to a general Velocity ResourceNotFoundException
*/
return null;
}
}
/**
* How to keep track of all the modified times across the paths. Note that a file might have appeared in a directory
* 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
* the one that we have cached.
*/
public boolean isSourceModified( Resource resource )
{
/*
* we assume that the file needs to be reloaded; if we find the original file and it's unchanged, then we'll
* flip this.
*/
boolean modified = true;
String fileName = resource.getName();
String path = templatePaths.get( fileName );
File currentFile = null;
for ( int i = 0; currentFile == null && i < paths.size(); i++ )
{
String testPath = paths.get( i );
File testFile = new File( testPath, fileName );
if ( testFile.canRead() )
{
currentFile = testFile;
}
}
File file = new File( path, fileName );
if ( currentFile == null || !file.exists() )
{
/*
* noop: if the file is missing now (either the cached file is gone, or the file can no longer be found)
* then we leave modified alone (it's set to true); a reload attempt will be done, which will either use a
* new template or fail with an appropriate message about how the file couldn't be found.
*/
}
else if ( currentFile.equals( file ) && file.canRead() )
{
/*
* if only if currentFile is the same as file and file.lastModified() is the same as
* resource.getLastModified(), then we should use the cached version.
*/
modified = ( file.lastModified() != resource.getLastModified() );
}
/*
* rsvc.debug("isSourceModified for " + fileName + ": " + modified);
*/
return modified;
}
public long getLastModified( Resource resource )
{
String path = templatePaths.get( resource.getName() );
File file = new File( path, resource.getName() );
if ( file.canRead() )
{
return file.lastModified();
}
else
{
return 0;
}
}
}