package com.eucalyptus.event; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Map.Entry; import java.util.concurrent.ConcurrentNavigableMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.apache.log4j.Logger; import com.eucalyptus.util.HasName; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import com.google.common.collect.Lists; public class StatefulNamedRegistry<T extends HasName<T>, E extends Enum<E>> { private static Logger LOG = Logger.getLogger( StatefulNamedRegistry.class ); private Map<E, ConcurrentNavigableMap<String, T>> stateMaps; private ConcurrentNavigableMap<String, T> activeMap; private E[] states; private ReadWriteLock canHas; public StatefulNamedRegistry( E... states ) { super( ); this.activeMap = new ConcurrentSkipListMap<String, T>( ); this.states = states;// hack. this.canHas = new ReentrantReadWriteLock( ); if ( this.states.length > 1 ) { this.stateMaps = new HashMap<E, ConcurrentNavigableMap<String, T>>( ); for ( int i = 0; i < this.states.length; i++ ) { this.stateMaps.put( ( E ) states[i], new ConcurrentSkipListMap<String, T>( ) ); } } } public boolean isRegistered( String name ) { this.canHas.readLock( ).lock( ); try { for ( Map<String, T> m : this.stateMaps.values( ) ) if ( this.activeMap.containsKey( name ) ) return true; return false; } finally { this.canHas.readLock( ).unlock( ); } } public T remove( String name ) { T oldValue = null; this.canHas.writeLock( ).lock( ); try { for ( Map<String, T> m : this.stateMaps.values( ) ) { oldValue = m.remove( name ); if ( oldValue != null ) return oldValue; } throw new NoSuchElementException( "Can't find registered object: " + name + " in " + this.getClass( ).getSimpleName( ) ); } finally { this.canHas.writeLock( ).unlock( ); try { ListenerRegistry.getInstance( ).fireEvent( new StateEvent<T, E>( this.states[0], oldValue ) ); } catch ( EventVetoedException e ) { LOG.warn( "Registry change was vetoed: " + e, e ); } } } public T deregister( String key ) { return this.remove( key ); } public T register( T obj, E initialState ) { T oldValue = null; if ( obj == null ) { throw new IllegalArgumentException( "Value cannot be null: " + obj ); } this.canHas.writeLock( ).lock( ); try { oldValue = this.lookup( obj.getName( ) ); E oldState = this.getState( oldValue.getName( ) ); this.stateMaps.get( oldState ).remove( obj.getName( ) ); } catch ( NoSuchElementException e ) { this.stateMaps.get( initialState ).put( obj.getName( ), obj ); } finally { this.canHas.writeLock( ).unlock( ); try { ListenerRegistry.getInstance( ).fireEvent( new StateEvent<T, E>( initialState, obj ) ); } catch ( EventVetoedException e ) { LOG.warn( "Registry change was vetoed: " + e, e ); } } return oldValue; } public T registerIfAbsent( T obj, E initialState ) { T oldValue = null; if ( obj == null ) { throw new IllegalArgumentException( "Value cannot be null: " + obj ); } this.canHas.writeLock( ).lock( ); try { return this.lookup( obj.getName( ) ); } catch ( NoSuchElementException e ) { this.stateMaps.get( initialState ).putIfAbsent( obj.getName( ), obj ); } finally { this.canHas.writeLock( ).unlock( ); try { ListenerRegistry.getInstance( ).fireEvent( new StateEvent<T, E>( initialState, obj ) ); } catch ( EventVetoedException e ) { LOG.warn( "Registry change was vetoed: " + e, e ); } } return oldValue; } private E getState( String name ) throws NoSuchElementException { this.canHas.readLock( ).lock( ); try { for ( Entry<E, ConcurrentNavigableMap<String, T>> e : this.stateMaps.entrySet( ) ) { if ( e.getValue( ).containsKey( name ) ) { return e.getKey( ); } } throw new NoSuchElementException( "Can't find registered object: " + name + " in " + this.getClass( ).getSimpleName( ) ); } finally { this.canHas.readLock( ).unlock( ); } } public T lookup( String name ) throws NoSuchElementException { this.canHas.readLock( ).lock( ); try { for ( Map<String, T> m : this.stateMaps.values( ) ) { if ( m.containsKey( name ) ) { // LOG.debug( m.get( name ) ); return m.get( name ); } } throw new NoSuchElementException( "Can't find registered object: " + name + " in " + this.getClass( ).getSimpleName( ) ); } finally { this.canHas.readLock( ).unlock( ); } } public void setState( String name, E newState ) throws NoSuchElementException { T value = null; this.canHas.writeLock( ).lock( ); try { value = this.remove( name ); this.stateMaps.get( newState ).put( name, value ); } finally { this.canHas.writeLock( ).unlock( ); try { ListenerRegistry.getInstance( ).fireEvent( new StateEvent<T, E>( newState, value ) ); } catch ( EventVetoedException e ) { LOG.warn( "Registry change was vetoed: " + e, e ); } } } public boolean contains( String name ) { this.canHas.readLock( ).lock( ); try { for ( Map m : this.stateMaps.values( ) ) { if ( m.containsKey( name ) ) { return true; } } return false; } finally { this.canHas.readLock( ).unlock( ); } } public ImmutableMap<String, T> getMap( E state ) { return ImmutableMap.copyOf( this.stateMaps.get( state ) ); } public ImmutableList<String> listKeys( ) { List<String> keyList = Lists.newArrayList( ); for ( Map<String, T> m : this.stateMaps.values( ) ) { keyList.addAll( m.keySet( ) ); } return ImmutableList.copyOf( keyList ); } public ImmutableList<T> listValues( ) { List<T> valueList = Lists.newArrayList( ); for ( Map<String, T> m : this.stateMaps.values( ) ) { valueList.addAll( m.values( ) ); } return ImmutableList.copyOf( valueList ); } public ImmutableList<String> listKeys( E state ) { return ImmutableList.copyOf( this.stateMaps.get( state ).keySet( ) ); } public ImmutableList<T> listValues( E state ) { return ImmutableList.copyOf( this.stateMaps.get( state ).values( ) ); } }