/**
* 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.sword;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamFormatService;
import org.dspace.core.Context;
import org.dspace.content.Collection;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.BitstreamFormat;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.purl.sword.base.SWORDErrorException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.sql.SQLException;
import org.apache.log4j.Logger;
/**
* @author Richard Jones
*
* Class to represent the principal configurations of the SWORD
* service being offered. Not all configuration is available through
* this class, but the most useful common options, and those with
* default values are available
*
* Note that changes to values via the API will not be persisted
* between SWORD requests.
*
* For detailed descriptions of configuration values, see the sword
* configuration documentation
*
*/
public class SWORDConfiguration
{
/** logger */
public static final Logger log = Logger.getLogger(SWORDConfiguration.class);
protected BitstreamFormatService bitstreamFormatService = ContentServiceFactory
.getInstance().getBitstreamFormatService();
protected ConfigurationService configurationService = DSpaceServicesFactory
.getInstance().getConfigurationService();
/** whether we can support noOp */
private boolean noOp = true;
/** whether we can be verbose */
private boolean verbose = true;
/** what our default max upload size is */
private int maxUploadSize = -1;
/** do we support mediation */
private boolean mediated = false;
/** should we keep the original package as bitstream */
private boolean keepOriginal = false;
/** item bundle in which sword deposits are stored */
private String swordBundle = "SWORD";
/** should we keep the original package as a file on ingest error */
private boolean keepPackageOnFailedIngest = false;
/** location of directory to store packages on ingest error */
private String failedPackageDir = null;
/** Accepted formats */
private List<String> swordaccepts;
/**
* Initialise the sword configuration. It is at this stage that the
* object will interrogate the DSpace Configuration for details
*/
public SWORDConfiguration()
{
// set the max upload size
int mus = configurationService.getIntProperty(
"sword-server.max-upload-size");
if (mus > 0)
{
this.maxUploadSize = mus;
}
// set the mediation value
this.mediated = configurationService.getBooleanProperty(
"sword-server.on-behalf-of.enable");
// find out if we keep the original as bitstream
this.keepOriginal = configurationService.getBooleanProperty(
"sword-server.keep-original-package");
// get the sword bundle
String bundle = configurationService.getProperty(
"sword-server.bundle.name");
if (bundle != null && "".equals(bundle))
{
this.swordBundle = bundle;
}
// find out if we keep the package as a file in specified directory
this.keepPackageOnFailedIngest = configurationService
.getBooleanProperty("sword-server.keep-package-on-fail", false);
// get directory path and name
this.failedPackageDir = configurationService.getProperty(
"sword-server.failed-package.dir");
// Get the accepted formats
String[] acceptsFormats = configurationService
.getArrayProperty("sword-server.accepts");
swordaccepts = new ArrayList<String>();
if (acceptsFormats == null)
{
acceptsFormats = new String[]{"application/zip"};
}
for (String element : acceptsFormats)
{
swordaccepts.add(element.trim());
}
}
/**
* Get the bundle name that SWORD will store its original deposit
* packages in, when storing them inside an item.
*
* @return bundle name where to store the original deposit packages
*/
public String getSwordBundle()
{
return swordBundle;
}
/**
* Set the bundle name that SWORD will store its original deposit
* packages in, when storing them inside an item.
*
* @param swordBundle set bundle name where to store the original
* deposit packages
*/
public void setSwordBundle(String swordBundle)
{
this.swordBundle = swordBundle;
}
/**
* Is this a no-op deposit?
*
* @return true if this is a no-op deposit
*/
public boolean isNoOp()
{
return noOp;
}
/**
* Set whether this is a no-op deposit.
*
* @param noOp sets whether this is a no-op deposit
*/
public void setNoOp(boolean noOp)
{
this.noOp = noOp;
}
/**
* Is this a verbose deposit?
*
* @return true if is verbose deposit
*/
public boolean isVerbose()
{
return verbose;
}
/**
* Set whether this is a verbose deposit.
*
* @param verbose is verbose deposit?
*/
public void setVerbose(boolean verbose)
{
this.verbose = verbose;
}
/**
* What is the max upload size (in bytes) for the SWORD interface?
*
* @return maximum upload size
*/
public int getMaxUploadSize()
{
return maxUploadSize;
}
/**
* set the max upload size (in bytes) for the SWORD interface
*
* @param maxUploadSize maximum upload size to set
*/
public void setMaxUploadSize(int maxUploadSize)
{
this.maxUploadSize = maxUploadSize;
}
/**
* Does the server support mediated deposit (aka on-behalf-of)?
*
* @return true if server supports mediated deposit
*/
public boolean isMediated()
{
return mediated;
}
/**
* Set whether the server supports mediated deposit (aka on-behalf-of).
*
* @param mediated set whether server supports mediated deposit
*/
public void setMediated(boolean mediated)
{
this.mediated = mediated;
}
/**
* Should the repository keep the original package?
*
* @return true if repository keeps copies of original package
*/
public boolean isKeepOriginal()
{
return keepOriginal;
}
/**
* Set whether the repository should keep copies of the original package.
*
* @param keepOriginal set whether to keep copies of original package
*/
public void setKeepOriginal(boolean keepOriginal)
{
this.keepOriginal = keepOriginal;
}
/**
* set whether the repository should write file of the original package if ingest fails
*
* @param keepOriginalOnFail set whether to keep copies of original
* package if ingest fails
*/
public void setKeepPackageOnFailedIngest(boolean keepOriginalOnFail)
{
keepPackageOnFailedIngest = keepOriginalOnFail;
}
/**
* should the repository write file of the original package if ingest fails
*
* @return true if repository keeps copies of original package if ingest
* fails
*/
public boolean isKeepPackageOnFailedIngest()
{
return keepPackageOnFailedIngest;
}
/**
* set the directory to write file of the original package
*
* @param dir directory where original package is kept
*/
public void setFailedPackageDir(String dir)
{
failedPackageDir = dir;
}
/**
* directory location of the files with original packages
* for failed ingests
*
* @return dir directory where original package is kept
*/
public String getFailedPackageDir()
{
return failedPackageDir;
}
/**
* Get the list of MIME types that the given DSpace object will
* accept as packages.
*
* @param context
* The relevant DSpace Context.
* @param dso
* target DSpace object
* @return the list of MIME types that the given DSpace object will
* accept as packages.
* @throws DSpaceSWORDException
* can be thrown by the internals of the DSpace SWORD implementation
*/
public List<String> getAccepts(Context context, DSpaceObject dso)
throws DSpaceSWORDException
{
try
{
List<String> accepts = new ArrayList<String>();
if (dso instanceof Collection)
{
for (String format : swordaccepts)
{
accepts.add(format);
}
}
else if (dso instanceof Item)
{
List<BitstreamFormat> bfs = bitstreamFormatService
.findNonInternal(context);
for (BitstreamFormat bf : bfs)
{
accepts.add(bf.getMIMEType());
}
}
return accepts;
}
catch (SQLException e)
{
throw new DSpaceSWORDException(e);
}
}
/**
* Get the list of MIME types that a Collection will accept as packages
*
* @return the list of MIME types
* @throws DSpaceSWORDException
* can be thrown by the internals of the DSpace SWORD implementation
*/
public List<String> getCollectionAccepts() throws DSpaceSWORDException
{
List<String> accepts = new ArrayList<String>();
for (String format : swordaccepts)
{
accepts.add(format);
}
return accepts;
}
/**
* Get a map of packaging URIs to Q values for the packaging types which
* the given collection will accept.
*
* The URI should be a unique identifier for the packaging type,
* such as:
*
* http://purl.org/net/sword-types/METSDSpaceSIP
*
* and the Q value is a floating point between 0 and 1 which defines
* how much the server "likes" this packaging type
*
* @param col
* target collection
* @return map of packaging URIs to Q values for the packaging types which
* the given collection will accept.
*/
public Map<String, Float> getAcceptPackaging(Collection col)
{
Map<String, String> identifiers = new HashMap<String, String>();
Map<String, String> qs = new HashMap<String, String>();
String handle = col.getHandle();
// build the holding maps of identifiers and q values
String acceptPackagingPrefix = "sword-server.accept-packaging";
List<String> keys = configurationService.getPropertyKeys(acceptPackagingPrefix);
for (String key : keys)
{
// extract the configuration into the holding Maps
String suffix = key.substring(acceptPackagingPrefix.length()+1);
String[] bits = suffix.split("\\.");
if (bits.length == 2)
{
// global settings
String value = configurationService.getProperty(key);
if (bits[1].equals("identifier"))
{
identifiers.put(bits[0], value);
}
else if (bits[1].equals("q"))
{
qs.put(bits[0], value);
}
}
// collection settings
if (bits.length == 3 && bits[0].equals(handle))
{
// this is configuration for our collection
String value = configurationService.getProperty(key);
if (bits[2].equals("identifier"))
{
identifiers.put(bits[1], value);
}
else if (bits[2].equals("q"))
{
qs.put(bits[1], value);
}
}
}
// merge the holding maps into the Accept Packaging settings
Map<String, Float> ap = new HashMap<String, Float>();
for (String ik : identifiers.keySet())
{
String id = identifiers.get(ik);
String qv = qs.get(ik);
Float qf = Float.parseFloat(qv);
ap.put(id, qf);
}
return ap;
}
/**
* Is the given packaging/media type supported by the given DSpace
* object?
*
* @param mediaType
* packaging/media type to check
* @param dso
* target DSpace object
* @return true if the given packaging/media type is supported by the
* given DSpace object
* @throws DSpaceSWORDException
* can be thrown by the internals of the DSpace SWORD implementation
* @throws SWORDErrorException on generic SWORD exception
*/
public boolean isSupportedMediaType(String mediaType, DSpaceObject dso)
throws DSpaceSWORDException, SWORDErrorException
{
if (mediaType == null || "".equals(mediaType))
{
return true;
}
if (dso instanceof Collection)
{
Map<String, Float> accepts = this
.getAcceptPackaging((Collection) dso);
for (String accept : accepts.keySet())
{
if (accept.equals(mediaType))
{
return true;
}
}
}
else if (dso instanceof Item)
{
// items don't unpackage, so they don't care what the media type is
return true;
}
return false;
}
/**
* Is the given content MIME type acceptable to the given DSpace object?
*
* @param context
* The relevant DSpace Context.
* @param type
* MIME type to check
* @param dso
* target DSpace object
* @return true if the given content MIME type is acceptable
* to the given DSpace object
* @throws DSpaceSWORDException
* can be thrown by the internals of the DSpace SWORD implementation
*/
public boolean isAcceptableContentType(Context context, String type,
DSpaceObject dso)
throws DSpaceSWORDException
{
List<String> accepts = this.getAccepts(context, dso);
return accepts.contains(type);
}
/**
* Get the temp directory for storing files during deposit.
*
* @return temp directory for storing files during deposit
* @throws DSpaceSWORDException
* can be thrown by the internals of the DSpace SWORD implementation
*/
public String getTempDir()
throws DSpaceSWORDException
{
return (configurationService.getProperty("upload.temp.dir") != null)
? configurationService.getProperty("upload.temp.dir")
: System.getProperty("java.io.tmpdir");
}
}