AIP Export Work : Add a new METSRightsCrosswalk which can translate DSpace ResourcePolicies to/from METSRights Schema (http://cosimo.stanford.edu/sdr/metsrights.xsd) -- this allows ResourcePolicies to be backed up and restored via AIPs. For AIPs, enabled METSRights by default in dspace.cfg. Also enhanced AbstractMETSDisseminator to allow you to export METS' amdSec for DSpace BUNDLES (necessary, as Bundles can have ResourcePolicies). Other various comment enhancements to a few other Crosswalks/Disseminators. @TODO -- Although export of METRights works well, the re-ingest is not perfect as it doesn't integrate yet with Mark Wood's RoleIngester.

git-svn-id: http://scm.dspace.org/svn/repo/dspace/trunk@5331 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
Tim Donohue
2010-09-02 20:27:50 +00:00
parent 0873776830
commit 4918db51ec
5 changed files with 773 additions and 69 deletions

View File

@@ -107,6 +107,7 @@ public class AIPTechMDCrosswalk
*
* @return array of namespaces, which may be empty.
*/
@Override
public Namespace[] getNamespaces()
{
Namespace result[] = new Namespace[1];
@@ -125,6 +126,7 @@ public class AIPTechMDCrosswalk
* @return SchemaLocation string, including URI namespace, followed by
* whitespace and URI of XML schema document, or empty string if unknown.
*/
@Override
public String getSchemaLocation()
{
return "";
@@ -137,10 +139,21 @@ public class AIPTechMDCrosswalk
* @param dso dspace object, e.g. an <code>Item</code>.
* @return true when disseminator is capable of producing metadata.
*/
@Override
public boolean canDisseminate(DSpaceObject dso)
{
//can only Disseminate SITE, COMMUNITY, COLLECTION, ITEM, BITSTREAM
if(dso.getType()==Constants.SITE
|| dso.getType()==Constants.COMMUNITY
|| dso.getType()==Constants.COLLECTION
|| dso.getType()==Constants.ITEM
|| dso.getType()==Constants.BITSTREAM)
{
return true;
}
else
return false;
}
/**
* Predicate: Does this disseminator prefer to return a list of Elements,
@@ -156,6 +169,7 @@ public class AIPTechMDCrosswalk
*
* @return true when disseminator prefers you call disseminateList().
*/
@Override
public boolean preferList()
{
return false;
@@ -180,6 +194,7 @@ public class AIPTechMDCrosswalk
* @throws SQLException Database failure in services this calls
* @throws AuthorizeException current user not authorized for this operation.
*/
@Override
public List disseminateList(DSpaceObject dso)
throws CrosswalkException, IOException, SQLException,
AuthorizeException
@@ -203,6 +218,7 @@ public class AIPTechMDCrosswalk
* @throws SQLException Database failure in services this calls
* @throws AuthorizeException current user not authorized for this operation.
*/
@Override
public Element disseminateElement(DSpaceObject dso)
throws CrosswalkException, IOException, SQLException,
AuthorizeException
@@ -310,6 +326,7 @@ public class AIPTechMDCrosswalk
* and feed that to the transformation, since it may get handled
* differently than a List of metadata elements.
*/
@Override
public void ingest(Context context, DSpaceObject dso, Element root)
throws CrosswalkException, IOException, SQLException, AuthorizeException
{
@@ -322,6 +339,7 @@ public class AIPTechMDCrosswalk
* these correspond directly to Item.addMetadata() calls so
* they are simply executed.
*/
@Override
public void ingest(Context context, DSpaceObject dso, List dimList)
throws CrosswalkException,
IOException, SQLException, AuthorizeException
@@ -499,13 +517,4 @@ public class AIPTechMDCrosswalk
log.warn("Failed to find or create bitstream format named \""+bsfShortName+"\"");
}
}
// parse the hdl: URI/URN format into a raw Handle.
private String decodeHandleURI(String value)
{
if (value.startsWith("hdl:"))
return value.substring(4);
else
return null;
}
}

View File

@@ -0,0 +1,600 @@
/*
* METSRightsCrosswalk.java
*
* Version: $Revision: 5265 $
*
* Date: $Date: 2010-08-13 15:10:32 -0500 (Fri, 13 Aug 2010) $
*
* Copyright (c) 2002-2009, The DSpace Foundation. 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 DSpace Foundation nor the names of its
* 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.content.crosswalk;
import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.eperson.EPerson;
import org.dspace.eperson.Group;
import org.jdom.Element;
import org.jdom.Namespace;
/**
* METSRights Ingestion & Dissemination Crosswalk
* <p>
* Translate between DSpace internal policies (i.e. permissions) and the
* METSRights metadata schema
* (see <a href="http://www.loc.gov/standards/rights/METSRights.xsd">
* http://www.loc.gov/standards/rights/METSRights.xsd</a> for details).
* <p>
* Examples of METSRights usage available from:
* <a href="http://www.loc.gov/standards/rights/">
* http://www.loc.gov/standards/rights/</a>
* <p>
* This Crosswalk provides a way to export DSpace permissions into a standard
* format, and then re-import or restore them into a DSpace instance.
*
* @author Tim Donohue
* @version $Revision: 2108 $
*/
public class METSRightsCrosswalk
implements IngestionCrosswalk, DisseminationCrosswalk
{
/** log4j category */
private static Logger log = Logger.getLogger(METSRightsCrosswalk.class);
private static final Namespace METSRights_NS =
Namespace.getNamespace("rights", "http://cosimo.stanford.edu/sdr/metsrights/");
// XML schemaLocation fragment for this crosswalk, from config.
private String schemaLocation =
METSRights_NS.getURI()+" http://cosimo.stanford.edu/sdr/metsrights.xsd";
private static final Namespace namespaces[] = { METSRights_NS };
private final static Map<Integer,String> otherTypesMapping = new HashMap<Integer,String>();
static
{
//Mapping of DSpace Policy Actions to METSRights PermissionType values
// (These are the values stored in the @OTHERPERMITTYPE attribute in METSRights)
// NOTE: READ, WRITE, DELETE are not included here as they map directly to existing METSRights PermissionTypes
otherTypesMapping.put(Constants.ADD, "ADD CONTENTS");
otherTypesMapping.put(Constants.REMOVE, "REMOVE CONTENTS");
otherTypesMapping.put(Constants.ADMIN, "ADMIN");
otherTypesMapping.put(Constants.DEFAULT_BITSTREAM_READ, "READ FILE CONTENTS");
otherTypesMapping.put(Constants.DEFAULT_ITEM_READ, "READ ITEM CONTENTS");
}
// Value of METSRights <Context> @CONTEXTCLASS attribute to use for DSpace Groups
private static final String GROUP_CONTEXTCLASS = "MANAGED_GRP";
// Value of METSRights <Context> @CONTEXTCLASS attribute to use for DSpace EPeople
private static final String PERSON_CONTEXTCLASS = "ACADEMIC USER";
// Value of METSRights <Context> @CONTEXTCLASS attribute to use for "Anonymous" DSpace Group
private static final String ANONYMOUS_CONTEXTCLASS = "GENERAL PUBLIC";
// Value of METSRights <Context> @CONTEXTCLASS attribute to use for "Administrator" DSpace Group
private static final String ADMIN_CONTEXTCLASS = "REPOSITORY MGR";
// Value of METSRights <UserName> @USERTYPE attribute to use for DSpace Groups
private static final String GROUP_USERTYPE = "GROUP";
// Value of METSRights <UserName> @USERTYPE attribute to use for DSpace Groups
private static final String PERSON_USERTYPE = "INDIVIDUAL";
/*----------- Dissemination functions -------------------*/
@Override
public Namespace[] getNamespaces()
{
return namespaces;
}
@Override
public String getSchemaLocation()
{
return schemaLocation;
}
@Override
public boolean canDisseminate(DSpaceObject dso)
{
//can disseminate all types of DSpace Objects, except for SITE
if(dso.getType()!=Constants.SITE)
return true;
else
return false;
}
/**
* Actually Disseminate into METSRights schema. This method locates all DSpace
* policies (permissions) for the provided object, and translates them into
* METSRights PermissionTypes.
*
* @param dso DSpace Object
* @return XML Element corresponding to the new <RightsDeclarationMD> translation
* @throws CrosswalkException
* @throws IOException
* @throws SQLException
* @throws AuthorizeException
*/
@Override
public Element disseminateElement(DSpaceObject dso)
throws CrosswalkException,
IOException, SQLException, AuthorizeException
{
if(dso==null)
return null;
// we don't have a way to provide METSRights for a SITE object
else if(dso.getType() == Constants.SITE)
throw new CrosswalkObjectNotSupported("The METSRightsCrosswalk cannot crosswalk a SITE object");
//Root element: RightsDeclarationMD
// All DSpace content is just under LICENSE -- no other rights can be claimed
Element rightsMD = new Element("RightsDeclarationMD", METSRights_NS);
rightsMD.setAttribute("RIGHTSCATEGORY", "LICENSED");
//Three sections to METSRights:
// * RightsDeclaration - general rights statement
// * RightsHolder - info about who owns rights
// * Context - info about specific permissions granted
// We're just crosswalking DSpace policies to "Context" permissions by default
// It's too difficult to make statements about who owns the rights and
// what those rights are -- too many types of content can be stored in DSpace
//Get all policies on this DSpace Object
Context context = new Context();
List<ResourcePolicy> policies = AuthorizeManager.getPolicies(context, dso);
//For each DSpace policy
for(ResourcePolicy policy : policies)
{
// DSpace Policies can either reference a Group or an Individual, but not both!
Group group = policy.getGroup();
EPerson person = policy.getEPerson();
//if(isSpecialGroup(group))
// {
// disseminateMembers(rightsContext)
// }
// Create our <Context> node for this policy
Element rightsContext = new Element("Context", METSRights_NS);
rightsMD.addContent(rightsContext);
//First, handle Group-based policies
// For Group policies we need to setup a
// <Context CONTEXTCLASS='[group-type]'><UserName USERTYPE='GROUP'>[group-name]</UserName>...
if(group != null)
{
//Default all DSpace groups to have "MANAGED GRP" as the type
String contextClass=GROUP_CONTEXTCLASS;
if(group.getID()==0) //DSpace Anonymous Group = 'GENERAL PUBLIC' type
contextClass = ANONYMOUS_CONTEXTCLASS;
else if(group.getID()==1) //DSpace Administrator Group = 'REPOSITORY MGR' type
contextClass = ADMIN_CONTEXTCLASS;
rightsContext.setAttribute("CONTEXTCLASS", contextClass);
//If this is a "MANAGED GRP", then create a <UserName> child
//to specify the group Name, and set @USERTYPE='GROUP'
if(contextClass.equals(GROUP_CONTEXTCLASS))
{
Element rightsUser = new Element("UserName", METSRights_NS);
rightsUser.setAttribute("USERTYPE",GROUP_USERTYPE);
rightsUser.addContent(group.getName());
rightsContext.addContent(rightsUser);
}
}//end if group
//Next, handle User-based policies
// For User policies we need to setup a
// <Context CONTEXTCLASS='ACADEMIC USER'><UserName USERTYPE='INDIVIDUAL'>[group-name]</UserName>...
else if(person!=null)
{
// All EPeople are considered 'Academic Users'
rightsContext.setAttribute("CONTEXTCLASS", PERSON_CONTEXTCLASS);
//Create a <UserName> node corresponding to person's email, set @USERTYPE='INDIVIDUAL'
Element rightsUser = new Element("UserName", METSRights_NS);
rightsUser.setAttribute("USERTYPE",PERSON_USERTYPE);
rightsUser.addContent(person.getEmail());
rightsContext.addContent(rightsUser);
}//end if person
//Translate the DSpace ResourcePolicy into a <Permissions> element
Element rightsPerm = translatePermissions(policy);
rightsContext.addContent(rightsPerm);
}//end for each policy
context.complete();
return rightsMD;
}
@Override
public List disseminateList(DSpaceObject dso)
throws CrosswalkException,
IOException, SQLException, AuthorizeException
{
List result = new ArrayList(1);
result.add(disseminateElement(dso));
return result;
}
@Override
public boolean preferList()
{
return false;
}
/**
* Translates a DSpace ResourcePolicy's permissions into a METSRights
* <code>Permissions</code> element. Returns the created
* <code>Permissions</code> element. This element may be empty if
* there was an issue translating the ResourcePolicy.
*
* @param policy The DSpace ResourcePolicy
* @return the Element representing the METSRIghts <code>Permissions</code> or null.
*/
private Element translatePermissions(ResourcePolicy policy)
{
//Create our <Permissions> node to store all permissions in this context
Element rightsPerm = new Element("Permissions", METSRights_NS);
//Determine the 'actions' permitted by this DSpace policy, and translate to METSRights PermissionTypes
int action = policy.getAction();
//All READ-based actions = cannot modify or delete object
if(action==Constants.READ
|| action==Constants.DEFAULT_BITSTREAM_READ
|| action==Constants.DEFAULT_ITEM_READ)
{
// For DSpace, READ = Discover and Display
rightsPerm.setAttribute("DISCOVER", "true");
rightsPerm.setAttribute("DISPLAY", "true");
//Read = cannot modify or delete
rightsPerm.setAttribute("MODIFY", "false");
rightsPerm.setAttribute("DELETE", "false");
}
//All WRITE-based actions = can modify, but cannot delete
else if(action == Constants.WRITE
|| action==Constants.ADD)
{
rightsPerm.setAttribute("DISCOVER", "true");
rightsPerm.setAttribute("DISPLAY", "true");
//Write = can modify, but cannot delete
rightsPerm.setAttribute("MODIFY", "true");
rightsPerm.setAttribute("DELETE", "false");
}
//All DELETE-based actions = can modify & can delete
//(NOTE: Although Constants.DELETE is marked as "obsolete", it is still used in dspace-api)
else if(action == Constants.DELETE
|| action==Constants.REMOVE)
{
rightsPerm.setAttribute("DISCOVER", "true");
rightsPerm.setAttribute("DISPLAY", "true");
//Delete = can both modify and delete
rightsPerm.setAttribute("MODIFY", "true");
rightsPerm.setAttribute("DELETE", "true");
}
//ADMIN action = full permissions
else if(action == Constants.ADMIN)
{
rightsPerm.setAttribute("DISCOVER", "true");
rightsPerm.setAttribute("DISPLAY", "true");
rightsPerm.setAttribute("COPY", "true");
rightsPerm.setAttribute("DUPLICATE", "true");
rightsPerm.setAttribute("MODIFY", "true");
rightsPerm.setAttribute("DELETE", "true");
rightsPerm.setAttribute("PRINT", "true");
}
else
{
//Unknown action -- don't enable any rights by default
//NOTE: ALL WORKFLOW RELATED ACTIONS ARE NOT INCLUDED IN METSRIGHTS
//DSpace API no longer assigns nor checks any of the following 'action' types:
// * Constants.WORKFLOW_STEP_1
// * Constants.WORKFLOW_STEP_2
// * Constants.WORKFLOW_STEP_3
// * Constants.WORKFLOW_ABORT
}//end if
//Also add in OTHER permissionTypes, as necessary (see 'otherTypesMapping' above)
// (These OTHER permissionTypes are used to tell apart similar DSpace permissions during Ingestion)
if(otherTypesMapping.containsKey(action))
{
//if found in our 'otherTypesMapping', enable @OTHER attribute and add in the appropriate value to @OTHERPERMITTYPE attribute
rightsPerm.setAttribute("OTHER", "true");
rightsPerm.setAttribute("OTHERPERMITTYPE", otherTypesMapping.get(action));
}
return rightsPerm;
}
/*----------- Ingestion functions -------------------*/
@Override
public void ingest(Context context, DSpaceObject dso, Element root)
throws CrosswalkException, IOException, SQLException, AuthorizeException
{
if (!(root.getName().equals("RightsDeclarationMD")))
throw new MetadataValidationException("Wrong root element for METSRights: "+root.toString());
ingest(context, dso, root.getChildren());
}
@Override
public void ingest(Context context, DSpaceObject dso, List ml)
throws CrosswalkException, IOException, SQLException, AuthorizeException
{
// we cannot crosswalk METSRights to a SITE object
if (dso.getType() == Constants.SITE)
throw new CrosswalkObjectNotSupported("Wrong target object type, METSRightsCrosswalk cannot crosswalk a SITE object.");
// Loop through each Element in the List
Iterator mi = ml.iterator();
while (mi.hasNext())
{
Element element = (Element)mi.next();
// if we're fed a <RightsDeclarationMD> wrapper object, recurse on its guts:
if (element.getName().equals("RightsDeclarationMD"))
ingest(context, dso, element.getChildren());
// "Context" section (where permissions are stored)
else if (element.getName().equals("Context"))
{
//get what class of context this is
String contextClass = element.getAttributeValue("CONTEXTCLASS");
//also get reference to the <Permissions> element
Element permsElement = element.getChild("Permissions", METSRights_NS);
//Check if this permission pertains to Anonymous users
if(contextClass.equals(ANONYMOUS_CONTEXTCLASS))
{
//get DSpace Anonymous group, ID=0
Group anonGroup = Group.find(context, 0);
if(anonGroup==null)
throw new CrosswalkInternalException("The DSpace database has not been properly initialized. The Anonymous Group is missing from the database.");
assignPermissions(context, dso, anonGroup, permsElement);
} // else if this permission declaration pertains to Administrators
else if(contextClass.equals(ADMIN_CONTEXTCLASS))
{
//get DSpace Administrator group, ID=1
Group adminGroup = Group.find(context, 1);
if(adminGroup==null)
throw new CrosswalkInternalException("The DSpace database has not been properly initialized. The Administrator Group is missing from the database.");
assignPermissions(context, dso, adminGroup, permsElement);
} // else if this permission pertains to another DSpace group
else if(contextClass.equals(GROUP_CONTEXTCLASS))
{
//we need to find the name of DSpace group it pertains to
//Get the text within the <UserName> child element,
// this is the group's name
String groupName = element.getChildTextTrim("UserName", METSRights_NS);
//Check if this group exists in DSpace already
Group group = Group.findByName(context, groupName);
//if not found, throw an error -- user should restore group from the SITE AIP
if(group==null)
{
throw new CrosswalkInternalException("Cannot restore Group permissions on object ("
+ "type=" + Constants.typeText[dso.getType()] + ", "
+ "handle=" + dso.getHandle() + ", "
+ "ID=" + dso.getID()
+ "). The Group named '" + groupName + "' is missing from DSpace. "
+ "Please restore this group using the SITE AIP, or recreate it.");
}
//assign permissions to group on this object
assignPermissions(context, dso, group, permsElement);
}//end if Group
else if(contextClass.equals(PERSON_CONTEXTCLASS))
{
//we need to find the person it pertains to
// Get the text within the <UserName> child element,
// this is the person's email address
String personEmail = element.getChildTextTrim("UserName", METSRights_NS);
//Check if this person exists in DSpace already
EPerson person = EPerson.findByEmail(context, personEmail);
//If cannot find by email, try by netID
//(though METSRights should contain email if it was exported by DSpace)
if(person==null)
person = EPerson.findByNetid(context, personEmail);
//if not found, throw an error -- user should restore person from the SITE AIP
if(person==null)
{
throw new CrosswalkInternalException("Cannot restore Person permissions on object ("
+ "type=" + Constants.typeText[dso.getType()] + ", "
+ "handle=" + dso.getHandle() + ", "
+ "ID=" + dso.getID()
+ "). The Person with email/netid '" + personEmail + "' is missing from DSpace. "
+ "Please restore this Person object using the SITE AIP, or recreate it.");
}
//assign permissions to person on this object
assignPermissions(context, dso, person, permsElement);
}//end if Person
} //end if "Context" element
}//end while loop
}
/**
* Parses the 'permsElement' (corresponding to a <code>Permissions</code>
* element), and assigns those permissions to the specified Group
* on the specified DSpace Object.
*
* @param context DSpace context object
* @param dso The DSpace Object
* @param group The DSpace Group
* @param permsElement The METSRights <code>Permissions</code> element
*/
private void assignPermissions(Context context, DSpaceObject dso, Group group, Element permsElement)
throws SQLException, AuthorizeException
{
//first, parse our permissions to determine which action we are allowing in DSpace
int actionID = parsePermissions(permsElement);
//If action ID is less than base READ permissions (value=0),
// then something must've gone wrong in the parsing
if(actionID < Constants.READ)
{
log.warn("Unable to properly restore all access permissions on object ("
+ "type=" + Constants.typeText[dso.getType()] + ", "
+ "handle=" + dso.getHandle() + ", "
+ "ID=" + dso.getID()
+ ") for group '" + group.getName() + "'.");
}
//Otherwise, add the appropriate group policy for this object
AuthorizeManager.addPolicy(context, dso, actionID, group);
}
/**
* Parses the 'permsElement' (corresponding to a <code>Permissions</code>
* element), and assigns those permissions to the specified EPerson
* on the specified DSpace Object.
*
* @param context DSpace context object
* @param dso The DSpace Object
* @param person The DSpace EPerson
* @param permsElement The METSRights <code>Permissions</code> element
*/
private void assignPermissions(Context context, DSpaceObject dso, EPerson person, Element permsElement)
throws SQLException, AuthorizeException
{
//first, parse our permissions to determine which action we are allowing in DSpace
int actionID = parsePermissions(permsElement);
//If action ID is less than base READ permissions (value=0),
// then something must've gone wrong in the parsing
if(actionID < Constants.READ)
{
log.warn("Unable to properly restore all access permissions on object ("
+ "type=" + Constants.typeText[dso.getType()] + ", "
+ "handle=" + dso.getHandle() + ", "
+ "ID=" + dso.getID()
+ ") for person '" + person.getEmail() + "'.");
}
//Otherwise, add the appropriate EPerson policy for this object
AuthorizeManager.addPolicy(context, dso, actionID, person);
}
/**
* Parses the 'permsElement' (corresponding to a <code>Permissions</code>
* element) to find the corresponding DSpace permission type. This
* DSpace permission type must be one of the Action IDs specified in
* <code>org.dspace.core.Constants</code>
* <P>
* Returns -1 if failed to parse permissions.
*
* @param permsElement The METSRights <code>Permissions</code> element
* @return A DSpace Action ID from <code>org.dspace.core.Constants</code>
*/
private int parsePermissions(Element permsElement)
{
//First, check if the @OTHERPERMITTYPE attribute is specified
String otherPermitType = permsElement.getAttributeValue("OTHERPERMITTYPE");
//if @OTHERPERMITTYPE attribute exists, it will map directly to a DSpace Action type
if(otherPermitType!=null && !otherPermitType.isEmpty())
{
if(otherTypesMapping.containsValue(otherPermitType))
{
//find the Action ID this value maps to
for(int actionType: otherTypesMapping.keySet())
{
//if found, this is the Action ID corresponding to this permission
if(otherTypesMapping.get(actionType).equals(otherPermitType))
return actionType;
}
}
else
{
log.warn("Unrecognized @OTHERPERMITTYPE attribute value ("
+ otherPermitType
+ ") found in METSRights section of METS Manifest.");
}
}
else // Otherwise, a closer analysis of all Permission element attributes is necessary
{
boolean discoverPermit = Boolean.parseBoolean(permsElement.getAttributeValue("DISCOVER"));
boolean displayPermit = Boolean.parseBoolean(permsElement.getAttributeValue("DISPLAY"));
boolean modifyPermit = Boolean.parseBoolean(permsElement.getAttributeValue("MODIFY"));
boolean deletePermit = Boolean.parseBoolean(permsElement.getAttributeValue("DELETE"));
boolean otherPermit = Boolean.parseBoolean(permsElement.getAttributeValue("OTHER"));
//if DELETE='true'
if(deletePermit && !otherPermit)
{
//This must refer to the DELETE action type
//(note REMOVE & ADMIN action type have @OTHERPERMITTYPE values specified)
return Constants.DELETE;
}//if MODIFY='true'
else if(modifyPermit && !otherPermit)
{
//This must refer to the WRITE action type
//(note ADD action type has an @OTHERPERMITTYPE value specified)
return Constants.WRITE;
}
else if(discoverPermit && displayPermit && !otherPermit)
{
//This must refer to the READ action type
return Constants.READ;
}
}
//if we got here, we failed to parse out proper permissions
// return -1 to signify failure (as 0 = READ permissions)
return -1;
}
}

View File

@@ -527,6 +527,8 @@ public abstract class AbstractMETSDisseminator
DisseminationCrosswalk xwalk = (DisseminationCrosswalk)
PluginManager.getNamedPlugin(DisseminationCrosswalk.class, xwalkName);
if (xwalk.canDisseminate(dso))
{
//For a normal DisseminationCrosswalk, we will be expecting an XML (DOM) based result.
// So, we are going to wrap this XML result in an <mdWrap> element
MdWrap mdWrap = new MdWrap();
@@ -541,6 +543,9 @@ public abstract class AbstractMETSDisseminator
else
return null;
}
else
return null;
}
// If we didn't find the correct crosswalk, we will check to see if this is
// a StreamDisseminationCrosswalk -- a Stream crosswalk disseminates to an OutputStream
else
@@ -777,6 +782,11 @@ public abstract class AbstractMETSDisseminator
if ((bName != null) && !bName.equals(""))
fileGrp.setUSE(bundleToFileGrp(bName));
// add technical metadata for a bundle
String techBundID = addAmdSec(context, bundles[i], params, mets, extraStreams);
if (techBundID != null)
fileGrp.setADMID(techBundID);
// watch for primary bitstream
int primaryBitstreamID = -1;
boolean isContentBundle = false;
@@ -976,9 +986,9 @@ public abstract class AbstractMETSDisseminator
// set links to metadata for object -- after type-specific
// code since that can add to the object metadata.
StringBuffer dmdIds = new StringBuffer();
StringBuilder dmdIds = new StringBuilder();
for (int i = 0; i < dmdId.length; ++i)
dmdIds.append(" "+dmdId[i]);
dmdIds.append(" ").append(dmdId[i]);
div0.setDMDID(dmdIds.substring(1));
if (objectAMDID != null)
div0.setADMID(objectAMDID);

View File

@@ -81,24 +81,13 @@ import java.net.URLEncoder;
* object model. An AIP contains all of the information needed to restore
* the object precisely in another DSpace archive instance.
* <p>
* This ingester recognizes two distinct types of AIPs: "Manifest-Only" and "External".
* The Manifest-Only AIP, which is selected by specifying a PackageParameters
* key "manifestOnly" with the value "true", refers to all its contents by
* reference only. For Community or Collection AIPs this means all references to their
* child objects are just via Handles. For Item AIPs all Bitreams are just
* referenced by their asset store location instead of finding them in the "package".
* The Manifest-Only AIP package format is simply a METS XML document serialized into a file.
* <p>
* An "external" AIP (the default), is a conventional Zip-file based package
* that includes copies of all bitstreams referenced by the object as well
* as a serialized METS XML document in the path "mets.xml".
*
* Configuration keys:
* <p>
* The following take as values a space-and-or-comma-separated list
* of plugin names that name *either* a DisseminationCrosswalk or
* StreamDisseminationCrosswalk plugin. Shown are the dfeault values.
* The value may be a simple plugin name, or a METS MDsec-name followed by
* a colon and the plugin name e.g. "DSpaceHistory :HISTORY"
* StreamDisseminationCrosswalk plugin. Shown are the default values.
* The value may be a simple crosswalk name, or a METS MDsec-name followed by
* a colon and the crosswalk name e.g. "DSpaceDepositLicense:DSPACE_DEPLICENSE"
*
* # MD types to put in the sourceMD section of the object.
* aip.disseminate.sourceMD = AIP-TECHMD
@@ -107,19 +96,20 @@ import java.net.URLEncoder;
* aip.disseminate.techMD = PREMIS
*
* # MD types to put in digiprovMD section of the object.
* # (Note that this is disabled unless the History System is installed)
* #aip.disseminate.digiprovMD = DSpaceHistory :HISTORY
* #aip.disseminate.digiprovMD =
*
* # MD types to put in the rightsMD section of the object.
* aip.disseminate.rightsMD = DSpaceDepositLicense:DSPACE_DEPLICENSE, \
* CreativeCommonsRDF:DSPACE_CCRDF, CreativeCommonsText:DSPACE_CCTXT
* CreativeCommonsRDF:DSPACE_CCRDF, CreativeCommonsText:DSPACE_CCTXT, METSRights
*
* # MD types to put in dmdSec's corresponding the object.
* aip.disseminate.dmd = MODS, DIM
*
* @author Larry Stone
* @author Tim Donohue
* @version $Revision: 1.1 $
* @see AbstractMETSDisseminator
* @see AbstractPackageDisseminator
*/
public class DSpaceAIPDisseminator
extends AbstractMETSDisseminator
@@ -158,6 +148,7 @@ public class DSpaceAIPDisseminator
*
* @return string name of profile.
*/
@Override
public String getProfile()
{
return PROFILE_1_0;
@@ -166,20 +157,32 @@ public class DSpaceAIPDisseminator
/**
* Returns name of METS fileGrp corresponding to a DSpace bundle name.
* For AIP the mapping is direct.
*
* @param bname name of DSpace bundle.
* @return string name of fileGrp
*/
@Override
public String bundleToFileGrp(String bname)
{
return bname;
}
/**
* metsHdr for AIP.
* Create the metsHdr element for the AIP METS Manifest.
* <p>
* CREATEDATE is time at which the package (i.e. this manifest) was created.
* LASTMODDATE is last-modified time of the target object, if available.
* Agent describes the archive this belongs to.
*
* @param context DSpace Context
* @param dso current DSpace Object
* @param params Packager Parameters
* @return List of crosswalk names to run
* @throws SQLException
* @throws IOException
* @throws AuthorizeException
*/
@Override
public MetsHdr makeMetsHdr(Context context, DSpaceObject dso,
PackageParameters params)
{
@@ -205,8 +208,20 @@ public class DSpaceAIPDisseminator
}
/**
* Get DMD choice for Item. It defaults to MODS, plus DIM.
* Return the name of all crosswalks to run for the dmdSec section of
* the METS Manifest.
* <p>
* Default is DIM (DSpace Internal Metadata) and MODS.
*
* @param context DSpace Context
* @param dso current DSpace Object
* @param params Packager Parameters
* @return List of crosswalk names to run
* @throws SQLException
* @throws IOException
* @throws AuthorizeException
*/
@Override
public String [] getDmdTypes(Context context, DSpaceObject dso, PackageParameters params)
throws SQLException, IOException, AuthorizeException
{
@@ -223,11 +238,20 @@ public class DSpaceAIPDisseminator
}
/**
* Get name of technical metadata crosswalk for Bitstreams.
* Default is PREMIS (for Bistreams only).
* This is both the name of the crosswalk plugin
* and the METS MDTYPE.
* Return the name of all crosswalks to run for the techMD section of
* the METS Manifest.
* <p>
* Default is PREMIS.
*
* @param context DSpace Context
* @param dso current DSpace Object
* @param params Packager Parameters
* @return List of crosswalk names to run
* @throws SQLException
* @throws IOException
* @throws AuthorizeException
*/
@Override
public String[] getTechMdTypes(Context context, DSpaceObject dso, PackageParameters params)
throws SQLException, IOException, AuthorizeException
{
@@ -250,12 +274,24 @@ public class DSpaceAIPDisseminator
}
/**
* Get name of source metadata crosswalk for each kind of DSO.
* Return the name of all crosswalks to run for the sourceMD section of
* the METS Manifest.
* <p>
* Default is AIP-TECHMD.
* <p>
* In an AIP, the sourceMD element MUST include the original persistent
* identifier (Handle) of the object, and the original persistent ID
* (Handle) of its parent in the archive, so that it can be restored.
*
* @param context DSpace Context
* @param dso current DSpace Object
* @param params Packager Parameters
* @return List of crosswalk names to run
* @throws SQLException
* @throws IOException
* @throws AuthorizeException
*/
@Override
public String[] getSourceMdTypes(Context context, DSpaceObject dso, PackageParameters params)
throws SQLException, IOException, AuthorizeException
{
@@ -271,8 +307,20 @@ public class DSpaceAIPDisseminator
}
/**
* Get name of provenance MD crosswalks - none by default.
* Return the name of all crosswalks to run for the digiprovMD section of
* the METS Manifest.
* <p>
* By default, none are returned
*
* @param context DSpace Context
* @param dso current DSpace Object
* @param params Packager Parameters
* @return List of crosswalk names to run
* @throws SQLException
* @throws IOException
* @throws AuthorizeException
*/
@Override
public String[] getDigiprovMdTypes(Context context, DSpaceObject dso, PackageParameters params)
throws SQLException, IOException, AuthorizeException
{
@@ -284,20 +332,36 @@ public class DSpaceAIPDisseminator
}
/**
* Return crosswalks of Rights metadata types. By default, for Item
* only, return the deposit license and CreativeCommons if available.
* Return the name of all crosswalks to run for the rightsMD section of
* the METS Manifest.
* <p>
* By default, Deposit Licenses and CC Licenses will be added for Items.
* Also, by default METSRights info will be added for all objects.
*
* @param context DSpace Context
* @param dso current DSpace Object
* @param params Packager Parameters
* @return List of crosswalk names to run
* @throws SQLException
* @throws IOException
* @throws AuthorizeException
*/
@Override
public String[] getRightsMdTypes(Context context, DSpaceObject dso, PackageParameters params)
throws SQLException, IOException, AuthorizeException
{
// rights only apply to Item at this time.
if (dso.getType() == Constants.ITEM)
{
List<String> result = new ArrayList<String>();
String rTypes = ConfigurationManager.getProperty("aip.disseminate.rightsMD");
//If unspecified in configuration file, add default settings
if (rTypes == null)
{
List<String> result = new ArrayList<String>();
// Licenses only apply to an Item
if (dso.getType() == Constants.ITEM)
{
//By default, disseminate Deposit License, and any CC Licenses
// to an item's rightsMD section
if (PackageUtils.findDepositLicense(context, (Item)dso) != null)
result.add(DSPACE_DEPOSIT_LICENSE_MDTYPE);
@@ -305,28 +369,33 @@ public class DSpaceAIPDisseminator
result.add(CREATIVE_COMMONS_RDF_MDTYPE);
else if (CreativeCommons.getLicenseTextBitstream((Item)dso) != null)
result.add(CREATIVE_COMMONS_TEXT_MDTYPE);
return result.toArray(new String[result.size()]);
}
//By default, also add METSRights info to the rightsMD
result.add("METSRights");
}
else
return rTypes.split("\\s*,\\s*");
}
return new String[0];
return result.toArray(new String[result.size()]);
}
/**
* Get the URL by which the METS manifest refers to a Bitstream
* member of an Item the "package". Note that this ONLY has to work
* for the Bitstreams belonging to a Bunde in an Item, NOT for the
* other associated Bitstreams containing metadata streams, or logo
* of a Community/Collection, etc.
* member within the same package. In other words, this is generally
* a relative path link to where the Bitstream file is within the Zipped
* up AIP.
* <p>
* For an manifest-only AIP, this is a reference to an HTTP URL where
* For a manifest-only AIP, this is a reference to an HTTP URL where
* the bitstream should be able to be downloaded from.
* An external AIP names a file in the package
* with a relative URL, that is, relative pathname.
* <p>
*
* @param bitstream the Bitstream
* @param params Packager Parameters
* @return String in URL format naming path to bitstream.
*/
@Override
public String makeBitstreamURL(Bitstream bitstream, PackageParameters params)
{
// if bare manifest, use external "persistent" URI for bitstreams
@@ -391,7 +460,17 @@ public class DSpaceAIPDisseminator
* by crosswalks (e.g. AIP techMd) for the parent, it has to be at
* a higher level in the AIP manifest. The structMap is an obvious
* and standards-compliant location for it.
*
* @param context DSpace context
* @param dso Current DSpace object
* @param params Packager Parameters
* @param mets METS manifest
* @throws SQLException
* @throws IOException
* @throws AuthorizeException
* @throws MetsException
*/
@Override
public void addStructMap(Context context, DSpaceObject dso,
PackageParameters params, Mets mets)
throws SQLException, IOException, AuthorizeException, MetsException
@@ -441,8 +520,11 @@ public class DSpaceAIPDisseminator
}
/**
* include all bundles in AIP as content.
* Include all bundles in AIP as content.
* @param bundle Bundle to check for
* @return true always
*/
@Override
public boolean includeBundle(Bundle bundle)
{
return true;

View File

@@ -735,7 +735,8 @@ plugin.named.org.dspace.content.crosswalk.IngestionCrosswalk = \
org.dspace.content.crosswalk.OREIngestionCrosswalk = ore, \
org.dspace.content.crosswalk.NullIngestionCrosswalk = NIL, \
org.dspace.content.crosswalk.OAIDCIngestionCrosswalk = dc, \
org.dspace.content.crosswalk.DIMIngestionCrosswalk = dim
org.dspace.content.crosswalk.DIMIngestionCrosswalk = dim, \
org.dspace.content.crosswalk.METSRightsCrosswalk = METSRIGHTS
plugin.selfnamed.org.dspace.content.crosswalk.IngestionCrosswalk = \
org.dspace.content.crosswalk.XSLTIngestionCrosswalk, \
@@ -754,6 +755,7 @@ plugin.named.org.dspace.content.crosswalk.DisseminationCrosswalk = \
org.dspace.content.crosswalk.PREMISCrosswalk = PREMIS, \
org.dspace.content.crosswalk.METSDisseminationCrosswalk = METS, \
org.dspace.content.crosswalk.METSDisseminationCrosswalk = mets, \
org.dspace.content.crosswalk.METSRightsCrosswalk = METSRIGHTS, \
org.dspace.content.crosswalk.OREDisseminationCrosswalk = ore, \
org.dspace.content.crosswalk.DIMDisseminationCrosswalk = dim
@@ -856,9 +858,10 @@ aip.disseminate.sourceMD = AIP-TECHMD
# Rights metadata in AIP (exported to METS <rightsMD> section)
# Format is <label-for-METS>:<DSpace-crosswalk-name> [, ...] (label is optional)
# If unspecified, default to adding all Licenses (CC and Deposit licenses)
# If unspecified, default to adding all Licenses (CC and Deposit licenses),
# as well as METSRights information
aip.disseminate.rightsMD = DSpaceDepositLicense:DSPACE_DEPLICENSE, \
CreativeCommonsRDF:DSPACE_CCRDF, CreativeCommonsText:DSPACE_CCTEXT
CreativeCommonsRDF:DSPACE_CCRDF, CreativeCommonsText:DSPACE_CCTEXT, METSRIGHTS
# Descriptive metadata in AIP (exported to METS <dmdSec> section)
# Format is <label-for-METS>:<DSpace-crosswalk-name> [, ...] (label is optional)