package com.eucalyptus.event;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.log4j.Logger;
import com.eucalyptus.records.EventType;
import com.eucalyptus.records.Record;
import com.eucalyptus.util.LogUtil;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import com.eucalyptus.records.EventRecord;
public class ReentrantListenerRegistry<T> {
private static Logger LOG = Logger.getLogger( ReentrantListenerRegistry.class );
private Multimap<T, EventListener> listenerMap;
private Lock modificationLock;
public ReentrantListenerRegistry( ) {
super( );
this.listenerMap = Multimaps.newArrayListMultimap( );
this.modificationLock = new ReentrantLock( );
}
public void register( T type, EventListener listener ) {
EventRecord.caller( ReentrantListenerRegistry.class, EventType.LISTENER_REGISTERED, type.getClass( ).getSimpleName( ), listener.getClass( ).getCanonicalName( ) ).info( );
this.modificationLock.lock( );
try {
if ( !this.listenerMap.containsEntry( type, listener ) ) {
this.listenerMap.put( type, listener );
}
} finally {
this.modificationLock.unlock( );
}
}
public void deregister( T type, EventListener listener ) {
EventRecord.caller( ReentrantListenerRegistry.class, EventType.LISTENER_DEREGISTERED, type.getClass( ).getSimpleName( ), listener.getClass( ).getCanonicalName( ) ).info( );
this.modificationLock.lock( );
try {
this.listenerMap.remove( type, listener );
} finally {
this.modificationLock.unlock( );
}
}
public void destroy( T type ) {
this.modificationLock.lock( );
for( EventListener e : this.listenerMap.get( type ) ) {
EventRecord.caller( ReentrantListenerRegistry.class, EventType.LISTENER_DESTROY_ALL, type.getClass( ).getSimpleName( ), e.getClass( ).getCanonicalName( ) ).info( );
}
try {
this.listenerMap.removeAll( type );
} finally {
this.modificationLock.unlock( );
}
}
public void fireEvent( T type, Event e ) throws EventVetoedException {
List<EventListener> listeners;
this.modificationLock.lock( );
try {
listeners = Lists.newArrayList( this.listenerMap.get( type ) );
} finally {
this.modificationLock.unlock( );
}
this.fireEvent( e, listeners );
}
private void fireEvent( Event e, List<EventListener> listeners ) throws EventVetoedException {
for ( EventListener ce : listeners ) {
ce.advertiseEvent( e );
if ( e.isVetoed( ) ) {
String cause = e.getCause( ) != null ? e.getCause( ) : "no cause given";
EventRecord.here( ReentrantListenerRegistry.class, EventType.LISTENER_EVENT_VETOD, ce.getClass( ).getSimpleName( ), e.toString( ), cause ).info( );
throw new EventVetoedException( String.format( "Event %s was vetoed by listener %s: %s", LogUtil.dumpObject( e ), LogUtil.dumpObject( ce ), cause ) );
}
}
for ( EventListener ce : listeners ) {
Record record = EventRecord.here( ReentrantListenerRegistry.class, EventType.LISTENER_EVENT_FIRED, ce.getClass( ).getSimpleName( ), e.toString( ));
if ( e instanceof ClockTick ) {
record.trace( );
} else {
record.debug( );
}
ce.fireEvent( e );
if ( e.getFail( ) != null ) {
LOG.info( e.getFail( ) );
LOG.debug( e.getFail( ), e.getFail( ) );
throw new EventVetoedException( e.getFail( ) );
}
}
}
}