All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.cedarsoft.history.ElementsCollection Maven / Gradle / Ivy

package com.cedarsoft.history;

import com.cedarsoft.Lockable;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * Contains a collection of entries
 */
public class ElementsCollection implements ObservableObjectAccess, Lockable {
  @NotNull
  @NonNls
  public static final String PROPERTY_ELEMENTS = "elements";

  private Long id;
  @NotNull
  protected final List elements = new ArrayList();
  @NotNull
  protected final CollectionSupport collectionSupport = new CollectionSupport( this );
  @NotNull
  protected final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

  public ElementsCollection() {
  }

  public ElementsCollection( @NotNull Collection elements ) {
    this.elements.addAll( elements );
  }

  public final void add( @NotNull E element ) {
    addElement( element );
  }

  /**
   * Adds a new entry
   *
   * @param element the entry that is added
   */
  public void addElement( @NotNull E element ) {
    lock.writeLock().lock();
    int index;
    try {
      elements.add( element );
      index = elements.indexOf( element );
    } finally {
      lock.writeLock().unlock();
    }
    collectionSupport.elementAdded( element, index );
  }

  public void commit( @NotNull E element ) {
    lock.readLock().lock();
    int index;
    try {
      if ( !elements.contains( element ) ) {
        throw new IllegalArgumentException( "Invalid element commited: " + element + ". Is not contained within this collection." );
      }
      index = elements.indexOf( element );
    } finally {
      lock.readLock().unlock();
    }
    collectionSupport.elementChanged( element, index );
  }

  /**
   * Whether this contains any entries
   *
   * @return whether this  contains any entries
   */
  public boolean hasElements() {
    lock.readLock().lock();
    try {
      return !elements.isEmpty();
    } finally {
      lock.readLock().unlock();
    }
  }

  public boolean isEmpty() {
    return !hasElements();
  }

  public void addAll( @NotNull List additionalElements ) {
    for ( E element : additionalElements ) {
      add( element );
    }
  }

  public int size() {
    lock.readLock().lock();
    try {
      return elements.size();
    } finally {
      lock.readLock().unlock();
    }
  }

  /**
   * Returns all cessions
   *
   * @return the cessions
   */
  @NotNull
  public List getElements() {
    lock.readLock().lock();
    try {
      return Collections.unmodifiableList( elements );
    } finally {
      lock.readLock().unlock();
    }
  }

  public final void remove( @NotNull E element ) {
    removeEntry( element );
  }

  public boolean removeEntry( @NotNull E element ) {
    lock.writeLock().lock();
    boolean removed;
    int index;
    try {
      index = elements.indexOf( element );
      removed = elements.remove( element );
    } finally {
      lock.writeLock().unlock();
    }

    collectionSupport.elementDeleted( element, index );

    return removed;
  }

  public void addElementListener( @NotNull ElementsListener listener ) {
    collectionSupport.addElementListener( listener );
  }

  public void removeElementListener( @NotNull ElementsListener listener ) {
    collectionSupport.removeElementListener( listener );
  }

  @NotNull
  public List findElements( @NotNull ElementVisistor visistor ) {
    List found = new ArrayList();

    lock.readLock().lock();
    try {
      for ( E element : elements ) {
        if ( visistor.fits( element ) ) {
          found.add( element );
        }
      }
    } finally {
      lock.readLock().unlock();
    }

    return Collections.unmodifiableList( found );
  }

  /**
   * Returns the first entry that matches the visistor
   *
   * @param visistor the visitor that identifies the entries
   * @return the first entry
   *
   * @throws NoElementFoundException if no entry has been found
   */
  @NotNull
  public E findFirstElement( @NotNull ElementVisistor visistor ) throws NoElementFoundException {
    E found = findFirstElementNullable( visistor );
    if ( found == null ) {
      throw new NoElementFoundException( "No element found for " + visistor.getIdentifier() );
    }
    return found;
  }

  @Nullable
  public E findFirstElementNullable( @NotNull ElementVisistor visistor ) {
    lock.readLock().lock();
    try {
      for ( E element : elements ) {
        if ( visistor.fits( element ) ) {
          return element;
        }
      }
    } finally {
      lock.readLock().unlock();
    }
    return null;
  }

  public boolean contains( @NotNull E element ) {
    lock.readLock().lock();
    try {
      return elements.contains( element );
    } finally {
      lock.readLock().unlock();
    }
  }

  public boolean contains( @NotNull ElementVisistor visistor ) throws NoElementFoundException {
    lock.readLock().lock();
    try {
      for ( E element : elements ) {
        if ( visistor.fits( element ) ) {
          return true;
        }
      }
    } finally {
      lock.readLock().unlock();
    }
    return false;
  }

  /**
   * Removes the entries
   *
   * @param visistor the visitor that describes the entries
   */
  @NotNull
  public List removeElements( @NotNull ElementVisistor visistor ) {
    List removed = new ArrayList();
    lock.writeLock().lock();
    try {
      for ( Iterator it = elements.iterator(); it.hasNext(); ) {
        E element = it.next();
        if ( visistor.fits( element ) ) {
          it.remove();
          removed.add( element );
        }
      }
    } finally {
      lock.writeLock().unlock();
    }

    return removed;
  }

  public void clear() {
    if ( !collectionSupport.hasListeners() ) {
      lock.writeLock().lock();
      try {
        elements.clear();
      } finally {
        lock.writeLock().unlock();
      }
    }

    lock.writeLock().lock();
    try {
      for ( Iterator it = elements.iterator(); it.hasNext(); ) {
        E element = it.next();
        it.remove();
        collectionSupport.elementDeleted( element, 0 );
      }
    } finally {
      lock.writeLock().unlock();
    }
  }

  @NotNull
  public ReentrantReadWriteLock getLock() {
    return lock;
  }

  /**
   * XStream
   *
   * @return this
   */
  @NotNull
  private Object readResolve() {
    try {
      {
        Field field = ElementsCollection.class.getDeclaredField( "collectionSupport" );
        field.setAccessible( true );
        field.set( this, new CollectionSupport( this ) );
      }
      {
        Field field = ElementsCollection.class.getDeclaredField( "lock" );
        field.setAccessible( true );
        field.set( this, new ReentrantReadWriteLock() );
      }
    } catch ( Exception e ) {
      throw new RuntimeException( e );
    }
    return this;
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy