
org.jitsi.impl.configuration.ChangeEventDispatcher Maven / Gradle / Ivy
/*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed 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.jitsi.impl.configuration;
import java.beans.*;
import java.util.*;
import org.jitsi.service.configuration.*;
/**
* This is a utility class that can be used by objects that support constrained
* properties. You can use an instance of this class as a member field and
* delegate various work to it.
*
* @author Emil Ivov
*/
public class ChangeEventDispatcher
{
/**
* All property change listeners registered so far.
*/
private List propertyChangeListeners;
/**
* All listeners registered for vetoable change events.
*/
private List vetoableChangeListeners;
/**
* Hashtable for managing property change listeners registered for specific
* properties. Maps property names to PropertyChangeSupport objects.
*/
private Map propertyChangeChildren;
/**
* Hashtable for managing vetoable change listeners registered for specific
* properties. Maps property names to PropertyChangeSupport objects.
*/
private Map vetoableChangeChildren;
/**
* The object to be provided as the "source" for any generated events.
*/
private final Object source;
/**
* Constructs a VetoableChangeSupport object.
*
* @param sourceObject The object to be given as the source for any events.
*/
public ChangeEventDispatcher(Object sourceObject)
{
if (sourceObject == null)
throw new NullPointerException("sourceObject");
source = sourceObject;
}
/**
* Add a PropertyChangeListener to the listener list.
* The listener is registered for all properties.
*
* @param listener The PropertyChangeChangeListener to be added
*/
public synchronized void addPropertyChangeListener(
PropertyChangeListener listener)
{
if (propertyChangeListeners == null)
propertyChangeListeners = new Vector();
propertyChangeListeners.add(listener);
}
/**
* Add a PropertyChangeListener for a specific property. The listener
* will be invoked only when a call on firePropertyChange names that
* specific property.
*
* @param propertyName The name of the property to listen on.
* @param listener The ConfigurationChangeListener to be added
*/
public synchronized void addPropertyChangeListener(
String propertyName,
PropertyChangeListener listener)
{
if (propertyChangeChildren == null)
{
propertyChangeChildren =
new Hashtable();
}
ChangeEventDispatcher child = propertyChangeChildren.get(
propertyName);
if (child == null)
{
child = new ChangeEventDispatcher(source);
propertyChangeChildren.put(propertyName, child);
}
child.addPropertyChangeListener(listener);
}
/**
* Remove a PropertyChangeListener from the listener list.
* This removes a ConfigurationChangeListener that was registered
* for all properties.
*
* @param listener The PropertyChangeListener to be removed
*/
public synchronized void removePropertyChangeListener(
PropertyChangeListener listener)
{
if (propertyChangeListeners != null)
propertyChangeListeners.remove(listener);
}
/**
* Remove a PropertyChangeListener for a specific property.
*
* @param propertyName The name of the property that was listened on.
* @param listener The VetoableChangeListener to be removed
*/
public synchronized void removePropertyChangeListener(
String propertyName,
PropertyChangeListener listener)
{
if (propertyChangeChildren != null)
{
ChangeEventDispatcher child
= propertyChangeChildren.get(propertyName);
if (child != null)
child.removePropertyChangeListener(listener);
}
}
/**
* Add a VetoableChangeListener to the listener list.
* The listener is registered for all properties.
*
* @param listener The VetoableChangeListener to be added
*/
public synchronized void addVetoableChangeListener(
ConfigVetoableChangeListener listener)
{
if (vetoableChangeListeners == null)
{
vetoableChangeListeners
= new Vector();
}
vetoableChangeListeners.add(listener);
}
/**
* Remove a VetoableChangeListener from the listener list.
* This removes a VetoableChangeListener that was registered
* for all properties.
*
* @param listener The VetoableChangeListener to be removed
*/
public synchronized void removeVetoableChangeListener(
ConfigVetoableChangeListener listener)
{
if (vetoableChangeListeners != null)
vetoableChangeListeners.remove(listener);
}
/**
* Add a VetoableChangeListener for a specific property. The listener
* will be invoked only when a call on fireVetoableChange names that
* specific property.
*
* @param propertyName The name of the property to listen on.
* @param listener The ConfigurationChangeListener to be added
*/
public synchronized void addVetoableChangeListener(
String propertyName,
ConfigVetoableChangeListener listener)
{
if (vetoableChangeChildren == null)
{
vetoableChangeChildren
= new Hashtable();
}
ChangeEventDispatcher child = vetoableChangeChildren.get(propertyName);
if (child == null)
{
child = new ChangeEventDispatcher(source);
vetoableChangeChildren.put(propertyName, child);
}
child.addVetoableChangeListener(listener);
}
/**
* Remove a VetoableChangeListener for a specific property.
*
* @param propertyName The name of the property that was listened on.
* @param listener The VetoableChangeListener to be removed
*/
public synchronized void removeVetoableChangeListener(
String propertyName,
ConfigVetoableChangeListener listener)
{
if (vetoableChangeChildren != null)
{
ChangeEventDispatcher child
= vetoableChangeChildren.get( propertyName );
if (child != null)
child.removeVetoableChangeListener(listener);
}
}
/**
* Report a vetoable property update to any registered listeners. If
* no one vetos the change, then fire a new ConfigurationChangeEvent
* indicating that the change has been accepted. In the case of a
* PropertyVetoException, end eventdispatch and rethrow the exception
*
* No event is fired if old and new are equal and non-null.
*
* @param propertyName The programmatic name of the property
* that is about to change..
* @param oldValue The old value of the property.
* @param newValue The new value of the property.
*/
public void fireVetoableChange(String propertyName,
Object oldValue, Object newValue)
{
if (vetoableChangeListeners != null || vetoableChangeChildren != null)
{
fireVetoableChange(
new PropertyChangeEvent(
source,
propertyName,
oldValue, newValue));
}
}
/**
* Fire a vetoable property update to any registered listeners. If anyone
* vetos the change, then the exception will be rethrown by this method.
*
* No event is fired if old and new are equal and non-null.
*
* @param evt The PropertyChangeEvent to be fired.
*/
public void fireVetoableChange(PropertyChangeEvent evt)
{
Object oldValue = evt.getOldValue();
Object newValue = evt.getNewValue();
String propertyName = evt.getPropertyName();
if (oldValue != null && newValue != null && oldValue.equals(newValue))
return;
ConfigVetoableChangeListener[] targets = null;
ChangeEventDispatcher child = null;
synchronized (this)
{
if (vetoableChangeListeners != null)
{
targets
= vetoableChangeListeners.toArray(
new ConfigVetoableChangeListener[
vetoableChangeListeners.size()]);
}
if (vetoableChangeChildren != null && propertyName != null)
child = vetoableChangeChildren.get(propertyName);
}
if (vetoableChangeListeners != null && targets != null)
{
for (ConfigVetoableChangeListener target : targets)
target.vetoableChange(evt);
}
if (child != null)
child.fireVetoableChange(evt);
}
/**
* Report a bound property update to any registered listeners.
* No event is fired if old and new are equal and non-null.
*
* @param propertyName The programmatic name of the property
* that was changed.
* @param oldValue The old value of the property.
* @param newValue The new value of the property.
*/
public void firePropertyChange(String propertyName,
Object oldValue, Object newValue)
{
if (oldValue == null || newValue == null || !oldValue.equals(newValue))
{
firePropertyChange(
new PropertyChangeEvent(
source,
propertyName,
oldValue, newValue));
}
}
/**
* Fire an existing PropertyChangeEvent to any registered listeners.
* No event is fired if the given event's old and new values are
* equal and non-null.
* @param evt The PropertyChangeEvent object.
*/
public void firePropertyChange(PropertyChangeEvent evt)
{
Object oldValue = evt.getOldValue();
Object newValue = evt.getNewValue();
String propertyName = evt.getPropertyName();
if (oldValue != null && newValue != null && oldValue.equals(newValue))
return;
if (propertyChangeListeners != null)
{
for (PropertyChangeListener target : propertyChangeListeners)
target.propertyChange(evt);
}
if (propertyChangeChildren != null && propertyName != null)
{
ChangeEventDispatcher child
= propertyChangeChildren.get(propertyName);
if (child != null)
child.firePropertyChange(evt);
}
}
/**
* Check if there are any listeners for a specific property. (Generic
* listeners count as well)
*
* @param propertyName the property name.
* @return true if there are one or more listeners for the given property
*/
public synchronized boolean hasPropertyChangeListeners(String propertyName)
{
if(propertyChangeListeners != null && !propertyChangeListeners.isEmpty())
{
// there is a generic listener
return true;
}
if (propertyChangeChildren != null)
{
ChangeEventDispatcher child
= propertyChangeChildren.get(propertyName);
if (child != null && child.propertyChangeListeners != null)
return!child.propertyChangeListeners.isEmpty();
}
return false;
}
/**
* Check if there are any vetoable change listeners for a specific property.
* (Generic vetoable change listeners count as well)
*
* @param propertyName the property name.
* @return true if there are one or more listeners for the given property
*/
public synchronized boolean hasVetoableChangeListeners(String propertyName)
{
if(vetoableChangeListeners != null && !vetoableChangeListeners.isEmpty())
{
// there is a generic listener
return true;
}
if (vetoableChangeChildren != null)
{
ChangeEventDispatcher child
= vetoableChangeChildren.get(propertyName);
if (child != null && child.vetoableChangeListeners != null)
return!child.vetoableChangeListeners.isEmpty();
}
return false;
}
}