package org.apache.maven.archiva.consumers.lucene;
/*
* 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 org.apache.maven.archiva.consumers.AbstractMonitoredConsumer;
import org.apache.maven.archiva.consumers.ConsumerException;
import org.apache.maven.archiva.consumers.DatabaseUnprocessedArtifactConsumer;
import org.apache.maven.archiva.indexer.RepositoryContentIndex;
import org.apache.maven.archiva.indexer.RepositoryContentIndexFactory;
import org.apache.maven.archiva.indexer.RepositoryIndexException;
import org.apache.maven.archiva.indexer.bytecode.BytecodeRecord;
import org.apache.maven.archiva.model.ArchivaArtifact;
import org.apache.maven.archiva.repository.ManagedRepositoryContent;
import org.apache.maven.archiva.repository.RepositoryContentFactory;
import org.apache.maven.archiva.repository.RepositoryException;
import com.sun.org.apache.bcel.internal.classfile.ClassParser;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
import com.sun.org.apache.bcel.internal.classfile.Method;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
/**
* IndexJavaPublicMethodsConsumer
*
* @author <a href="mailto:joakime@apache.org">Joakim Erdfelt</a>
* <a href="mailto:oching@apache.org">Maria Odea Ching</a>
* @version $Id: IndexJavaPublicMethodsConsumer.java 680606 2008-07-29 02:48:33Z oching $
*
* @plexus.component role="org.apache.maven.archiva.consumers.DatabaseUnprocessedArtifactConsumer"
* role-hint="index-public-methods"
* instantiation-strategy="per-lookup"
*/
public class IndexJavaPublicMethodsConsumer
extends AbstractMonitoredConsumer
implements DatabaseUnprocessedArtifactConsumer
{
/**
* @plexus.configuration default-value="index-public-methods"
*/
private String id;
/**
* @plexus.configuration default-value="Index the java public methods for Full Text Search."
*/
private String description;
/**
* @plexus.requirement role-hint="lucene"
*/
private RepositoryContentIndexFactory repoIndexFactory;
/**
* @plexus.requirement
*/
private RepositoryContentFactory repoFactory;
private static final String CLASSES = "classes";
private static final String METHODS = "methods";
private List<String> includes = new ArrayList<String>();
public IndexJavaPublicMethodsConsumer()
{
includes.add( "jar" );
includes.add( "war" );
includes.add( "ear" );
includes.add( "zip" );
includes.add( "tar.gz" );
includes.add( "tar.bz2" );
includes.add( "car" );
includes.add( "sar" );
includes.add( "mar" );
includes.add( "rar" );
}
public void beginScan()
{
// TODO Auto-generated method stubx
}
public void completeScan()
{
// TODO Auto-generated method stub
}
public List<String> getIncludedTypes()
{
return includes;
}
public void processArchivaArtifact( ArchivaArtifact artifact )
throws ConsumerException
{
try
{
ManagedRepositoryContent repoContent =
repoFactory.getManagedRepositoryContent( artifact.getModel().getRepositoryId() );
File file = new File( repoContent.getRepoRoot(), repoContent.toPath( artifact ) );
if( file.getAbsolutePath().endsWith( ".jar" ) || file.getAbsolutePath().endsWith( ".war" ) ||
file.getAbsolutePath().endsWith( ".ear" ) || file.getAbsolutePath().endsWith( ".zip" ) ||
file.getAbsolutePath().endsWith( ".tar.gz" ) || file.getAbsolutePath().endsWith( ".tar.bz2" ) ||
file.getAbsolutePath().endsWith( ".car" ) || file.getAbsolutePath().endsWith( ".sar" ) ||
file.getAbsolutePath().endsWith( ".mar" ) || file.getAbsolutePath().endsWith( ".rar" ) )
{
if( file.exists() )
{
List<String> files = readFilesInArchive( file );
Map<String, List<String>> mapOfClassesAndMethods =
getPublicClassesAndMethodsFromFiles( file.getAbsolutePath(), files );
// NOTE: what about public variables? should these be indexed too?
RepositoryContentIndex bytecodeIndex = repoIndexFactory.createBytecodeIndex( repoContent.getRepository() );
artifact.getModel().setRepositoryId( repoContent.getId() );
BytecodeRecord bytecodeRecord = new BytecodeRecord();
bytecodeRecord.setFilename( file.getName() );
bytecodeRecord.setClasses( mapOfClassesAndMethods.get( CLASSES ) );
bytecodeRecord.setFiles( files );
bytecodeRecord.setMethods( mapOfClassesAndMethods.get( METHODS ) );
bytecodeRecord.setArtifact( artifact );
bytecodeRecord.setRepositoryId( repoContent.getId() );
bytecodeIndex.modifyRecord( bytecodeRecord );
}
}
}
catch ( RepositoryException e )
{
throw new ConsumerException( "Can't run index cleanup consumer: " + e.getMessage() );
}
catch ( RepositoryIndexException e )
{
throw new ConsumerException( "Error encountered while adding artifact to index: " + e.getMessage() );
}
catch ( IOException e )
{
throw new ConsumerException( "Error encountered while getting file contents: " + e.getMessage() );
}
}
public String getDescription()
{
return description;
}
public String getId()
{
return id;
}
public boolean isPermanent()
{
return false;
}
private List<String> readFilesInArchive( File file )
throws IOException
{
ZipFile zipFile = new ZipFile( file );
List<String> files;
try
{
files = new ArrayList<String>( zipFile.size() );
for ( Enumeration entries = zipFile.entries(); entries.hasMoreElements(); )
{
ZipEntry entry = (ZipEntry) entries.nextElement();
files.add( entry.getName() );
}
}
finally
{
closeQuietly( zipFile );
}
return files;
}
private void closeQuietly( ZipFile zipFile )
{
try
{
if ( zipFile != null )
{
zipFile.close();
}
}
catch ( IOException e )
{
// ignored
}
}
private static boolean isClass( String name )
{
return name.endsWith( ".class" ) && name.lastIndexOf( "$" ) < 0;
}
private Map<String, List<String>> getPublicClassesAndMethodsFromFiles( String zipFile, List<String> files )
{
Map<String, List<String>> map = new HashMap<String, List<String>>();
List<String> methods = new ArrayList<String>();
List<String> classes = new ArrayList<String>();
for( String file : files )
{
if( isClass( file ) )
{
try
{
ClassParser parser = new ClassParser( zipFile, file );
JavaClass javaClass = parser.parse();
if( javaClass.isPublic() )
{
classes.add( javaClass.getClassName() );
}
Method[] methodsArr = javaClass.getMethods();
for( Method method : methodsArr )
{
if( method.isPublic() )
{
methods.add( method.getName() );
}
}
}
catch ( IOException e )
{
// ignore
}
}
}
map.put( CLASSES, classes );
map.put( METHODS, methods );
return map;
}
}