mcconnell 2003/07/05 00:57:50
Added: merlin/composition/src/java/org/apache/avalon/composition/model/impl
Scanner.java
Log:
Utility class that handles the scanning of directories, jar files and streams for
type and service defintions.
Revision Changes Path
1.1
avalon-sandbox/merlin/composition/src/java/org/apache/avalon/composition/model/impl/Scanner.java
Index: Scanner.java
===================================================================
/* ====================================================================
* The Apache Software License, Version 1.1
*
* Copyright (c) 2002 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowledgment may appear in the software
* itself, if and wherever such third-party acknowledgments
* normally appear.
*
* 4. The names "Jakarta", "Avalon", and "Apache Software Foundation"
* must not be used to endorse or promote products derived from this
* software without prior written permission. For written
* permission, please contact [EMAIL PROTECTED]
*
* 5. Products derived from this software may not be called "Apache",
* nor may "Apache" appear in their name, without prior written
* permission of the Apache Software Foundation.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.avalon.composition.model.impl;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.zip.ZipEntry;
import org.apache.avalon.composition.model.ModelException;
import org.apache.avalon.composition.util.ExceptionHelper;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.meta.data.Profile;
import org.apache.avalon.meta.info.Service;
import org.apache.avalon.meta.info.Type;
import org.apache.avalon.meta.info.builder.TypeBuilder;
import org.apache.avalon.meta.info.builder.ServiceBuilder;
/**
* A repository for services, types and profiles.
*
* @author <a href="mailto:[EMAIL PROTECTED]">Gary Shea</a>
* @version $Revision: 1.1 $ $Date: 2003/07/05 07:57:50 $
*/
public class Scanner extends AbstractLogEnabled
{
//===================================================================
// static
//===================================================================
private static final String X_INFO = ".xinfo";
private static final String X_TYPE = ".xtype";
private static final String X_SERVICE = ".xservice";
private static final String X_PROFILE = ".xprofile";
/**
* The type builder.
*/
private static final TypeBuilder TYPE_BUILDER =
new TypeBuilder();
/**
* The service builder.
*/
private static final ServiceBuilder SERVICE_BUILDER =
new ServiceBuilder();
//===================================================================
// state
//===================================================================
/**
* Parent repository.
*/
private ClassLoader m_classloader;
//===================================================================
// constructor
//===================================================================
/**
* Creation of a new scanner using a supplied classloader.
* The scanner is responsible for scanning suppied URLs for
* service and types.
*
* @param classloader the classloader
*/
public Scanner( ClassLoader classloader )
{
if( classloader == null )
{
throw new NullPointerException( "classloader" );
}
m_classloader = classloader;
}
//=======================================================================
// Repository
//=======================================================================
/**
* Scan the supplied url for Service and Type defintions.
* @param urls the URL array to scan
* @return an object array containing [EMAIL PROTECTED] Service} and
* [EMAIL PROTECTED] Type} instances
*/
public void scan( URL[] urls, List types, List services ) throws ModelException
{
for( int i=0; i<urls.length; i++ )
{
URL url = urls[i];
scanURL( url, types, services );
}
}
/**
* Add a URL to the classpath.
* @param url the URL to add to the repository
*/
private void scanURL( URL url, List types, List services ) throws ModelException
{
if( getLogger().isDebugEnabled() )
{
getLogger().debug( "scanning: " + url );
}
if( isDirectory( url ) )
{
scanDirectory( url, types, services );
}
else if(
url.getProtocol().equals( "jar" )
|| ( url.getProtocol().equals( "file" ) && url.toString().endsWith( ".jar"
) ) )
{
scanJarFileURL( url, types, services );
}
else
{
scanInputStream( url, types, services );
}
}
private void scanDirectory( URL url, List types, List services ) throws
ModelException
{
try
{
File directory = getDirectory( url );
scanDirectoryContent( directory, directory, types, services );
}
catch( Throwable e )
{
final String error =
"Unexpected Ierror while attempting to scan directory: "
+ url;
throw new ModelException( error, e );
}
}
private void scanJarFileURL( URL url, List types, List services ) throws
ModelException
{
URL uri = url;
try
{
if( !url.getProtocol().equals( "jar" ) )
{
uri = getJarURL( url );
}
if( !uri.toString().endsWith( "!/" ) )
{
final String error =
"Embeded jar file loading not supported: " + url;
throw new IllegalArgumentException( error );
}
final JarURLConnection jar = (JarURLConnection) uri.openConnection();
final JarFile base = jar.getJarFile();
scanJarFile( base, types, services );
}
catch( Throwable e )
{
final String error =
"Unexpected error while scanning jar file: " + url;
throw new ModelException( error );
}
}
private void scanJarFile( JarFile base, List types, List services ) throws
Exception
{
Enumeration entries = base.entries();
while( entries.hasMoreElements() )
{
ZipEntry entry = (ZipEntry) entries.nextElement();
String name = entry.getName();
if( name.endsWith( X_TYPE ) || name.endsWith( X_INFO ) )
{
addType( types, name );
}
else if( name.endsWith( X_SERVICE ) )
{
addService( services, name );
}
}
}
private void scanInputStream( URL url, List types, List services )
{
try
{
Object object = url.openStream();
if( object != null )
{
JarInputStream stream = new JarInputStream( (InputStream) object );
scanJarInputStream( stream, types, services );
return;
}
else
{
if( getLogger().isWarnEnabled() )
{
getLogger().warn(
"Unrecognized content from url " + url );
}
}
}
catch( Throwable e )
{
if( getLogger().isWarnEnabled() )
{
final String error =
"Content related error while scanning url: " + url;
getLogger().warn( ExceptionHelper.packException(
error, e, getLogger().isDebugEnabled() ) );
}
}
}
private void scanJarInputStream( JarInputStream stream, List types, List
services ) throws Exception
{
ZipEntry entry = null;
try
{
entry = stream.getNextEntry();
}
catch( Throwable e )
{
entry = null;
}
while( entry != null )
{
String name = entry.getName();
if( name.endsWith( X_TYPE ) || name.endsWith( X_INFO ) )
{
addType( types, name );
}
else if( name.endsWith( X_SERVICE ) )
{
addService( services, name );
}
try
{
entry = stream.getNextEntry();
}
catch( Throwable e )
{
entry = null;
}
}
}
private void scanDirectoryContent( File base, File dir, List types, List
services ) throws Exception
{
File[] files = dir.listFiles();
String path = base.toString();
int j = path.length();
for( int i = 0; i < files.length; i++ )
{
File file = files[i];
if( file.isDirectory() )
{
getLogger().debug( "scanning dir: " + file );
scanDirectoryContent( base, file, types, services );
}
else
{
scanFile( j, file, types, services );
}
}
}
private void scanFile( int j, File file, List types, List services ) throws
Exception
{
String filename = file.toString();
String name = filename.substring( j, filename.length() );
if( name.endsWith( X_TYPE ) || name.endsWith( X_INFO ) )
{
addType( types, name );
}
else if( name.endsWith( X_SERVICE ) )
{
addService( services, name );
}
}
private void addType( List list, String name ) throws Exception
{
String classname = parseResourceName( name );
list.add( TYPE_BUILDER.build( classname, m_classloader ) );
}
private void addService( List list, String name ) throws Exception
{
String classname = parseResourceName( name );
list.add( SERVICE_BUILDER.build( classname, m_classloader ) );
}
private boolean isDirectory( URL url )
{
if( url.getProtocol().equals( "file" ) )
{
return getFile( url ).isDirectory();
}
return false;
}
private File getDirectory( URL url ) throws IllegalArgumentException
{
File file = getFile( url );
if( file.isDirectory() )
{
return file;
}
throw new IllegalArgumentException(
"URL does not refer to a directory: " + url );
}
private File getFile( URL url ) throws IllegalArgumentException
{
if( url.getProtocol().equals( "file" ) )
{
return new File( url.toString().substring( 5 ) );
}
throw new IllegalArgumentException(
"URL protocol does not match the required file: protocol: " + url );
}
private String parseResourceName( String resource )
{
int i = resource.lastIndexOf( "." );
String name = resource.substring( 0, i );
String name2 = name.replace( '/', '.' );
String name3 = name2.replace( '\\', '.' );
if( name3.startsWith( "." ) )
{
return name3.substring( 1, name3.length() );
} else
{
return name3;
}
}
private URL getJarURL( URL url ) throws MalformedURLException
{
if( url.getProtocol().equals( "jar" ) )
{
return url;
} else
{
return new URL( "jar:" + url.toString() + "!/" );
}
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]