/******************************************************************************
* Copyright (c) 2016 Oracle
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Konstantin Komissarchik - initial implementation and ongoing maintenance
******************************************************************************/
package org.eclipse.sapphire;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* An implementation of {@link Set} that is {@link Observable} using listeners.
*
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
*/
public final class ObservableSet<E> implements Set<E>, Observable
{
private final Set<E> base;
private ListenerContext listeners;
public ObservableSet()
{
this( null );
}
public ObservableSet( final Set<E> base )
{
this.base = ( base == null ? new HashSet<E>() : base );
}
@Override
public void attach( final Listener listener )
{
if( listener == null )
{
throw new IllegalArgumentException();
}
synchronized( this )
{
if( this.listeners == null )
{
this.listeners = new ListenerContext();
}
this.listeners.attach( listener );
}
}
@Override
public void detach( final Listener listener )
{
if( listener == null )
{
throw new IllegalArgumentException();
}
synchronized( this )
{
if( this.listeners != null )
{
this.listeners.detach( listener );
}
}
}
private void broadcast()
{
final ListenerContext listeners;
synchronized( this )
{
listeners = this.listeners;
}
if( listeners != null )
{
listeners.broadcast( new Event() );
}
}
@Override
public int size()
{
synchronized( this )
{
return this.base.size();
}
}
@Override
public boolean isEmpty()
{
synchronized( this )
{
return this.base.isEmpty();
}
}
@Override
public boolean contains( final Object obj )
{
synchronized( this )
{
return this.base.contains( obj );
}
}
@Override
public boolean containsAll( final Collection<?> collection )
{
synchronized( this )
{
return this.base.containsAll( collection );
}
}
@Override
public Iterator<E> iterator()
{
synchronized( this )
{
return new Iterator<E>()
{
private final Iterator<E> base = ObservableSet.this.base.iterator();
public boolean hasNext()
{
synchronized( ObservableSet.this )
{
return this.base.hasNext();
}
}
public E next()
{
synchronized( ObservableSet.this )
{
return this.base.next();
}
}
public void remove()
{
synchronized( ObservableSet.this )
{
this.base.remove();
broadcast();
}
}
};
}
}
@Override
public Object[] toArray()
{
synchronized( this )
{
return this.base.toArray();
}
}
@Override
public <T> T[] toArray( final T[] array )
{
synchronized( this )
{
return this.base.toArray( array );
}
}
@Override
public boolean add( final E entry )
{
final boolean modified;
synchronized( this )
{
modified = this.base.add( entry );
}
if( modified )
{
broadcast();
}
return modified;
}
@Override
public boolean addAll( Collection<? extends E> collection )
{
final boolean modified;
synchronized( this )
{
modified = this.base.addAll( collection );
}
if( modified )
{
broadcast();
}
return modified;
}
@Override
public boolean remove( final Object obj )
{
final boolean modified;
synchronized( this )
{
modified = this.base.remove( obj );
}
if( modified )
{
broadcast();
}
return modified;
}
@Override
public boolean removeAll( final Collection<?> collection )
{
final boolean modified;
synchronized( this )
{
modified = this.base.removeAll( collection );
}
if( modified )
{
broadcast();
}
return modified;
}
@Override
public boolean retainAll( final Collection<?> collection )
{
final boolean modified;
synchronized( this )
{
modified = this.base.retainAll( collection );
}
if( modified )
{
broadcast();
}
return modified;
}
@Override
public void clear()
{
boolean broadcast = false;
synchronized( this )
{
if( ! this.base.isEmpty() )
{
broadcast = true;
}
this.base.clear();
}
if( broadcast )
{
broadcast();
}
}
}