/*
* Copyright 2010 Proofpoint, Inc.
*
* Licensed 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.
*/
package io.airlift.jmx;
import com.google.inject.ConfigurationException;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.InjectionPoint;
import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* Utility for iterating over dependent classes in a Guice injector
*/
class GuiceDependencyIterator implements Iterator<Class<?>>, Iterable<Class<?>>
{
private final Set<Key<?>> visited;
private final Iterator<Dependency<?>> currentDependencyIterator;
private final TypeLiteral<?> creationTypeLiteral;
private final Class<?> creationClass;
private Class<?> currentClass = null;
/**
* @param typeLiteral the type literal to iterate over
*/
public GuiceDependencyIterator(TypeLiteral<?> typeLiteral)
{
this(null, typeLiteral, new HashSet<Key<?>>());
}
/**
* @param clazz the class to iterate over
*/
public GuiceDependencyIterator(Class<?> clazz)
{
this(clazz, null, new HashSet<Key<?>>());
}
/**
* Returns whether or not there was an injection point for the type/class
*
* @return true/false
*/
public boolean hasInjectionPoint()
{
return (currentDependencyIterator != null);
}
/**
* Use an external set of visited classes - this is used to avoid recursive iteration
*
* @param visited the visited set. A copy is _not_ made. The original instance will be mutated
* @return new iterator that uses the given visited set instance
*/
public GuiceDependencyIterator substituteVisitedSet(Set<Key<?>> visited)
{
return new GuiceDependencyIterator(creationClass, creationTypeLiteral, visited);
}
@Override
public Iterator<Class<?>> iterator()
{
return new GuiceDependencyIterator(creationClass, creationTypeLiteral, visited);
}
@Override
public boolean hasNext()
{
if (currentDependencyIterator != null) {
while ((currentClass == null) && currentDependencyIterator.hasNext()) {
currentClass = GuiceInjectorIterator.parseKey(visited, currentDependencyIterator.next().getKey());
}
}
return (currentClass != null);
}
@Override
public Class<?> next()
{
if (!hasNext()) {
throw new NoSuchElementException();
}
Class<?> localClass = currentClass;
currentClass = null;
return localClass;
}
@Override
public void remove()
{
throw new UnsupportedOperationException();
}
private GuiceDependencyIterator(Class<?> clazz, TypeLiteral<?> typeLiteral, Set<Key<?>> visited)
{
this.creationClass = clazz;
this.creationTypeLiteral = typeLiteral;
this.visited = visited;
// must be called last
currentDependencyIterator = initInjectionPoint();
}
private Iterator<Dependency<?>> initInjectionPoint()
{
try {
InjectionPoint injectionPoint;
if (creationTypeLiteral != null) {
injectionPoint = InjectionPoint.forConstructorOf(creationTypeLiteral);
}
else {
injectionPoint = InjectionPoint.forConstructorOf(creationClass);
}
return injectionPoint.getDependencies().iterator();
}
catch (ConfigurationException dummy) {
// ignore
}
return null;
}
}