/* * Copyright James Leigh (c) 2007. * * Licensed under the Aduna BSD-style license. */ package net.enilink.komma.dm.change; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.CopyOnWriteArraySet; import net.enilink.komma.core.IStatement; import net.enilink.komma.core.URI; import net.enilink.komma.dm.IDataManager; import net.enilink.komma.dm.internal.change.AddChange; import net.enilink.komma.dm.internal.change.NamespaceChange; import net.enilink.komma.dm.internal.change.RemoveChange; /** * Tracks changes to an {@link IDataManager} by implementing the interface * {@link IDataChangeSupport}. * */ public class DataChangeTracker implements IDataChangeSupport, IDataChangeTracker { protected Map<IDataManager, List<IDataChange>> activeDataManagers = new HashMap<IDataManager, List<IDataChange>>(); protected WeakHashMap<IDataManager, Object> disabledDataManagers = new WeakHashMap<IDataManager, Object>(); private CopyOnWriteArraySet<IDataChangeListener> listeners = new CopyOnWriteArraySet<IDataChangeListener>(); private CopyOnWriteArraySet<IDataChangeListener> internalListeners = new CopyOnWriteArraySet<IDataChangeListener>(); private ThreadLocal<Boolean> disabled = new ThreadLocal<Boolean>(); @Override public void add(IDataManager dm, IStatement stmt) { addChange(dm, new AddChange(stmt)); } private void addChange(IDataManager dm, IDataChange change) { synchronized (activeDataManagers) { ensureList(activeDataManagers, dm).add(change); } } @Override public void addChangeListener(IDataChangeListener changeListener) { listeners.add(changeListener); } public void addInternalChangeListener(IDataChangeListener changeListener) { internalListeners.add(changeListener); } @Override public void close(IDataManager dm) { synchronized (activeDataManagers) { activeDataManagers.remove(dm); } } @Override public void commit(IDataManager dm) { List<IDataChange> committed = null; synchronized (activeDataManagers) { List<IDataChange> changes = activeDataManagers.get(dm); if (changes != null && !changes.isEmpty()) { committed = new ArrayList<IDataChange>(changes); changes.clear(); } } if (committed != null) { handleChanges(committed); } } @Override public void dataChanged(List<IDataChange> changes) { handleChanges(changes); } private <K, T> List<T> ensureList(Map<K, List<T>> map, K key) { List<T> list = map.get(key); if (list == null) { list = new ArrayList<T>(); map.put(key, list); } return list; } protected void handleChanges(List<IDataChange> committed) { notifyListeners(committed); } @Override public boolean isEnabled(IDataManager dm) { if (disabled.get() != null) { return false; } else { synchronized (disabledDataManagers) { return disabledDataManagers.get(dm) == null; } } } protected void notifyListeners(List<IDataChange> changes) { for (IDataChangeListener internalChangeListener : internalListeners) { internalChangeListener.dataChanged(changes); } for (IDataChangeListener changeListener : listeners) { changeListener.dataChanged(changes); } } @Override public void remove(IDataManager dm, IStatement stmt) { addChange(dm, new RemoveChange(stmt)); } @Override public void removeChangeListener(IDataChangeListener changeListener) { listeners.remove(changeListener); } public void removeInternalChangeListener(IDataChangeListener changeListener) { internalListeners.remove(changeListener); } @Override public void removeNamespace(IDataManager dm, String prefix, URI namespace) { IDataChange change = new NamespaceChange(prefix, namespace, null); addChange(dm, change); } @Override public void rollback(IDataManager dm) { synchronized (activeDataManagers) { List<IDataChange> changes = activeDataManagers.get(dm); if (changes != null) { changes.clear(); } } } public void setEnabled(IDataManager dm, boolean enabled) { if (dm == null) { if (enabled) { disabled.remove(); } else { disabled.set(true); } } else { synchronized (disabledDataManagers) { if (enabled) { disabledDataManagers.remove(dm); } else { disabledDataManagers.put(dm, true); } } } } @Override public void setNamespace(IDataManager dm, String prefix, URI oldNS, URI newNS) { IDataChange change = new NamespaceChange(prefix, oldNS, newNS); addChange(dm, change); } }