/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.browse;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.content.*;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.handle.HandleManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* Entity class to represent an item that is being used to generate Browse
* results. This behaves in many was similar to the Item object, but its
* metadata handling has been further optimised for performance in both
* reading and writing, and it does not deal with other objects related to
* items
*
* FIXME: this class violates some of the encapsulation of the Item, but there is
* unfortunately no way around this until DAOs and an interface are provided
* for the Item class.
*
* @author Richard Jones
*
*/
public class BrowseItem extends DSpaceObject
{
/** Logger */
private static Logger log = Logger.getLogger(BrowseItem.class);
/** a List of all the metadata */
private List<Metadatum> metadata = new ArrayList<Metadatum>();
/** database id of the item */
private int id = -1;
/** is the item in the archive */
private boolean in_archive = true;
/** is the item withdrawn */
private boolean withdrawn = false;
/** is the item discoverable */
private boolean discoverable = true;
/** item handle */
private String handle = null;
/**
* Construct a new browse item with the given ourContext and the database id
*
* @param context the DSpace ourContext
* @param id the database id of the item
* @param in_archive
* @param withdrawn
*/
public BrowseItem(Context context, int id, boolean in_archive, boolean withdrawn, boolean discoverable) {
super(context);
this.id = id;
this.in_archive = in_archive;
this.withdrawn = withdrawn;
this.discoverable = discoverable;
}
/**
* Get String array of metadata values matching the given parameters
*
* @param schema metadata schema
* @param element metadata element
* @param qualifier metadata qualifier
* @param lang metadata language
* @return array of matching values
* @throws SQLException
*/
public Metadatum[] getMetadata(String schema, String element, String qualifier, String lang) {
try
{
BrowseItemDAO dao = BrowseDAOFactory.getItemInstance(ourContext);
// if the qualifier is a wildcard, we have to get it out of the
// database
if (Item.ANY.equals(qualifier))
{
try {
return dao.queryMetadata(id, schema, element, qualifier, lang);
} catch (SQLException e) {
log.error("caught exception: ", e);
}
}
if (!metadata.isEmpty())
{
List<Metadatum> values = new ArrayList<Metadatum>();
Iterator<Metadatum> i = metadata.iterator();
while (i.hasNext())
{
Metadatum dcv = i.next();
if (match(schema, element, qualifier, lang, dcv))
{
values.add(dcv);
}
}
if (values.isEmpty())
{
Metadatum[] dcvs = new Metadatum[0];
try {
dcvs = dao.queryMetadata(id, schema, element, qualifier, lang);
} catch (SQLException e) {
log.error("caught exception: ", e);
}
if (dcvs != null)
{
Collections.addAll(metadata, dcvs);
}
return dcvs;
}
// else, Create an array of matching values
Metadatum[] valueArray = new Metadatum[values.size()];
valueArray = (Metadatum[]) values.toArray(valueArray);
return valueArray;
}
else
{
Metadatum[] dcvs = new Metadatum[0];
try {
dcvs = dao.queryMetadata(id, schema, element, qualifier, lang);
} catch (SQLException e) {
log.error("caught exception: ", e);
}
if (dcvs != null)
{
Collections.addAll(metadata, dcvs);
}
return dcvs;
}
}
catch (BrowseException be)
{
log.error("caught exception: ", be);
return null;
}
}
/**
* Get the type of object. This object masquerades as an Item, so this
* returns the value of Constants.ITEM
*
*@return Constants.ITEM
*/
public int getType()
{
return Constants.ITEM;
}
/**
* @deprecated
* @param real
*/
public int getType(boolean real)
{
if (!real)
{
return Constants.ITEM;
}
else
{
return getType();
}
}
/**
* get the database id of the item
*
* @return database id of item
*/
public int getID()
{
return id;
}
/**
* Set the database id of the item
*
* @param id the database id of the item
*/
public void setID(int id)
{
this.id = id;
}
/**
* Utility method for pattern-matching metadata elements. This
* method will return <code>true</code> if the given schema,
* element, qualifier and language match the schema, element,
* qualifier and language of the <code>Metadatum</code> object passed
* in. Any or all of the element, qualifier and language passed
* in can be the <code>Item.ANY</code> wildcard.
*
* @param schema
* the schema for the metadata field. <em>Must</em> match
* the <code>name</code> of an existing metadata schema.
* @param element
* the element to match, or <code>Item.ANY</code>
* @param qualifier
* the qualifier to match, or <code>Item.ANY</code>
* @param language
* the language to match, or <code>Item.ANY</code>
* @param dcv
* the Dublin Core value
* @return <code>true</code> if there is a match
*/
private boolean match(String schema, String element, String qualifier,
String language, Metadatum dcv)
{
// We will attempt to disprove a match - if we can't we have a match
if (!element.equals(Item.ANY) && !element.equals(dcv.element))
{
// Elements do not match, no wildcard
return false;
}
if (qualifier == null)
{
// Value must be unqualified
if (dcv.qualifier != null)
{
// Value is qualified, so no match
return false;
}
}
else if (!qualifier.equals(Item.ANY))
{
// Not a wildcard, so qualifier must match exactly
if (!qualifier.equals(dcv.qualifier))
{
return false;
}
}
if (language == null)
{
// Value must be null language to match
if (dcv.language != null)
{
// Value is qualified, so no match
return false;
}
}
else if (!language.equals(Item.ANY))
{
// Not a wildcard, so language must match exactly
if (!language.equals(dcv.language))
{
return false;
}
}
else if (!schema.equals(Item.ANY))
{
if (dcv.schema != null && !dcv.schema.equals(schema))
{
// The namespace doesn't match
return false;
}
}
// If we get this far, we have a match
return true;
}
/* (non-Javadoc)
* @see org.dspace.content.DSpaceObject#getHandle()
*/
public String getHandle()
{
// Get our Handle if any
if (this.handle == null)
{
try
{
this.handle = HandleManager.findHandle(ourContext, this);
}
catch (SQLException e)
{
log.error("caught exception: ", e);
}
}
return this.handle;
}
/**
* Get a thumbnail object out of the item.
*
* Warning: using this method actually instantiates an Item, which has a
* corresponding performance hit on the database during browse listing
* rendering. That's your own fault for wanting to put images on your
* browse page!
*
* @throws SQLException
*/
public Thumbnail getThumbnail()
throws SQLException
{
// instantiate an item for this one. Not nice.
Item item = Item.find(ourContext, id);
if (item == null)
{
return null;
}
// now go sort out the thumbnail
// if there's no original, there is no thumbnail
Bundle[] original = item.getBundles("ORIGINAL");
if (original.length == 0)
{
return null;
}
// if multiple bitstreams, check if the primary one is HTML
boolean html = false;
if (original[0].getBitstreams().length > 1)
{
Bitstream[] bitstreams = original[0].getBitstreams();
for (int i = 0; (i < bitstreams.length) && !html; i++)
{
if (bitstreams[i].getID() == original[0].getPrimaryBitstreamID())
{
html = bitstreams[i].getFormat().getMIMEType().equals("text/html");
}
}
}
// now actually pull out the thumbnail (ouch!)
Bundle[] thumbs = item.getBundles("THUMBNAIL");
// if there are thumbs and we're not dealing with an HTML item
// then show the thumbnail
if ((thumbs.length > 0) && !html)
{
Bitstream thumbnailBitstream;
Bitstream originalBitstream;
if ((original[0].getBitstreams().length > 1) && (original[0].getPrimaryBitstreamID() > -1))
{
originalBitstream = Bitstream.find(ourContext, original[0].getPrimaryBitstreamID());
thumbnailBitstream = thumbs[0].getBitstreamByName(originalBitstream.getName() + ".jpg");
}
else
{
originalBitstream = original[0].getBitstreams()[0];
thumbnailBitstream = thumbs[0].getBitstreams()[0];
}
if ((thumbnailBitstream != null)
&& (AuthorizeManager.authorizeActionBoolean(ourContext, thumbnailBitstream, Constants.READ)))
{
return new Thumbnail(thumbnailBitstream, originalBitstream);
}
}
return null;
}
public String getName()
{
return getMetadataFirstValue(MetadataSchema.DC_SCHEMA, "title", null, Item.ANY);
}
@Override
public void update() throws SQLException, AuthorizeException
{
}
@Override
public void updateLastModified()
{
}
public boolean isArchived()
{
return in_archive;
}
public boolean isWithdrawn()
{
return withdrawn;
}
public boolean isDiscoverable() {
return discoverable;
}
}