| /******************************************************************************* |
| * 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; |
| } |
| } |