Package org.dbwiki.data.time

Source Code of org.dbwiki.data.time.VersionIndex

/*
    BEGIN LICENSE BLOCK
    Copyright 2010-2011, Heiko Mueller, Sam Lindley, James Cheney and
    University of Edinburgh

    This file is part of Database Wiki.

    Database Wiki 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.

    Database Wiki 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 Database Wiki.  If not, see <http://www.gnu.org/licenses/>.
    END LICENSE BLOCK
*/
package org.dbwiki.data.time;

import org.dbwiki.data.provenance.Provenance;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;

import org.dbwiki.data.database.DatabaseAttributeNode;
import org.dbwiki.data.database.DatabaseElementNode;
import org.dbwiki.data.database.DatabaseGroupNode;
import org.dbwiki.data.database.DatabaseNode;
import org.dbwiki.data.database.DatabaseTextNode;
import org.dbwiki.exception.WikiFatalException;
import org.dbwiki.exception.data.WikiTimeException;

/** A a version index, listing the versions of an object
* @author jcheney
*
*/
public class VersionIndex {
  /*
   * Private Variables
   */
 
  private Hashtable<String, Version> _versionNameIndex;
  private Vector<Version> _versionList;

 
  /*
   * Constructors
   */
 
  public VersionIndex()  {
    _versionList = new Vector<Version>();
    _versionNameIndex = new Hashtable<String, Version>();
  }

 
  /*
   * Public Methods
   */
  /** Adds a new version
   * Check that there are no duplicates and that the next version being added is the next in the sequence
   */
  public synchronized void add(Version version) throws org.dbwiki.exception.WikiException {
    //System.out.println("DEBUG: "+version.toString());
    if (_versionNameIndex.containsKey(version.name())) {
      throw new WikiTimeException(WikiTimeException.DuplicateVersion, "Version " + version.name() + " already exists");
    }
    if (version.number() != (_versionList.size() + 1)) {
      throw new WikiFatalException("Invalid version number " + version.number() + ". Expected number is " + (_versionList.size() + 1));
    }
   
    _versionList.add(version);
    _versionNameIndex.put(version.name(), version);
  }
 
  /** Get the version at position index in the index
   *
   */
  public synchronized Version get(int index) {
    return _versionList.get(index);
  }

  /** Get a version by its string name
   *
   * @param name
   * @return
   */
  public synchronized Version getByName(String name) {
    String key = name.toUpperCase();
   
    if (!_versionNameIndex.containsKey(key)) {
      return null;
    }
    return _versionNameIndex.get(name);
  }

  /** Get version by its version number, i.e. the id stored in the database
   *
   */
  public synchronized Version getByNumber(int number) throws org.dbwiki.exception.WikiException {
    for (int iVersion = 0; iVersion < this.size(); iVersion++) {
      Version version = this.get(iVersion);
      if (version.number() == number) {
        return version;
      }
    }
    throw new WikiTimeException(WikiTimeException.UnknownVersionNumber, String.valueOf(number));
  }

  /** Get the last version in the index, which is the last in the vector
   *
   */
  public synchronized Version getLastVersion() {
    if (!this.isEmpty()) {
      return _versionList.lastElement();
    } else {
      return null;
    }
  }
 
  /** Gets a new version based on the current date/time, whose number is 1+ size of the index
   * Uses the given provenance record, and uses this as the version index
   * Not clear that this is safe to "add" if version numbers and positions ever get out of sync
   */
  public synchronized Version getNextVersion(Provenance provenance) {
    Date date = new Date();
    String name = new SimpleDateFormat("d MMM yyyy HH:mm:ss").format(date);
    int number = size() + 1;
   
    // FIXME #time: the need for the following hack is symptomatic of
    // fundamental flaws in the design of this class.
    //
    // HACK:
    // make sure we don't get any name clashes through
    // generating multiple versions in the same second!
    if(_versionNameIndex.containsKey(name)) {
      name = name + "(" + number + ")";
    }

    return new Version(size() + 1,
        name,
        date.getTime(), provenance, this);
  }
 
  /** Get the version that was valid at a given date
   *
   * @param date
   * @return
   */
  public synchronized Version getVersionAt(Date date) {
   
    Version version = null;
    for (int iVersion = 0; iVersion < this.size(); iVersion++) {
      if (this.get(iVersion).time() <= date.getTime()) {
        version = this.get(iVersion);
      } else {
        break;
      }
    }
    return version;
  }

  /** Is version index empty?
   *
   * @return
   */
  public synchronized boolean isEmpty() {
    return (_versionList.size() == 0);
  }

  /** Size of the version index
   *
   */
  public synchronized int size() {
    return _versionList.size();
  }

 
 
  /*
   * Private Methods
   */

 
  /** Adds a version to a version hash table
   *
   */
  private void addVersion(int time, Hashtable<Integer, Version> versions) throws org.dbwiki.exception.WikiException {
    Integer key = new Integer(time);
    if (!versions.containsKey(key)) {
      versions.put(key, getByNumber(time));
    }
  }
 
  /** Adds modification points to version hash table.
   * Adds each start and end point to the table except for the end point if the last interval is open.
   * @param timestamp
   * @param versions
   * @throws org.dbwiki.exception.WikiException
   */
  private void addModificationPoints(TimeSequence timestamp, Hashtable<Integer, Version> versions) throws org.dbwiki.exception.WikiException {
    TimeInterval[] intervals = timestamp.intervals();
    for (int iInterval = 0; iInterval < intervals.length; iInterval++) {
      TimeInterval interval = intervals[iInterval];
      this.addVersion(interval.start(), versions);
      if (!interval.isOpen()) {
        this.addVersion(interval.end() + 1, versions);
      }
    }
  }
 
  /** Adds changes relevant to node or its descendants
   * FIXME: This might be better handled in DatabaseElementNode
   * @param element
   * @param versions
   * @throws org.dbwiki.exception.WikiException
   */
  private void addNodeChanges(DatabaseElementNode element, Hashtable<Integer, Version> versions) throws org.dbwiki.exception.WikiException {
    if (element.isAttribute()) {
      DatabaseAttributeNode attribute = (DatabaseAttributeNode)element;
      for (int iValue = 0; iValue < attribute.value().size(); iValue++) {
        DatabaseTextNode value = attribute.value().get(iValue);
        if (value.hasTimestamp()) {
          this.addModificationPoints(value.getTimestamp(), versions);
        }
      }
    } else {
      DatabaseGroupNode group = (DatabaseGroupNode)element;
      for (int iNode = 0; iNode < group.children().size(); iNode++) {
        DatabaseElementNode node = group.children().get(iNode);
        if (node.hasTimestamp()) {
          this.addModificationPoints(node.getTimestamp(),  versions);
        }
        this.addNodeChanges(node,  versions);
      }
    }
  }
 
  /** Get the list of versions where something changed affecting node
   * FIXME #time: Hard to understand, try to simplify.  Seems to side-effect the version index!
   */
  public Vector<Version> getNodeChanges(DatabaseNode node) throws org.dbwiki.exception.WikiException {
    Hashtable<Integer, Version> versions = new Hashtable<Integer, Version>();
   
    addModificationPoints(node.getTimestamp(), versions);
   
    if (node.isElement()) {
      addNodeChanges((DatabaseElementNode)node, versions);
    }
   
    Vector<Version> result = new Vector<Version>();
   
    // Iterate over all versions.
    Iterator<Version> elements = versions.values().iterator();
    while (elements.hasNext()) {
      Version version = elements.next(); // For each version...
      boolean added = false
      if (result.size() > 0) { // if some versions have been added
        for (int iVersion = 0; iVersion < result.size(); iVersion++) {
          // add this version in place of the first modification point whose number is greater.
          if (version.number() < result.get(iVersion).number()) {
            // add this version in position of iVersion
            result.add(iVersion, version);
            added = true;
            break;
          }
        }
      }
      // If no versions have been added then add this version.
      if (!added) {
        result.add(version);
      }
    }
    return result;
  }
}
TOP

Related Classes of org.dbwiki.data.time.VersionIndex

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.