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

com.gemstone.gemfire.internal.util.VersionedArrayList Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2010-2015 Pivotal Software, Inc. All rights reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you
 * may not use this file except in compliance with the License. You
 * may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License. See accompanying
 * LICENSE file.
 */

package com.gemstone.gemfire.internal.util;

import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import com.gemstone.gemfire.DataSerializable;
import com.gemstone.gemfire.internal.InternalDataSerializer;
import com.gemstone.gemfire.internal.cache.Node;

/**
 * Versioned ArrayList which maintains the version everytime the list gets
 * modified. This is thread-safe in terms of add and remove operations and also
 * list is an unmodifiable list to avoid ConcurrentModificationException.
 * 
 * @see java.util.ConcurrentModificationException
 * 
 * @author rreja
 */
public class VersionedArrayList implements DataSerializable, Versionable, Iterable
{
  private static final long serialVersionUID = -1455442285961593385L;

  /** Version of the list. */
  private long version = -1;

  /** ArrayList */
  private List list;
  
//  private List vhist = new ArrayList();  // DEBUG
  
  /**
   * Constructor for DataSerializable.
   */
  public VersionedArrayList() {
    this.list = new ArrayList();
  }

  /**
   * Constructor.
   * 
   * @param size
   */
  public VersionedArrayList(int size) {
    this.list = new ArrayList(size);
  }

  public VersionedArrayList(List list) {
    this.list = Collections.unmodifiableList(list);
//    incrementVersion("i->" + list);
    incrementVersion();
  }

  /**
   * Adds obj to the list. Addition is done by making a copy of the existing
   * list and then adding the obj to the new list and assigning the old list to
   * the new unmodifiable list. This is to ensure that the iterator of the list
   * doesn't get ConcurrentModificationException.
   * 
   * @see java.util.ConcurrentModificationException
   * @param obj
   */
  public synchronized void add(Node obj)
  {

    ArrayList newList = new ArrayList(this.list);
    newList.add(obj);
    this.list = Collections.unmodifiableList(newList);
//    incrementVersion("a->" + obj);
    incrementVersion();
  }

  /**
   * Removes obj from the list. Removal is done by making a copy of the existing
   * list and then removing the obj from the new list.  If the object was removed, 
   * the list is assigning to the new unmodifiable list. 
   * This is to ensure that the iterator of the list doesn't get ConcurrentModificationException.
   * @return true if the element was removed and the version was changed, otherwise version and list are left
   * unmodified.
   * 
   * @see java.util.ConcurrentModificationException
   * @param obj the object to remove from the list
   */
  public synchronized boolean remove(Node obj)
  {
    ArrayList newList = new ArrayList(this.list);
    boolean ret = newList.remove(obj);
    if (ret) {
      this.list = Collections.unmodifiableList(newList);
//      incrementVersion("r->" + obj);
      incrementVersion();
    } 
    return ret;
  }

  /**
   * Returns the iterator.
   * 
   * @return a list Iterator
   */
  public synchronized Iterator iterator()
  {
    return this.list.iterator();
  }

  /**
   * Returns the size of the list.
   * 
   * @return int
   */
  public synchronized int size()
  {
    return this.list.size();
  }

  /**
   * Returns true if obj is present in the list otherwise false.
   * 
   * @param obj
   * @return true if obj is present in the list
   */
  public boolean contains(Node obj)
  {
    final List l; 
    synchronized(this) {
      l = this.list;
    }
    return l.contains(obj);
  }

  

  /**
   * Returns Object at index i.
   * 
   * @param i
   * @return Object
   */
  public Object get(int i)
  {
    final List l; 
    synchronized(this) {
      l = this.list;
    }
    return l.get(i);
  }

  /**
   * Returns the index of Object if present, else -1.
   * 
   * @param obj
   * @return int
   */
  public int indexOf(Object obj)
  {
    final List l;
    synchronized(this) {
      l = this.list;
    }
    return l.indexOf(obj);
  }

  /**
   * Returns a copy of the arraylist contained.
   * 
   * @return ArrayList
   */
  public Set getListCopy()
  {
    final List l;
    synchronized(this) {
      l = this.list;
    }
    return new HashSet(l);
  }

  /**
   * Prints the version and elements of the list.
   * 
   * @return String with version and elements of the list.
   */
  @Override
  public String toString()
  {
    final List l;
//    final List vh;
    synchronized(this) {
      l = this.list;
//      vh = this.vhist;
    }
    StringBuffer sb = new StringBuffer();
    sb.append("ArrayList version = " + getVersion() + " Elements = { ");
    for (int i = 0; i < l.size(); i++) {
      sb.append(l.get(i).toString() + ", ");
    }
//    sb.append("vhist:\n " + vh);
    sb.append("}");
    return sb.toString();
  }

 
  public void toData(DataOutput out) throws IOException
  {
    long v = -1;
    final List l;
//    final List vh;
    synchronized (this) {
      v = this.version;
      l = this.list;
//      vh = this.vhist;
    }

    out.writeLong(v);
    final int s = l.size();
    out.writeInt(s);
    for (int k = 0; k < s; k++) {
      InternalDataSerializer.invokeToData((l.get(k)), out);
    }

//    final int sh = vh.size();
//    out.writeInt(sh);
//    for (int k = 0; k < sh; k++) {
//      out.writeUTF((String) vh.get(k));
//    }
  }


  public void fromData(DataInput in) throws IOException, ClassNotFoundException
  {
    final ArrayList l = new ArrayList();
    final long v = in.readLong();
    final int size = in.readInt();
    for (int k = 0; k < size; k++) {      
      l.add(new Node(in));
    }
    
//    final ArrayList vh = new ArrayList();
//    final int vhsize = in.readInt();
//    for (int k = 0; k < vhsize; k++) {      
//      vh.add(in.readUTF());
//    }
    
    synchronized (this) {
      this.version = v;
      this.list = Collections.unmodifiableList(l);
//      this.vhist = Collections.unmodifiableList(vh);
    }
  }

  
  /* (non-Javadoc)
   * @see com.gemstone.gemfire.internal.util.Versionable#getVersion()
   */
  public synchronized Comparable getVersion()
  {
    return Long.valueOf(this.version);
  }
  
  public boolean isNewerThan(Versionable other) {
    if (other instanceof VersionedArrayList) {
      final long v = ((Long) other.getVersion()).longValue();
      synchronized(this) {
        return this.version > v;
      }
    } else {
      final Comparable o = other.getVersion();
      return getVersion().compareTo(o) > 0;
    } 
  }
  
  public boolean isOlderThan(Versionable other) {
    if (other instanceof VersionedArrayList) {
      final long v;
      synchronized(other) {
        v = ((VersionedArrayList) other).version;        
      }
      synchronized(this) {
        return this.version < v;
      }
    } else {
      final Comparable o = other.getVersion();
      return getVersion().compareTo(o) < 0;
    } 
  }
  
  public boolean isSame(Versionable other)
  {
    if (other instanceof VersionedArrayList) {
      final long v;
      synchronized(other) {
        v = ((VersionedArrayList) other).version;        
      }
      synchronized(this) {
        return this.version == v;
      }
    } else {
      final Comparable o = other.getVersion();
      return getVersion().compareTo(o) == 0;
    } 
  }

//private synchronized void incrementVersion(String op)
  private synchronized void incrementVersion()
  {
// DEBUG
//    {
//      StringWriter s = new StringWriter();
//      final String pre = 
//        "o=" + op + 
//        ":t=" + System.currentTimeMillis() + 
//        ":m=" + InternalDistributedSystem.getAnyInstance().getDistributedMember().toString() + ": ";
//      s.write(pre);
//      PrintWriter p = new PrintWriter(s);
//      new Exception().fillInStackTrace().printStackTrace(p);
//      
//      ArrayList newList = new ArrayList(this.vhist);
//      newList.add(pre); // Capture what code added this version
//      this.vhist = Collections.unmodifiableList(newList);
//    }
    
    ++this.version;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy