/* * ****************************************************************************** * sdrtrunk * Copyright (C) 2014-2019 Dennis Sheirer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see * ***************************************************************************** */ package io.github.dsheirer.identifier; import io.github.dsheirer.identifier.configuration.AliasListConfigurationIdentifier; import io.github.dsheirer.sample.Listener; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Collection; import java.util.Iterator; /** * Identifier collection with methods for changing or updating managed identifiers */ public class MutableIdentifierCollection extends IdentifierCollection implements IdentifierUpdateProvider, Listener { private final static Logger mLog = LoggerFactory.getLogger(MutableIdentifierCollection.class); private Listener mListener; public MutableIdentifierCollection() { } public MutableIdentifierCollection(Collection identifiers) { for(Identifier identifier: identifiers) { update(identifier); } } /** * Broadcasts all of the currently held identifiers to the registered listener */ public void broadcastIdentifiers() { for(Identifier identifier : getIdentifiers()) { notifyAdd(identifier); } } /** * Registers a listener to be notified when identifiers are added to or removed from this collection */ @Override public void setIdentifierUpdateListener(Listener listener) { mListener = listener; } /** * Unregisters the listener from receiving identifier update notifications */ @Override public void removeIdentifierUpdateListener() { mListener = null; } /** * Notifies a registered listener that the identifier has been added to this collection */ private void notifyAdd(Identifier identifier) { setUpdated(true); if(mListener != null) { mListener.receive(new IdentifierUpdateNotification(identifier, IdentifierUpdateNotification.Operation.ADD)); } } /** * Notifies a registered listener that the identifier has been removed from this collection */ private void notifyRemove(Identifier identifier) { setUpdated(true); if(mListener != null) { mListener.receive(new IdentifierUpdateNotification(identifier, IdentifierUpdateNotification.Operation.REMOVE)); } } /** * Adds the identifier to this collection if not already contained in this collection. * * @param identifier to add */ private void add(Identifier identifier) { if(identifier.isValid() && !mIdentifiers.contains(identifier)) { mIdentifiers.add(identifier); notifyAdd(identifier); } //Retain a reference to the alias list identifier separately so that it can be accessed quickly. if(identifier instanceof AliasListConfigurationIdentifier) { mAliasListConfigurationIdentifier = (AliasListConfigurationIdentifier)identifier; } } /** * Adds the identifier to this collection if not already contained in this collection. Does NOT broadcast an * update notification. * * @param identifier to add */ private void silentAdd(Identifier identifier) { if(identifier.isValid() && !mIdentifiers.contains(identifier)) { mIdentifiers.add(identifier); } //Retain a reference to the alias list identifier separately so that it can be accessed quickly. if(identifier instanceof AliasListConfigurationIdentifier) { mAliasListConfigurationIdentifier = (AliasListConfigurationIdentifier)identifier; } } /** * Removes the identifier from this collection */ public void remove(Identifier identifier) { if(mIdentifiers.remove(identifier)) { notifyRemove(identifier); } //Remove the reference to the alias list identifier. if(identifier instanceof AliasListConfigurationIdentifier) { mAliasListConfigurationIdentifier = null; } } /** * Removes the identifier from this collection and does NOT broadcast an update notification */ public void silentRemove(Identifier identifier) { mIdentifiers.remove(identifier); //Remove the reference to the alias list identifier. if(identifier instanceof AliasListConfigurationIdentifier) { mAliasListConfigurationIdentifier = null; } } /** * Adds the identifier only if the value is different from the existing identifiers(s). If * there are multiple matching identifiers, then they are all removed and replaced by this * single identifier. * * @param identifier */ public void update(Identifier identifier) { if(identifier != null) { Identifier existing = getIdentifier(identifier.getIdentifierClass(), identifier.getForm(), identifier.getRole()); if(existing != null) { if(!existing.equals(identifier)) { remove(existing); add(identifier); } } else { add(identifier); } } } /** * Adds the identifier only if the value is different from the existing identifiers(s). If * there are multiple matching identifiers, then they are all removed and replaced by this * single identifier. * * @param identifier */ public void silentUpdate(Identifier identifier) { if(identifier != null) { Identifier existing = getIdentifier(identifier.getIdentifierClass(), identifier.getForm(), identifier.getRole()); if(existing != null) { if(!existing.equals(identifier)) { silentRemove(existing); silentAdd(identifier); } } else { silentAdd(identifier); } } } /** * Updates all identifiers */ public void update(Collection identifiers) { for(Identifier identifier : identifiers) { update(identifier); } } /** * Removes/clears all identifiers from the collection */ public void clear() { Iterator it = mIdentifiers.iterator(); while(it.hasNext()) { notifyRemove(it.next()); it.remove(); } } /** * Removes all identifiers of the specified identifier class */ public void remove(IdentifierClass identifierClass) { Iterator it = mIdentifiers.iterator(); Identifier next = null; while(it.hasNext()) { next = it.next(); if(next.getIdentifierClass() == identifierClass) { it.remove(); notifyRemove(next); } } } /** * Removes all identifiers of the specified form */ public void remove(Form form) { Iterator it = mIdentifiers.iterator(); Identifier next = null; while(it.hasNext()) { next = it.next(); if(next.getForm() == form) { it.remove(); notifyRemove(next); } } } /** * Removes all identifiers of the specified role */ public void remove(Role role) { Iterator it = mIdentifiers.iterator(); Identifier next = null; while(it.hasNext()) { next = it.next(); if(next.getRole() == role) { it.remove(); notifyRemove(next); } } } /** * Removes all identifiers of the specified identifier class, form and role */ public void remove(IdentifierClass identifierClass, Form form, Role role) { Iterator it = mIdentifiers.iterator(); Identifier next = null; while(it.hasNext()) { next = it.next(); if(next.getIdentifierClass() == identifierClass && next.getForm() == form && next.getRole() == role) { it.remove(); notifyRemove(next); } } } /** * Removes all identifiers of the specified identifier class and role */ public void remove(IdentifierClass identifierClass, Role role) { Iterator it = mIdentifiers.iterator(); Identifier next = null; while(it.hasNext()) { next = it.next(); if(next.getIdentifierClass() == identifierClass && next.getRole() == role) { it.remove(); notifyRemove(next); } } } /** * Implements the listener interface to receive notifications of identifier updates. This allows an * identifier collection to maintain a synchronized state with a remote identifier collection. * * @param identifierUpdateNotification to add or remove an identifier */ @Override public void receive(IdentifierUpdateNotification identifierUpdateNotification) { if(identifierUpdateNotification.isAdd()) { update(identifierUpdateNotification.getIdentifier()); } else if(identifierUpdateNotification.isRemove()) { remove(identifierUpdateNotification.getIdentifier()); } else if(identifierUpdateNotification.isSilentAdd()) { silentUpdate(identifierUpdateNotification.getIdentifier()); } else if(identifierUpdateNotification.isSilentRemove()) { silentRemove(identifierUpdateNotification.getIdentifier()); } } /** * Creates a copy of this collection and resets the updated flag so that future invocations of this * method will return a copy with the updated flag set to false. */ public IdentifierCollection copyOf() { IdentifierCollection copy = new IdentifierCollection(getIdentifiers()); copy.setUpdated(isUpdated()); setUpdated(false); return copy; } }