blob: 3256ea64e692e0546030902909563c353da52ce1 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2015 Sonatype, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Stuart McCulloch (Sonatype, Inc.) - initial API and implementation
*******************************************************************************/
package org.eclipse.sisu.space;
import java.net.URL;
import javax.inject.Qualifier;
import org.eclipse.sisu.inject.Logs;
import com.google.inject.Module;
/**
* {@link SpaceVisitor} that reports types annotated with {@link Qualifier} annotations.
*/
public final class QualifiedTypeVisitor
implements SpaceVisitor, ClassVisitor
{
// ----------------------------------------------------------------------
// Implementation fields
// ----------------------------------------------------------------------
private final QualifierCache qualifierCache = new QualifierCache();
private final QualifiedTypeListener listener;
private ClassSpace space;
private URL location;
private String source;
private String clazzName;
private boolean qualified;
// ----------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------
public QualifiedTypeVisitor( final QualifiedTypeListener listener )
{
this.listener = listener;
}
// ----------------------------------------------------------------------
// Public methods
// ----------------------------------------------------------------------
public static boolean verify( final ClassSpace space, final Class<?>... specification )
{
for ( final Class<?> expectedClazz : specification )
{
try
{
final Class<?> spaceClazz = space.loadClass( expectedClazz.getName() );
if ( spaceClazz != expectedClazz )
{
Logs.warn( "Inconsistent ClassLoader for: {} in: {}", expectedClazz, space );
Logs.warn( "Expected: {} saw: {}", expectedClazz.getClassLoader(), spaceClazz.getClassLoader() );
}
}
catch ( final TypeNotPresentException e )
{
if ( expectedClazz.isAnnotation() )
{
Logs.trace( "Potential problem: {} is not visible from: {}", expectedClazz, space );
}
}
}
return true;
}
public void enterSpace( final ClassSpace _space )
{
space = _space;
source = null;
if ( Logs.TRACE_ENABLED )
{
verify( _space, Qualifier.class, Module.class );
}
}
public ClassVisitor visitClass( final URL url )
{
location = url;
clazzName = null;
qualified = false;
return this;
}
public void enterClass( final int modifiers, final String name, final String _extends, final String[] _implements )
{
if ( ( modifiers & NON_INSTANTIABLE ) == 0 )
{
clazzName = name; // concrete type
}
}
public AnnotationVisitor visitAnnotation( final String desc )
{
if ( null != clazzName )
{
qualified = qualified || qualifierCache.qualify( space, desc );
}
return null;
}
public void disqualify()
{
qualified = false;
}
public void leaveClass()
{
if ( qualified )
{
listener.hear( space.loadClass( clazzName.replace( '/', '.' ) ), findSource() );
}
}
public void leaveSpace()
{
// no-op
}
// ----------------------------------------------------------------------
// Implementation methods
// ----------------------------------------------------------------------
/**
* Finds source of current class; detailed location or {@link ClassSpace#toString()}.
*/
private String findSource()
{
if ( null != location )
{
// compressed record of class location
final String path = location.getPath();
if ( null == source || !path.startsWith( source ) )
{
final int i = path.indexOf( clazzName );
source = i <= 0 ? path : path.substring( 0, i );
}
}
else if ( null == source )
{
source = space.toString();
}
return source;
}
}