org.eclipse.sisu.inject.RankedBindings Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (c) 2010-present 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.inject;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Iterator;
import com.google.inject.Binding;
import com.google.inject.TypeLiteral;
/**
* Ordered sequence of {@link Binding}s of a given type; subscribes to {@link BindingPublisher}s on demand.
*/
final class RankedBindings
implements Iterable>, BindingSubscriber
{
// ----------------------------------------------------------------------
// Implementation fields
// ----------------------------------------------------------------------
final transient RankedSequence> bindings = new RankedSequence>();
final transient TypeLiteral type;
final transient RankedSequence pendingPublishers;
final Collection> cachedBeans = Weak.elements();
// ----------------------------------------------------------------------
// Constructors
// ----------------------------------------------------------------------
RankedBindings( final TypeLiteral type, final RankedSequence publishers )
{
this.type = type;
this.pendingPublishers = new RankedSequence( publishers );
}
// ----------------------------------------------------------------------
// Public methods
// ----------------------------------------------------------------------
public TypeLiteral type()
{
return type;
}
public void add( final Binding binding, final int rank )
{
bindings.insert( binding, rank );
}
public void remove( final Binding binding )
{
if ( bindings.removeThis( binding ) )
{
synchronized ( cachedBeans )
{
for ( final BeanCache, T> beans : cachedBeans )
{
beans.remove( binding );
}
}
}
}
public Iterable> bindings()
{
return bindings.snapshot();
}
public Itr iterator()
{
return new Itr();
}
// ----------------------------------------------------------------------
// Local methods
// ----------------------------------------------------------------------
BeanCache newBeanCache()
{
final BeanCache beans = new BeanCache();
synchronized ( cachedBeans )
{
cachedBeans.add( beans );
}
return beans;
}
void add( final BindingPublisher publisher, final int rank )
{
/*
* No need to lock; ranked sequence is thread-safe.
*/
pendingPublishers.insert( publisher, rank );
}
void remove( final BindingPublisher publisher )
{
/*
* Lock just to prevent subscription race condition.
*/
synchronized ( publisher ) // NOSONAR
{
if ( !pendingPublishers.removeThis( publisher ) )
{
publisher.unsubscribe( this );
}
}
}
// ----------------------------------------------------------------------
// Implementation types
// ----------------------------------------------------------------------
/**
* {@link Binding} iterator that only subscribes to {@link BindingPublisher}s as required.
*/
final class Itr
implements Iterator>
{
// ----------------------------------------------------------------------
// Implementation fields
// ----------------------------------------------------------------------
private final RankedSequence>.Itr itr = bindings.iterator();
// ----------------------------------------------------------------------
// Public methods
// ----------------------------------------------------------------------
public boolean hasNext()
{
// apply any publishers that could add bindings before the current position
BindingPublisher publisher = pendingPublishers.peek();
while ( null != publisher && !itr.hasNext( publisher.maxBindingRank() ) )
{
synchronized ( publisher )
{
// check in case subscribed by another thread
if ( publisher == pendingPublishers.peek() )
{
// only update list _after_ subscription
publisher.subscribe( RankedBindings.this );
pendingPublishers.removeThis( publisher );
}
}
publisher = pendingPublishers.peek();
}
return itr.hasNext();
}
public Binding next()
{
return itr.next();
}
public int rank()
{
return itr.rank();
}
public void remove()
{
throw new UnsupportedOperationException();
}
}
}