Package org.dspace.app.xmlui.utils

Source Code of org.dspace.app.xmlui.utils.DSpaceValidity

/*
* DSpaceValidity.java
*
* Version: $Revision: 3992 $
*
* Date: $Date: 2009-07-01 21:07:29 +0000 (Wed, 01 Jul 2009) $
*
* Copyright (c) 2002, Hewlett-Packard Company and Massachusetts
* Institute of Technology.  All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* - Neither the name of the Hewlett-Packard Company nor the name of the
* Massachusetts Institute of Technology nor the names of their
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/

package org.dspace.app.xmlui.utils;

import java.io.IOException;
import java.sql.SQLException;

import org.apache.cocoon.util.HashUtil;
import org.apache.excalibur.source.SourceValidity;
import org.dspace.browse.BrowseItem;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DCValue;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;

/**
* This is a validity object specifically implemented for the caching
* needs of DSpace, Manakin, and Cocoon.
*
* The basic idea is that each time a DSpace object rendered by a cocoon
* component the object and everything about it that makes it unique should
* be reflected in the validity object for the component. By following this
* principle if the object has been updated externally then the cache will be
* invalidated.
*
* This DSpaceValidity object makes this processes easier by abstracting out
* the processes of determining what is unique about a DSpace object. A class
* is expected to create a new DSpaceValidity object and add() to it all
* DSpaceObjects that are rendered by the component. This validity object will
* serialize all those objects to a string, take a hash of the string and compare
* the hash of the string for any updates.
*
*
* @author Scott Phillips
*/

public class DSpaceValidity implements SourceValidity
{
 
  private static final long serialVersionUID = 1L;

  /** The validityKey while it is being build, once it is completed. */
    protected StringBuffer validityKey;
   
    /** Simple flag to note if the object has been completed. */
    protected boolean completed = false;
   
    /** A hash of the validityKey taken after completetion */
    protected long hash;
   
    /** The time when the validity is no longer assumed to be valid */
    protected long assumedValidityTime = 0;
   
    /** The length of time that a cache is assumed to be valid */
    protected long assumedValidityDelay = 0;

    /**
     * Create a new DSpace validity object.
     *
     * @param initialValidityKey
     *      The initial string
     */
    public DSpaceValidity(String initialValidityKey)
    {
        this.validityKey = new StringBuffer();

        if (initialValidityKey != null)
           this.validityKey.append(initialValidityKey);
    }

    public DSpaceValidity()
    {
        this(null);
    }
   
    /**
     * Complete this validity object. After the completion no more
     * objects may be added to the validity object and the object
     * will return as valid.
     */
    public DSpaceValidity complete()
    {   
        this.completed = true;
        this.hash = HashUtil.hash(validityKey);
        this.validityKey = null;
       
        // Set the forced validity time.
        if (assumedValidityDelay > 0)
          resetAssumedValidityTime();
       
        return this;
    }
   
    /**
     * Set the time delay for how long this cache will be assumed
     * to be valid. When it is assumed valid no other checks will be
     * made to consider it's validity, and once the time has expired
     * a full validation will occure on the next cache hit. If the
     * cache proves to be validated on this hit then the assumed
     * validity timer is reset.
     *
     * @param milliseconds The delay time in millieseconds.
     */
    public void setAssumedValidityDelay(long milliseconds )
    {
      // record the delay time.
      this.assumedValidityDelay = milliseconds;
     
      // Also add the delay time to the validity hash so if the
      // admin changes the delay time then all the previous caches
      // are invalidated.
      this.validityKey.append("AssumedValidityDelay:"+milliseconds);
    }
   
    /**
     * Set the time delay for how long this cache will be assumed to be valid.
     *
     * This method takes a string which is parsed for the delay time, the string
     * must be of the following form: "<integer> <scale>" where scale is days,
     * hours, minutes, or seconds.
     *
     * Examples: "1 day" or "12 hours" or "1 hour" or "30 minutes"
     *
     * See the setAssumedValidityDelay(long) for more information.
     *
     * @param delay The delay time in a variable scale.
     */
    public void setAssumedValidityDelay(String delay)
    {
      if (delay == null || delay.length() == 0)
        return;
     
      String[] parts = delay.split(" ");
     
      if (parts == null || parts.length != 2)
        throw new IllegalArgumentException("Error unable to parse the assumed validity delay time: \""+delay+"\". All delays must be of the form \"<integer> <scale>\" where scale is either seconds, minutes, hours, or days.");

      long milliseconds = 0;
     
      long value = 0;
      try { value = Long.valueOf(parts[0]); }
      catch (NumberFormatException nfe) {
        throw new IllegalArgumentException("Error unable to parse the assumed validity delay time: \""+delay+"\". All delays must be of the form \"<integer> <scale>\" where scale is either seconds, minutes, hours, or days.",nfe);
      }
     
      String scale = parts[1].toLowerCase();
   
      if (scale.equals("weeks") || scale.equals("week"))
      {
        // milliseconds * seconds * minutes * hours * days * weeks
        // 1000 * 60 * 60 * 24 * 7 * 1 = 604,800,000
        milliseconds = value * 604800000;
      }
      else if (scale.equals("days") || scale.equals("day"))
      {
        // milliseconds * seconds * minutes * hours * days
        // 1000 * 60 * 60 * 24 * 1 = 86,400,000
        milliseconds = value * 86400000;
      }
      else if (scale.equals("hours") || scale.equals("hour"))
      {
        // milliseconds * seconds * minutes * hours
        // 1000 * 60 * 60 * 1 = 3,600,000
        milliseconds = value * 3600000;
      }
      else if (scale.equals("minutes") || scale.equals("minute"))
      {
        // milliseconds * second * minute
        // 1000 * 60 * 1 = 60,000
        milliseconds = value * 60000;
      }
      else if (scale.equals("seconds") || scale.equals("second"))
      {
        // milliseconds * second
        // 1000 * 1 = 1000
        milliseconds = value * 1000;
      }
      else
      {
        throw new IllegalArgumentException("Error unable to parse the assumed validity delay time: \""+delay+"\". All delays must be of the form \"<integer> <scale>\" where scale is either seconds, minutes, hours, or days.");
        }
     
      // Now set the actualy delay.
      setAssumedValidityDelay(milliseconds);
    }
   
   
    /**
     * Add a DSpace object to the validity. The order inwhich objects
     * are added to the validity object is important, insure that
     * objects are added in the *exact* same order each time a
     * validity object is created.
     *
     * Below are the following transative rules for adding
     * objects, i.e. if an item is added then all the items
     * bundles & bitstreams will also be added.
     *
     * Communities -> logo bitstream
     * Collection -> logo bitstream
     * Item -> bundles -> bitstream
     * Bundles -> bitstreams
     * EPeople -> groups
     *
     * @param dso
     *          The object to add to the validity.
     */
    public void add(DSpaceObject dso) throws SQLException
    {
        if (this.completed)
        {
            throw new IllegalStateException("Can not add DSpaceObject to a completed validity object");
        }
       
        if (dso == null)
        {
          this.validityKey.append("null")
        }
        else if (dso instanceof Community)
        {
            Community community = (Community) dso;

            validityKey.append("Community:");
            validityKey.append(community.getHandle());
            validityKey.append(community.getMetadata("introductory_text"));
            validityKey.append(community.getMetadata("short_description"));
            validityKey.append(community.getMetadata("side_bar_text"));
            validityKey.append(community.getMetadata("copyright_text"));
            validityKey.append(community.getMetadata("name"));
           
            // Add the communities logo
            this.add(community.getLogo());

        }
        else if (dso instanceof Collection)
        {
            Collection collection = (Collection) dso;
           
            validityKey.append("Collection:");
            validityKey.append(collection.getHandle());
            validityKey.append(collection.getMetadata("introductory_text"));
            validityKey.append(collection.getMetadata("short_description"));
            validityKey.append(collection.getMetadata("side_bar_text"));
            validityKey.append(collection.getMetadata("provenance_description"));
            validityKey.append(collection.getMetadata("copyright_text"));
            validityKey.append(collection.getMetadata("license"));
            validityKey.append(collection.getMetadata("name"));
           
            // Add the logo also;
            this.add(collection.getLogo());
           
        }
        else if (dso instanceof Item)
        {
            Item item = (Item) dso;
           
            validityKey.append("Item:");
            validityKey.append(item.getHandle());           
            validityKey.append(item.getOwningCollection());
            validityKey.append(item.getLastModified());
            // Include all metadata values in the validity key.
            DCValue[] dcvs = item.getDC(Item.ANY,Item.ANY,Item.ANY);
            for (DCValue dcv : dcvs)
            {
                validityKey.append(dcv.schema + ".");
                validityKey.append(dcv.element + ".");
                validityKey.append(dcv.qualifier + ".");
                validityKey.append(dcv.language + "=");
                validityKey.append(dcv.value);
            }
           
            for(Bundle bundle : item.getBundles())
            {
                // Add each of the items bundles & bitstreams.
                this.add(bundle);
            }
        }
        else if (dso instanceof BrowseItem)
        {
          BrowseItem browseItem = (BrowseItem) dso;
         
          validityKey.append("BrowseItem:");
          validityKey.append(browseItem.getHandle());
          DCValue[] dcvs = browseItem.getMetadata(Item.ANY, Item.ANY, Item.ANY, Item.ANY);
            for (DCValue dcv : dcvs)
            {
                validityKey.append(dcv.schema + ".");
                validityKey.append(dcv.element + ".");
                validityKey.append(dcv.qualifier + ".");
                validityKey.append(dcv.language + "=");
                validityKey.append(dcv.value);
            }
        }
        else if (dso instanceof Bundle)
        {
            Bundle bundle = (Bundle) dso;
           
            validityKey.append("Bundle:");
            validityKey.append(bundle.getID());
            validityKey.append(bundle.getName());
            validityKey.append(bundle.getPrimaryBitstreamID());
           
            for(Bitstream bitstream : bundle.getBitstreams())
            {
                this.add(bitstream);
            }
        }
        else if (dso instanceof Bitstream)
        {
            Bitstream bitstream = (Bitstream) dso;
           
            validityKey.append("Bundle:");
            validityKey.append(bitstream.getID());
            validityKey.append(bitstream.getSequenceID());
            validityKey.append(bitstream.getName());
            validityKey.append(bitstream.getSource());
            validityKey.append(bitstream.getDescription());
            validityKey.append(bitstream.getChecksum());
            validityKey.append(bitstream.getChecksumAlgorithm());
            validityKey.append(bitstream.getSize());
            validityKey.append(bitstream.getUserFormatDescription());
            validityKey.append(bitstream.getFormat().getDescription());
        }
        else if (dso instanceof EPerson)
        {
            EPerson eperson = (EPerson) dso;
           
            validityKey.append("Bundle:");
            validityKey.append(eperson.getID());
            validityKey.append(eperson.getEmail());
            validityKey.append(eperson.getNetid());
            validityKey.append(eperson.getFirstName());
            validityKey.append(eperson.getLastName());
            validityKey.append(eperson.canLogIn());
            validityKey.append(eperson.getRequireCertificate());
        }
        else if (dso instanceof Group)
        {
            Group group = (Group) dso;
           
            validityKey.append("Group:");
           
            validityKey.append(group.getID());
            validityKey.append(group.getName());
        }
        else
        {
            throw new IllegalArgumentException("DSpaceObject of type '"+dso.getClass().getName()+"' is not supported by the DSpaceValidity object.");
        }   
    }
   
    /**
     * Add a non DSpaceObject to the validity, the object should be
     * seralized into a string form. The order inwhich objects
     * are added to the validity object is important, insure that
     * objects are added in the *exact* same order each time a
     * validity object is created.
     *
     * @param nonDSpaceObject
     *          The non DSpace object to add to the validity.
     */
    public void add(String nonDSpaceObject) throws SQLException
    {
        validityKey.append("String:");
        validityKey.append(nonDSpaceObject);
    }
   
   
   
   
   
   
   
   
    /**
     * This method is used during serializion. When tomcat is shutdown cocoon's in-memory
     * cache is serialized and written to disk to later be read back into memory on start
     * up. When this class is read back into memory the readObject(stream) method will be
     * called.
     *
     * This method will re-read the serialization back into memory but it will then set
     * the assume validity time to zero. This means the next cache hit after a server startup
     * will never be assumed valid. Only after it has been checked once will the regular assume
     * validity mechanism be used.
     *
     * @param in
     * @throws IOException
     * @throws ClassNotFoundException
     */
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
    {
      // Read in this object as normal.
      in.defaultReadObject();
     
      // After reading from serialization do not assume validity anymore until it
      // has been checked at least once.
      this.assumedValidityTime = 0;
    }
   
   
    /**
     * Reset the assume validity time. This should be called only when the validity of this cache
     * has been confirmed to be accurate. This will reset the assume valid timer based upon the
     * configured delay.
     */
    private void resetAssumedValidityTime()
    {
      this.assumedValidityTime = System.currentTimeMillis() + this.assumedValidityDelay;
    }
   
    /**
     * Determine if the cache is still valid
     */
    public int isValid()
    {
        // Return true if we have a hash.
        if (this.completed)
        {
          // Check if we are configured to assume validity for a period of time.
          if (this.assumedValidityDelay > 0)
          {
            // Check if we should assume validitity.
            if (System.currentTimeMillis() < this.assumedValidityTime)
            {
              // Assume the cache is valid with out rechecking another validity object.
              return SourceValidity.VALID;
            }
          }
         
          return SourceValidity.UNKNOWN;
        }
        else
        {
          // This is an error, state. We are being asked whether we are valid before
          // we have been initialized.
            return SourceValidity.INVALID;
        }
    }

    /**
     * Determine if the cache is still valid based
     * upon the other validity object.
     *
     * @param otherObject
     *          The other validity object.
     */
    public int isValid(SourceValidity otherObject)
    {
        if (this.completed)
        {
            if (otherObject instanceof DSpaceValidity)
            {
                DSpaceValidity otherSSV = (DSpaceValidity) otherObject;
                if (hash == otherSSV.hash)
                { 
                  // Both caches have been checked are are considered valid,
                  // now we reset their assumed validity timers for both cache
                  // objects.
                  if (this.assumedValidityDelay > 0)
                    this.resetAssumedValidityTime();
                 
                  if (otherSSV.assumedValidityDelay > 0)
                    otherSSV.resetAssumedValidityTime();
                 
                    return SourceValidity.VALID;
                }
            }
        }

        return SourceValidity.INVALID;
    }
}
TOP

Related Classes of org.dspace.app.xmlui.utils.DSpaceValidity

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.