/*
* 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.jackrabbit.core.state;
import org.apache.jackrabbit.core.id.NodeId;
import org.apache.jackrabbit.spi.Name;
import java.lang.ref.Reference;
import java.lang.ref.WeakReference;
import java.util.Collection;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Component that holds references to listeners interested in changes to item
* states and dispatches notifications.
*/
public class StateChangeDispatcher {
/**
* Simple item state listeners.
* A copy on write array list is used so that no synchronization is required.
*/
private final Collection<WeakReference<ItemStateListener>> listeners =
new CopyOnWriteArrayList<WeakReference<ItemStateListener>>();
/**
* Node state listeners
* A copy on write array list is used so that no synchronization is required.
*/
private final Collection<WeakReference<NodeStateListener>> nsListeners =
new CopyOnWriteArrayList<WeakReference<NodeStateListener>>();
/**
* Add an <code>ItemStateListener</code>.
* @param listener the new listener to be informed on modifications
*/
public void addListener(ItemStateListener listener) {
assert getReference(listeners, listener) == null;
listeners.add(new WeakReference<ItemStateListener>(listener));
if (listener instanceof NodeStateListener) {
NodeStateListener nsListener = (NodeStateListener) listener;
assert getReference(nsListeners, nsListener) == null;
nsListeners.add(new WeakReference<NodeStateListener>(nsListener));
}
}
private <T> Reference<T> getReference(Collection< ? extends Reference<T>> coll, ItemStateListener listener) {
for (Reference<T> ref : coll) {
Object o = ref.get();
if (o == listener) {
return ref;
} else if (o == null) {
// clean up unreferenced objects
coll.remove(ref);
}
}
return null;
}
/**
* Remove an <code>ItemStateListener</code>
* @param listener an existing listener
*/
public void removeListener(ItemStateListener listener) {
if (listener instanceof NodeStateListener) {
nsListeners.remove(getReference(nsListeners, listener));
}
listeners.remove(getReference(listeners, listener));
}
/**
* Notify listeners about changes to some state.
* @param created created state.
*/
public void notifyStateCreated(ItemState created) {
for (Reference<ItemStateListener> ref : listeners) {
ItemStateListener l = ref.get();
if (l != null) {
l.stateCreated(created);
}
}
}
/**
* Notify listeners about changes to some state.
* @param modified modified state.
*/
public void notifyStateModified(ItemState modified) {
for (Reference<ItemStateListener> ref : listeners) {
ItemStateListener l = ref.get();
if (l != null) {
l.stateModified(modified);
}
}
}
/**
* Notify listeners about changes to some state.
* @param destroyed destroyed state.
*/
public void notifyStateDestroyed(ItemState destroyed) {
for (Reference<ItemStateListener> ref : listeners) {
ItemStateListener l = ref.get();
if (l != null) {
l.stateDestroyed(destroyed);
}
}
}
/**
* Notify listeners about changes to some state.
* @param discarded discarded state.
*/
public void notifyStateDiscarded(ItemState discarded) {
for (Reference<ItemStateListener> ref : listeners) {
ItemStateListener l = ref.get();
if (l != null) {
l.stateDiscarded(discarded);
}
}
}
/**
* Notify listeners about changes to some state.
* @param state node state that changed
* @param name name of node that was added
* @param index index of new node
* @param id id of new node
*/
public void notifyNodeAdded(NodeState state, Name name, int index, NodeId id) {
for (Reference<NodeStateListener> ref : nsListeners) {
NodeStateListener n = ref.get();
if (n != null) {
n.nodeAdded(state, name, index, id);
}
}
}
/**
* Notify listeners about changes to some state.
* @param state node state that changed
*/
public void notifyNodesReplaced(NodeState state) {
for (Reference<NodeStateListener> ref : nsListeners) {
NodeStateListener n = ref.get();
if (n != null) {
n.nodesReplaced(state);
}
}
}
/**
* Notify listeners about changes to some state.
* @param state node state that changed
*/
public void notifyNodeModified(NodeState state) {
for (Reference<NodeStateListener> ref : nsListeners) {
NodeStateListener n = ref.get();
if (n != null) {
n.nodeModified(state);
}
}
}
/**
* Notify listeners about changes to some state.
* @param state node state that changed
* @param name name of node that was added
* @param index index of new node
* @param id id of new node
*/
public void notifyNodeRemoved(NodeState state, Name name, int index, NodeId id) {
for (Reference<NodeStateListener> ref : nsListeners) {
NodeStateListener n = ref.get();
if (n != null) {
n.nodeRemoved(state, name, index, id);
}
}
}
}