// **********************************************************************
//
// <copyright>
//
// BBN Technologies
// 10 Moulton Street
// Cambridge, MA 02138
// (617) 873-8000
//
// Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/event/LayerSupport.java,v $
// $RCSfile: LayerSupport.java,v $
// $Revision: 1.9 $
// $Date: 2008/10/16 19:33:09 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.event;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.bbn.openmap.Layer;
/**
* This is a utility class that can be used by beans that need support for
* handling LayerListeners and firing LayerEvents. You can use an instance of
* this class as a member field of your bean and delegate work to it.
*/
public class LayerSupport
extends ListenerSupport<LayerListener> {
static Logger logger = Logger.getLogger("com.bbn.openmap.event.LayerSupport");
protected boolean synchronous = true;
/**
* Construct a LayerSupport.
*
* @param sourceBean The bean to be given as the source for any events.
*/
public LayerSupport(Object sourceBean) {
super(sourceBean);
logger.fine("LayerSupport created");
}
/**
* Send a layer event to all registered listeners.
*
* @param type the event type: one of ADD, REMOVE, REPLACE
* @param layers the list of layers
* @see LayerEvent
*/
public void fireLayer(int type, Layer[] layers) {
if (logger.isLoggable(Level.FINE)) {
logger.fine("calling setLayers on " + size() + " objects");
}
if (isEmpty())
return;
LayerEvent evt = new LayerEvent(source, type, layers);
for (LayerListener listener : this) {
listener.setLayers(evt);
}
}
/**
* Used to see if another Thread object needs to be created.
*/
protected Thread t;
/**
* Event information stack.
*/
protected Vector<SetLayerRunnable> events = new Vector<SetLayerRunnable>();
/**
* Pushed the information onto a Vector stack to get executed by a separate
* thread. Any thread launched is held on to, and if that thread is is null
* or not active, a new thread is kicked off. The dying thread checks the
* Vector stack and fires another event if it can.
*
* @param layerEventType
* @param layers
*/
public synchronized void pushLayerEvent(int layerEventType, Layer[] layers) {
if (synchronous) {
fireLayer(layerEventType, layers);
} else {
events.add(new SetLayerRunnable(layerEventType, layers));
if (t == null || !t.isAlive()) {
SetLayerRunnable runnable = popLayerEvent();
if (runnable != null) {
t = new Thread(runnable);
t.start();
}
}
}
}
/**
* Return the first event on the stack, may be null if there is nothing to
* do.
*/
public synchronized SetLayerRunnable popLayerEvent() {
try {
return events.remove(0);
} catch (ArrayIndexOutOfBoundsException aioobe) {
return null;
}
}
/**
* A reusable Runnable used by a thread to notify listeners when layers are
* turned on/off or shuffled.
*/
protected class SetLayerRunnable
implements Runnable {
protected int layerEventType;
protected Layer[] layers;
public SetLayerRunnable(int let, Layer[] lrs) {
layerEventType = let;
layers = lrs;
}
public int getEventType() {
return layerEventType;
}
public Layer[] getLayers() {
return layers;
}
public void run() {
doIt(getEventType(), getLayers());
SetLayerRunnable runnable = popLayerEvent();
while (runnable != null) {
doIt(runnable.getEventType(), runnable.getLayers());
runnable = popLayerEvent();
}
}
public void doIt(int eventType, Layer[] layers) {
logger.fine("firing LayerEvent on LayerListeners");
fireLayer(eventType, layers);
}
}
public boolean isSynchronous() {
return synchronous;
}
public void setSynchronous(boolean synchronous) {
this.synchronous = synchronous;
}
}