/*
* Data Hub Service (DHuS) - For Space data distribution.
* Copyright (C) 2013,2014,2015 GAEL Systems
*
* This file is part of DHuS software sources.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package fr.gael.dhus.datastore.scanner;
import java.util.AbstractList;
import java.util.EventListener;
import java.util.LinkedList;
import javax.swing.event.EventListenerList;
/**
* This class implement a {@link java.util.LinkedList} with additional
* {@link Listener#addedElement(Event)}/{@link Listener#removedElement(Event)}
* listeners. This List implementation can be use in "simulation" mode
* according to call to {@link #simulate(boolean)} method. Simulation runs
* {@link #add(Object)}/{@link #remove(Object)} methods without
* inserting/removing element from the list, but the listeners are still
* executed.
*/
public class AsynchronousLinkedList<E> extends AbstractList<E>
{
/**
* the delegate list used to store elements.
*/
LinkedList<E>delegate = new LinkedList<E> ();
/**
* This list possible events: ADD and REMOVE event are implemented.
*/
public enum EventType
{
ADD, REMOVE
}
/**
* The event happened in this {@link Listener} class.
* @param <E> element type passed into the list.
*/
public static class Event<E>
{
EventType type;
E element;
int index;
/**
* Build the event.
* @param type the type of event passed according to {@link EventType}
* types.
* @param element the changed element in the list.
* @param index the index of the element in the list.
*/
public Event(EventType type, E element, int index)
{
this.type = type;
this.element = element;
this.index = index;
}
public EventType getType()
{
return this.type;
}
public E getElement()
{
return this.element;
}
public int getIndex()
{
return this.index;
}
}
/**
* This listener is called once the operation is performed. When add event
* happens, the passed {@link Event} parameter contains the element that has
* just been added, and its position in the list. When remove event happens,
* the passed {@link Event} parameter contains the removed element, and the
* index in the list where the element was.
* If the element to remove is not present in the list and no remove action
* is performed, the listener will not be called, even in simulation mode.
*
* @param <E> the type of element being inserted into the list.
* @see AsynchronousLinkedList#simulate(boolean)
*/
public interface Listener<E> extends EventListener
{
void addedElement (Event<E> e);
void removedElement (Event<E> e);
}
private final EventListenerList listeners = new EventListenerList();
public void addListener(Listener<E> listener)
{
listeners.add (Listener.class, listener);
}
public void removeListener(Listener<E> listener)
{
listeners.remove (Listener.class, listener);
}
@SuppressWarnings ("unchecked")
protected Listener<E>[] getListeners()
{
return listeners.getListeners (Listener.class);
}
protected void fireListChanged(Event<E> e)
{
if(e.getType () == EventType.ADD)
{
for(Listener<E> listener : getListeners())
{
listener.addedElement (e);
}
}
else if(e.getType () == EventType.REMOVE)
{
for(Listener<E> listener : getListeners())
{
listener.removedElement (e);
}
}
}
/**
* Switch the component into a simulation mode. If simulation mode is active,
* elements passed to this class are never stored into the delegated list.
* To ensure no data is stored into the delegated list class, the internal
* instance is set to null.
* In any case, changing this mode resets the list.
*
* @param simulation activates the simulation mode if {@code true},
* otherwise, reset the list.
*/
public void simulate (boolean simulation)
{
if (simulation)
delegate = null;
else
delegate = new LinkedList<E> ();
}
// List implementation ...
@Override
public E get (int index)
{
if (delegate == null) return null;
return delegate.get (index);
}
@Override
public int size ()
{
if (delegate == null) return 0;
return delegate.size ();
}
@Override
public E set(int index, E element)
{
E ret;
if (delegate != null)
ret = delegate.set (index, element);
else
ret = null;
fireListChanged (new Event<E> (EventType.ADD, element, index));
return ret;
};
@Override
public void add(int index, E element)
{
if (delegate != null) delegate.add (index, element);
fireListChanged (new Event<E> (EventType.ADD, element, index));
}
@SuppressWarnings ("unchecked")
@Override
public boolean remove (Object o)
{
if (delegate == null) return false;
int index = delegate.indexOf (o);
boolean ret = delegate.remove (o);
if (ret) fireListChanged (new Event<E> (EventType.REMOVE, (E)o, index));
return ret;
}
}