Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
package org.codehaus.plexus.component;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import org.codehaus.plexus.classworlds.realm.ClassRealm;
import static org.codehaus.plexus.PlexusConstants.PLEXUS_DEFAULT_HINT;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import java.util.Iterator;
import java.util.Collections;
public class ComponentIndex
{
/**
* Should values be indexed by all types or simply the supplied type?
*/
private final boolean indexByAllTypes;
/**
* This is the actual index.
* ClassLoader -> Class -> RoleHint -> Values
*/
private final Map, Multimap>> index =
new LinkedHashMap, Multimap>>();
/**
* Creates a component index that indexes by all super types and interfaces of supplied type.
*/
public ComponentIndex()
{
this( false );
}
/**
* Creates a component index.
* @param indexByAllTypes if true, values are indexed by all super types and interfaces of supplied type; otherwise
* values are only indexed by supplied type
*/
public ComponentIndex( boolean indexByAllTypes )
{
this.indexByAllTypes = indexByAllTypes;
}
/**
* Are values are indexed by all super types and interfaces of supplied type?
* @return true, values are indexed by all super types and interfaces of supplied type; otherwise
* false and values are only indexed by supplied type
*/
public boolean isIndexByAllTypes()
{
return indexByAllTypes;
}
/**
* Gets the value associated with the specified type and roleHint.
*
* Values are searched for in classloader order starting from the thread context class loader or type class loader
* if thread context class loader is not set.
*
* @param type the type (or super type if enabled) associated with the value; not null
* @param roleHint the roleHint associated with the value, or null for the default roleHint
* @return the value associated with the type and roleHint, or null
*/
public synchronized V get( Class> type, String roleHint )
{
return get( type, roleHint, Thread.currentThread().getContextClassLoader() );
}
/**
* Gets the value associated with the specified type and roleHint.
*
* Values are searched for in classloader order starting from the specified class loader, or thread context class
* loader or type class loader if specified class loader is null.
*
* @param type the type (or super type if enabled) associated with the value; not null
* @param roleHint the roleHint associated with the value, or null for the default roleHint
* @param classLoader the class loader to search from
* @return the value associated with the type and roleHint, or null
*/
public synchronized V get( Class> type, String roleHint, ClassLoader classLoader )
{
if ( type == null )
{
throw new NullPointerException( "type is null" );
}
if ( roleHint == null )
{
roleHint = PLEXUS_DEFAULT_HINT;
}
Collection values = findAll( type, classLoader ).get( roleHint );
if ( values.isEmpty() )
{
return null;
}
return values.iterator().next();
}
public synchronized Collection getAll( )
{
ArrayList values = new ArrayList();
for ( SortedMap, Multimap> roleIndex : index.values() )
{
for ( Multimap roleHintIndex : roleIndex.values() )
{
values.addAll(roleHintIndex.values());
}
}
return values;
}
/**
* Gets all values associated with the specified type.
*
* Values are searched for in classloader order starting from the thread context class loader or type class loader
* if thread context class loader is not set.
*
* The values are sorted in class loader search order then by registration order.
*
* @param type the type (or super type if enabled) associated with the value; not null
* @return all values associated with the type; never null
*/
public synchronized List getAll( Class> type )
{
return getAll( type, Thread.currentThread().getContextClassLoader() );
}
/**
* Gets all values associated with the specified type.
*
* Values are searched for in classloader order starting from the specified class loader, or thread context class
* loader or type class loader if specified class loader is null.
*
* The values are sorted in class loader search order then by registration order.
*
* @param type the type (or super type if enabled) associated with the value; not null
* @param classLoader the class loader to search from
* @return all values associated with the type; never null
*/
public synchronized List getAll( Class> type, ClassLoader classLoader )
{
if ( type == null )
{
throw new NullPointerException( "type is null" );
}
return new ArrayList( findAll( type, classLoader ).values() );
}
/**
* Gets a map of all values associated with the specified type indexed by roleHint.
*
* Values are searched for in classloader order starting from the thread context class loader or type class loader
* if thread context class loader is not set.
*
* @param type the type (or super type if enabled) associated with the value; not null
* @return all of the value associated with the type; never null
*/
public synchronized Map getAllAsMap( Class> type )
{
return getAllAsMap( type, Thread.currentThread().getContextClassLoader() );
}
/**
* Gets a map of all values associated with the specified type indexed by roleHint.
*
* Values are searched for in classloader order starting from the specified class loader, or thread context class
* loader or type class loader if specified class loader is null.
*
* @param type the type (or super type if enabled) associated with the value; not null
* @param classLoader the class loader to search from
* @return all of the value associated with the type; never null
*/
public synchronized Map getAllAsMap( Class> type, ClassLoader classLoader )
{
if ( type == null )
{
throw new NullPointerException( "type is null" );
}
Map descriptors = new TreeMap();
for ( Entry entry : findAll( type, classLoader ).entries() )
{
if ( !descriptors.containsKey( entry.getKey() ) )
{
descriptors.put( entry.getKey(), entry.getValue() );
}
}
return descriptors;
}
private synchronized Multimap findAll( Class> type, ClassLoader classLoader )
{
if ( classLoader == null )
{
classLoader = type.getClassLoader();
}
// Determine class loaders to search
LinkedHashSet classLoaders = new LinkedHashSet();
for ( ClassLoader cl = classLoader; cl != null; cl = cl.getParent() )
{
if ( cl instanceof ClassRealm )
{
ClassRealm realm = (ClassRealm) cl;
while ( realm != null )
{
classLoaders.add( realm );
realm = realm.getParentRealm();
}
}
else
{
// todo lots of plexus code depends on a global search when there is a class loader associated with
// the thread but the cl is not a class realm
// classLoaders.add( cl );
}
}
// todo remove this when plexus code is updated to manage thread context class loader correctly
if ( classLoaders.isEmpty() )
{
classLoaders.addAll( index.keySet() );
}
// Get all valid component descriptors
Multimap roleHintIndex = Multimaps.newHashMultimap();
for ( ClassLoader cl : classLoaders )
{
SortedMap, Multimap> roleIndex = index.get( cl );
if ( roleIndex != null )
{
Multimap values = roleIndex.get( type );
if ( values != null )
{
roleHintIndex.putAll( values );
}
}
}
return Multimaps.unmodifiableMultimap( roleHintIndex );
}
/**
* Associate a value with the specified class loader, type and roleHint. The value is also associated with all
* superclasses and interfaces of the specified type unless index by all types is disabled.
*/
public synchronized void add( ClassLoader classLoader, Class> type, String roleHint, V value )
{
if ( classLoader == null )
{
throw new NullPointerException( "classLoader is null" );
}
if ( type == null )
{
throw new NullPointerException( "type is null" );
}
if ( roleHint == null )
{
roleHint = PLEXUS_DEFAULT_HINT;
}
if ( value == null )
{
throw new NullPointerException( "value is null" );
}
SortedMap, Multimap> roleIndex = index.get( classLoader );
if ( roleIndex == null )
{
roleIndex = new TreeMap, Multimap>( ClassComparator.INSTANCE );
index.put( classLoader, roleIndex );
}
for ( Class> clazz : getAllTypes( type ) )
{
Multimap roleHintIndex = roleIndex.get( clazz );
if ( roleHintIndex == null )
{
roleHintIndex = new ArrayListMultimap();
roleIndex.put( clazz, roleHintIndex );
}
roleHintIndex.put( roleHint, value );
}
}
/**
* Removes the specified value from the index. This is operation requires a linear search of the whole index, and
* is therefor very expensive.
* @param value the value to remove
*/
public synchronized void remove( V value )
{
if ( value == null )
{
throw new NullPointerException( "value is null" );
}
for ( SortedMap, Multimap> roleIndex : index.values() )
{
for ( Multimap roleHintIndex : roleIndex.values() )
{
for ( Iterator iterator = roleHintIndex.values().iterator(); iterator.hasNext(); )
{
V v = iterator.next();
if ( value.equals( v ) )
{
iterator.remove();
}
}
}
}
}
/**
* Removes all values associated with the specified class loader. This operation is very fast.
*/
public synchronized List removeAll( ClassLoader classLoader )
{
if ( classLoader == null )
{
throw new NullPointerException( "classLoader is null" );
}
ArrayList values = new ArrayList();
SortedMap, Multimap> roleIndex = index.remove( classLoader );
for ( Multimap roleHintIndex : roleIndex.values() )
{
values.addAll(roleHintIndex.values());
}
return values;
}
/**
* Removes all values from this index.
*/
public synchronized Collection clear()
{
Collection all = getAll();
index.clear();
return all;
}
private Set> getAllTypes( Class> type )
{
if ( type.isArray() )
{
throw new IllegalArgumentException( "type is an array: type=" + type );
}
// if we are not indexing by all types, simply return a set containing the source type
if ( !indexByAllTypes )
{
return Collections.>singleton( type );
}
// All found types
Set> allTypes = new LinkedHashSet>();
// Types that must still be processed... may contain entries that
// have already been added to allTypes, so check all types before
// actuall processing to avoid infinite loops
LinkedList> typesToProcess = new LinkedList>();
typesToProcess.add( type );
while ( !typesToProcess.isEmpty() )
{
Class> clazz = typesToProcess.removeFirst();
// have we already processed this type
if ( !allTypes.contains( clazz ) )
{
allTypes.add( clazz );
// schedule superclass for processing
Class> superclass = clazz.getSuperclass();
if ( superclass != null )
{
typesToProcess.addFirst( superclass );
}
// schedule all interfaces for processing
typesToProcess.addAll( 0, Arrays.>asList( clazz.getInterfaces() ) );
}
}
return allTypes;
}
private static final class ClassComparator implements Comparator>, Serializable
{
private static final ClassComparator INSTANCE = new ClassComparator();
public int compare( Class> class1, Class> class2 )
{
return class1.getName().compareTo( class2.getName() );
}
}
}