blob: 889d0e801244f78185373c3882cef44b22918a66 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.maven.mercury.event;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;
import org.apache.maven.mercury.logging.IMercuryLogger;
import org.apache.maven.mercury.logging.MercuryLoggerManager;
import org.codehaus.plexus.lang.DefaultLanguage;
import org.codehaus.plexus.lang.Language;
/**
* event queue dispatcher. It registers/unregisters listeners, dispatches events
*
* @author Oleg Gusakov
* @version $Id$
*
*/
public class EventManager
{
public static final int THREAD_COUNT = 4;
/**
* this property may contain comma separated list of bit numbers defined in MercuryEvent.EventTypeEnum. It supersedes
* any bits set by the appropriate EventManager constructor by OR operation with those
*/
public static final String SYSTEM_PROPERTY_EVENT_MASK = "maven.mercury.events";
public static final String systemPropertyEventMask = System.getProperty( SYSTEM_PROPERTY_EVENT_MASK, null );
private static final IMercuryLogger _log = MercuryLoggerManager.getLogger( EventManager.class );
private static final Language _lang = new DefaultLanguage( EventManager.class );
final List<MercuryEventListener> _listeners = new ArrayList<MercuryEventListener>(8);
final LinkedBlockingQueue<UnitOfWork> _queue = new LinkedBlockingQueue<UnitOfWork>( 512 );
private ExecutorService _execService;
private MercuryEvent.EventMask _eventMask;
/**
* default initialization - create thread pool
*/
public EventManager()
{
_execService = Executors.newFixedThreadPool( THREAD_COUNT );
for( int i = 0; i < THREAD_COUNT; i++ )
_execService.execute( new Runner( _queue ) );
processSystemOptions();
}
/**
* default initialization - create thread pool
*/
public EventManager( MercuryEvent.EventMask eventMask )
{
this();
this._eventMask = eventMask;
processSystemOptions();
}
private final void processSystemOptions()
{
if( systemPropertyEventMask == null )
return;
if( _eventMask == null )
_eventMask = new MercuryEvent.EventMask( systemPropertyEventMask );
else
_eventMask.setBits( systemPropertyEventMask );
}
/**
* add listener only if it meets the criteria
*
* @param listener
*/
public void register( MercuryEventListener listener )
{
MercuryEvent.EventMask lMask = listener.getMask();
if( lMask == null || _eventMask == null || _eventMask.intersects( lMask ) )
_listeners.add( listener );
}
public void unRegister( MercuryEventListener listener )
{
_listeners.remove( listener );
}
public List<MercuryEventListener> getListeners()
{
return _listeners;
}
public void fireEvent( MercuryEvent event )
{
for( MercuryEventListener listener : _listeners )
_queue.add( new UnitOfWork( listener, event ) );
}
public static final String toString( MercuryEvent event )
{
return new Date( event.getStart() )+", dur: "+ event.getDuration()+" millis :"
+ " ["+ event.getType()+":"+event.getName()+"] "
+ ( isEmpty( event.getTag() ) ? "" : ", tag: "+event.getTag() )
+ ( isEmpty( event.getInfo() ) ? "" : ", info: "+event.getInfo() )
+ ( isEmpty( event.getResult() ) ? "" : ", result: "+event.getResult() )
;
}
public static final boolean isEmpty( String o )
{
return o == null || o.length() < 1;
}
class UnitOfWork
{
MercuryEventListener listener;
MercuryEvent event;
public UnitOfWork( MercuryEventListener listener, MercuryEvent event )
{
this.listener = listener;
this.event = event;
}
void execute()
{
try
{
MercuryEvent.EventMask lMask = listener.getMask();
if( _eventMask != null )
{
if( lMask == null )
lMask = _eventMask;
else
lMask.and( _eventMask );
}
if( lMask == null || lMask.get( event.getType().bitNo ) )
listener.fire( event );
}
catch( Throwable th )
{
_log.error( _lang.getMessage( "listener.error", th.getMessage() ) );
}
}
}
class Runner
implements Runnable
{
final LinkedBlockingQueue<UnitOfWork> queue;
public Runner( LinkedBlockingQueue<UnitOfWork> queue )
{
this.queue = queue;
}
public void run()
{
UnitOfWork uow;
for(;;)
try
{
uow = queue.take();
uow.execute();
}
catch( InterruptedException e )
{
return;
}
}
}
}