blob: 91ff72165318db362faa598ab085b1d0f07026f5 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2010, 2013 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.plexus;
import java.net.URL;
import org.codehaus.plexus.component.annotations.Component;
import org.eclipse.sisu.inject.Logs;
import org.eclipse.sisu.space.AnnotationVisitor;
import org.eclipse.sisu.space.ClassSpace;
import org.eclipse.sisu.space.ClassVisitor;
import org.eclipse.sisu.space.LoadedClass;
import org.eclipse.sisu.space.QualifiedTypeVisitor;
import org.eclipse.sisu.space.SpaceScanner;
import org.eclipse.sisu.space.SpaceVisitor;
/**
* {@link SpaceVisitor} that reports Plexus bean classes annotated with @{@link Component}.
*/
public final class PlexusTypeVisitor
implements SpaceVisitor, ClassVisitor
{
// ----------------------------------------------------------------------
// Constants
// ----------------------------------------------------------------------
private static final String COMPONENT_DESC = SpaceScanner.jvmDescriptor( Component.class );
// ----------------------------------------------------------------------
// Implementation fields
// ----------------------------------------------------------------------
private final ComponentAnnotationVisitor componentVisitor = new ComponentAnnotationVisitor();
private final PlexusTypeListener plexusTypeListener;
private final QualifiedTypeVisitor qualifiedTypeVisitor;
private ClassSpace space;
private String source;
private String implementation;
// ----------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------
public PlexusTypeVisitor( final PlexusTypeListener listener )
{
plexusTypeListener = listener;
qualifiedTypeVisitor = new QualifiedTypeVisitor( listener );
}
// ----------------------------------------------------------------------
// Public methods
// ----------------------------------------------------------------------
public void enterSpace( final ClassSpace _space )
{
space = _space;
source = _space.toString();
qualifiedTypeVisitor.enterSpace( _space );
if ( Logs.TRACE_ENABLED )
{
QualifiedTypeVisitor.verify( _space, Component.class );
}
}
public ClassVisitor visitClass( final URL url )
{
componentVisitor.reset();
implementation = null;
qualifiedTypeVisitor.visitClass( null ); // disable detailed source location (see realm filtering)
return this;
}
public void enterClass( final int modifiers, final String name, final String _extends, final String[] _implements )
{
if ( ( modifiers & NON_INSTANTIABLE ) == 0 )
{
implementation = name;
}
qualifiedTypeVisitor.enterClass( modifiers, name, _extends, _implements );
}
public AnnotationVisitor visitAnnotation( final String desc )
{
if ( COMPONENT_DESC.equals( desc ) )
{
return componentVisitor;
}
return qualifiedTypeVisitor.visitAnnotation( desc );
}
public void leaveClass()
{
if ( null != implementation )
{
final Component component = componentVisitor.getComponent( space );
if ( null != component )
{
final Class<?> clazz = space.loadClass( implementation.replace( '/', '.' ) );
plexusTypeListener.hear( component, new LoadedClass<Object>( clazz ), source );
qualifiedTypeVisitor.disqualify();
}
}
qualifiedTypeVisitor.leaveClass();
}
public void leaveSpace()
{
qualifiedTypeVisitor.leaveSpace();
}
// ----------------------------------------------------------------------
// Implementation types
// ----------------------------------------------------------------------
/**
* {@link AnnotationVisitor} that records details of @{@link Component} annotations.
*/
static final class ComponentAnnotationVisitor
implements AnnotationVisitor
{
// ----------------------------------------------------------------------
// Implementation fields
// ----------------------------------------------------------------------
private String role;
private String hint;
private String strategy;
private String description;
// ----------------------------------------------------------------------
// Public methods
// ----------------------------------------------------------------------
public void reset()
{
role = null;
hint = Hints.DEFAULT_HINT;
strategy = Strategies.SINGLETON;
description = "";
}
public void enterAnnotation()
{
// no-op; maintain results outside of individual annotation scan
}
public void visitElement( final String name, final Object value )
{
if ( "role".equals( name ) )
{
role = (String) value;
}
else if ( "hint".equals( name ) )
{
hint = Hints.canonicalHint( (String) value );
}
else if ( "instantiationStrategy".equals( name ) )
{
strategy = (String) value;
}
else if ( "description".equals( name ) )
{
description = (String) value;
}
}
public void leaveAnnotation()
{
// no-op; maintain results outside of individual annotation scan
}
public Component getComponent( final ClassSpace space )
{
return null != role ? new ComponentImpl( space.loadClass( role ), hint, strategy, description ) : null;
}
}
}