/**
* 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.curate;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Properties;
import org.apache.log4j.Logger;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.ItemIterator;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.handle.HandleManager;
/**
* AbstractCurationTask encapsulates a few common patterns of task use,
* resources, and convenience methods.
*
* @author richardrodgers
*/
public abstract class AbstractCurationTask implements CurationTask
{
// invoking curator
protected Curator curator = null;
// curator-assigned taskId
protected String taskId = null;
// optional task configuration properties
private Properties taskProps = null;
// logger
private static Logger log = Logger.getLogger(AbstractCurationTask.class);
@Override
public void init(Curator curator, String taskId) throws IOException
{
this.curator = curator;
this.taskId = taskId;
}
@Override
public abstract int perform(DSpaceObject dso) throws IOException;
/**
* Distributes a task through a DSpace container - a convenience method
* for tasks declaring the <code>@Distributive</code> property.
* <P>
* This method invokes the 'performObject()' method on the current DSO, and
* then recursively invokes the 'performObject()' method on all DSOs contained
* within the current DSO. For example: if a Community is passed in, then
* 'performObject()' will be called on that Community object, as well as
* on all SubCommunities/Collections/Items contained in that Community.
* <P>
* Individual tasks MUST override either the <code>performObject</code> method or
* the <code>performItem</code> method to ensure the task is run on either all
* DSOs or just all Items, respectively.
*
* @param dso current DSpaceObject
* @throws IOException
*/
protected void distribute(DSpaceObject dso) throws IOException
{
try
{
//perform task on this current object
performObject(dso);
//next, we'll try to distribute to all child objects, based on container type
int type = dso.getType();
if (Constants.COLLECTION == type)
{
ItemIterator iter = ((Collection)dso).getItems();
while (iter.hasNext())
{
performObject(iter.next());
}
}
else if (Constants.COMMUNITY == type)
{
Community comm = (Community)dso;
for (Community subcomm : comm.getSubcommunities())
{
distribute(subcomm);
}
for (Collection coll : comm.getCollections())
{
distribute(coll);
}
}
else if (Constants.SITE == type)
{
Community[] topComm = Community.findAllTop(Curator.curationContext());
for (Community comm : topComm)
{
distribute(comm);
}
}
}
catch (SQLException sqlE)
{
throw new IOException(sqlE.getMessage(), sqlE);
}
}
/**
* Performs task upon a single DSpaceObject. Used in conjunction with the
* <code>distribute</code> method to run a single task across multiple DSpaceObjects.
* <P>
* By default, this method just wraps a call to <code>performItem</code>
* for each Item Object.
* <P>
* You should override this method if you want to use
* <code>distribute</code> to run your task across multiple DSpace Objects.
* <P>
* Either this method or <code>performItem</code> should be overridden if
* <code>distribute</code> method is used.
*
* @param dso the DSpaceObject
* @throws SQLException
* @throws IOException
*/
protected void performObject(DSpaceObject dso) throws SQLException, IOException
{
// By default this method only performs tasks on Items
// (You should override this method if you want to perform task on all objects)
if(dso.getType()==Constants.ITEM)
{
performItem((Item)dso);
}
//no-op for all other types of DSpace Objects
}
/**
* Performs task upon a single DSpace Item. Used in conjunction with the
* <code>distribute</code> method to run a single task across multiple Items.
* <P>
* You should override this method if you want to use
* <code>distribute</code> to run your task across multiple DSpace Items.
* <P>
* Either this method or <code>performObject</code> should be overridden if
* <code>distribute</code> method is used.
*
* @param item the DSpace Item
* @throws SQLException
* @throws IOException
*/
protected void performItem(Item item) throws SQLException, IOException
{
// no-op - override when using 'distribute' method
}
@Override
public int perform(Context ctx, String id) throws IOException
{
DSpaceObject dso = dereference(ctx, id);
return (dso != null) ? perform(dso) : Curator.CURATE_FAIL;
}
/**
* Returns a DSpaceObject for passed identifier, if it exists
*
* @param ctx
* DSpace context
* @param id
* canonical id of object
* @return dso
* DSpace object, or null if no object with id exists
* @throws IOException
*/
protected DSpaceObject dereference(Context ctx, String id) throws IOException
{
try
{
return HandleManager.resolveToObject(ctx, id);
}
catch (SQLException sqlE)
{
throw new IOException(sqlE.getMessage(), sqlE);
}
}
/**
* Sends message to the reporting stream
*
* @param message
* the message to stream
*/
protected void report(String message)
{
curator.report(message);
}
/**
* Assigns the result of the task performance
*
* @param result
* the result string
*/
protected void setResult(String result)
{
curator.setResult(taskId, result);
}
/**
* Returns task configuration property value for passed name, else
* <code>null</code> if no properties defined or no value for passed key.
*
* @param name
* the property name
* @return value
* the property value, or null
*
*/
protected String taskProperty(String name)
{
if (taskProps == null)
{
// load properties
taskProps = new Properties();
StringBuilder modName = new StringBuilder();
for (String segment : taskId.split("\\."))
{
// load property segments if present
modName.append(segment);
Properties modProps = ConfigurationManager.getProperties(modName.toString());
if (modProps != null)
{
taskProps.putAll(modProps);
}
modName.append(".");
}
// warn if *no* properties found
if (taskProps.size() == 0)
{
log.warn("Warning: No configuration properties found for task: " + taskId);
}
}
return taskProps.getProperty(name);
}
/**
* Returns task configuration integer property value for passed name, else
* passed default value if no properties defined or no value for passed key.
*
* @param name
* the property name
* @param defaultValue value
* the default value
* @return value
* the property value, or default value
*
*/
protected int taskIntProperty(String name, int defaultValue)
{
int intVal = defaultValue;
String strVal = taskProperty(name);
if (strVal != null)
{
try
{
intVal = Integer.parseInt(strVal.trim());
}
catch(NumberFormatException nfE)
{
log.warn("Warning: Number format error in module: " + taskId + " property: " + name);
}
}
return intVal;
}
/**
* Returns task configuration long property value for passed name, else
* passed default value if no properties defined or no value for passed key.
*
* @param name
* the property name
* @param defaultValue value
* the default value
* @return value
* the property value, or default
*
*/
protected long taskLongProperty(String name, long defaultValue)
{
long longVal = defaultValue;
String strVal = taskProperty(name);
if (strVal != null)
{
try
{
longVal = Long.parseLong(strVal.trim());
}
catch(NumberFormatException nfE)
{
log.warn("Warning: Number format error in module: " + taskId + " property: " + name);
}
}
return longVal;
}
/**
* Returns task configuration boolean property value for passed name, else
* passed default value if no properties defined or no value for passed key.
*
* @param name
* the property name
* @param defaultValue value
* the default value
* @return value
* the property value, or default
*
*/
protected boolean taskBooleanProperty(String name, boolean defaultValue)
{
String strVal = taskProperty(name);
if (strVal != null)
{
strVal = strVal.trim();
return strVal.equalsIgnoreCase("true") ||
strVal.equalsIgnoreCase("yes");
}
return defaultValue;
}
}