mirror of
https://github.com/DSpace/DSpace.git
synced 2025-10-07 01:54:22 +00:00
Applying Patch #2477820: DSpace 1.5 XMLUI - Enable METS <amdSec> using crosswalks. Allows you to retrieve Item-level METS files with an <amdSec> section, and generate the administrative metadata using any crosswalk. By default, the <amdSec> is NOT generated, in order to keep METS files small. But, it can be enabled via parameters on querystring (so that it is available to Themes, etc.). See patch description for more information.
git-svn-id: http://scm.dspace.org/svn/repo/trunk@3361 9c30dcfa-912a-0410-8fc2-9e0234be79fd
This commit is contained in:
@@ -232,13 +232,19 @@ public class DSpaceMETSGenerator extends AbstractGenerator
|
||||
Request request = ObjectModelHelper.getRequest(objectModel);
|
||||
String sections = request.getParameter("sections");
|
||||
String dmdTypes = request.getParameter("dmdTypes");
|
||||
String amdTypes = request.getParameter("amdTypes");
|
||||
String techMDTypes = request.getParameter("techMDTypes");
|
||||
String rightsMDTypes = request.getParameter("rightsMDTypes");
|
||||
String sourceMDTypes = request.getParameter("sourceMDTypes");
|
||||
String digiprovMDTypes = request.getParameter("digiprovMDTypes");
|
||||
String fileGrpTypes = request.getParameter("fileGrpTypes");
|
||||
String structTypes = request.getParameter("structTypes");
|
||||
|
||||
adapter.setSections(sections);
|
||||
adapter.setDmdTypes(dmdTypes);
|
||||
adapter.setAmdTypes(amdTypes);
|
||||
adapter.setTechMDTypes(techMDTypes);
|
||||
adapter.setRightsMDTypes(rightsMDTypes);
|
||||
adapter.setSourceMDTypes(sourceMDTypes);
|
||||
adapter.setDigiProvMDTypes(digiprovMDTypes);
|
||||
adapter.setFileGrpTypes(fileGrpTypes);
|
||||
adapter.setStructTypes(structTypes);
|
||||
}
|
||||
|
@@ -61,6 +61,7 @@ import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
|
||||
@@ -131,7 +132,7 @@ public abstract class AbstractAdapter
|
||||
/** The variables that dicatacte what part of the METS document to render */
|
||||
List<String> sections = new ArrayList<String>();
|
||||
List<String> dmdTypes = new ArrayList<String>();
|
||||
List<String> amdTypes = new ArrayList<String>();
|
||||
HashMap<String,List> amdTypes = new HashMap<String,List>();
|
||||
List<String> fileGrpTypes = new ArrayList<String>();
|
||||
List<String> structTypes = new ArrayList<String>();
|
||||
|
||||
@@ -170,22 +171,71 @@ public abstract class AbstractAdapter
|
||||
}
|
||||
|
||||
/**
|
||||
* A comma seperated list of METS administrative metadata formats to
|
||||
* render.
|
||||
* Store information about what will be rendered in the METS administrative
|
||||
* metadata section. HashMap format: keys = amdSec, value = List of mdTypes
|
||||
*
|
||||
* @param sections Comma seperated list of METS metadata types.
|
||||
* @param amdSec Section of <amdSec> where this administrative metadata
|
||||
* will be rendered
|
||||
* @param mdTypes Comma seperated list of METS metadata types.
|
||||
*/
|
||||
public void setAmdTypes(String amdTypes)
|
||||
public void setAmdTypes(String amdSec, String mdTypes)
|
||||
{
|
||||
if (amdTypes == null)
|
||||
if (mdTypes == null)
|
||||
return;
|
||||
|
||||
for (String amdType : amdTypes.split(","))
|
||||
List<String> mdTypeList = new ArrayList<String>();
|
||||
for (String mdType : mdTypes.split(","))
|
||||
{
|
||||
this.amdTypes.add(amdType);
|
||||
mdTypeList.add(mdType);
|
||||
}
|
||||
|
||||
this.amdTypes.put(amdSec, mdTypeList);
|
||||
}
|
||||
|
||||
/**
|
||||
* A comma seperated list of METS technical metadata formats to
|
||||
* render.
|
||||
*
|
||||
* @param techMDTypes Comma seperated list of METS metadata types.
|
||||
*/
|
||||
public void setTechMDTypes(String techMDTypes)
|
||||
{
|
||||
setAmdTypes("techMD", techMDTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* A comma seperated list of METS intellectual property rights metadata
|
||||
* formats to render.
|
||||
*
|
||||
* @param rightsMDTypes Comma seperated list of METS metadata types.
|
||||
*/
|
||||
public void setRightsMDTypes(String rightsMDTypes)
|
||||
{
|
||||
setAmdTypes("rightsMD", rightsMDTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* A comma seperated list of METS source metadata
|
||||
* formats to render.
|
||||
*
|
||||
* @param sourceMDTypes Comma seperated list of METS metadata types.
|
||||
*/
|
||||
public void setSourceMDTypes(String sourceMDTypes)
|
||||
{
|
||||
setAmdTypes("sourceMD", sourceMDTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* A comma seperated list of METS digital provenance metadata
|
||||
* formats to render.
|
||||
*
|
||||
* @param digiprovMDTypes Comma seperated list of METS metadata types.
|
||||
*/
|
||||
public void setDigiProvMDTypes(String digiprovMDTypes)
|
||||
{
|
||||
setAmdTypes("digiprovMD", digiprovMDTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* A comma seperated list of METS fileGrps to render. If no value
|
||||
* is provided then all groups are rendered.
|
||||
@@ -360,6 +410,29 @@ public abstract class AbstractAdapter
|
||||
* @return The METS file element.
|
||||
*/
|
||||
protected void renderFile(Item item, Bitstream bitstream, String fileID, String groupID) throws SAXException
|
||||
{
|
||||
renderFile(item, bitstream, fileID, groupID, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a METS file element for a given bitstream.
|
||||
*
|
||||
* @param item
|
||||
* If the bitstream is associated with an item provid the item
|
||||
* otherwise leave null.
|
||||
* @param bitstream
|
||||
* The bitstream to build a file element for.
|
||||
* @param fileID
|
||||
* The unique file id for this file.
|
||||
* @param groupID
|
||||
* The group id for this file, if it is derived from another file
|
||||
* then they should share the same groupID.
|
||||
* @param admID
|
||||
* The IDs of the administrative metadata sections which pertain
|
||||
* to this file
|
||||
* @return The METS file element.
|
||||
*/
|
||||
protected void renderFile(Item item, Bitstream bitstream, String fileID, String groupID, String admID) throws SAXException
|
||||
{
|
||||
AttributeMap attributes;
|
||||
|
||||
@@ -377,10 +450,12 @@ public abstract class AbstractAdapter
|
||||
// Start the actual file
|
||||
attributes = new AttributeMap();
|
||||
attributes.put("ID", fileID);
|
||||
attributes.put("GROUP_ID",groupID);
|
||||
if (mimeType != null)
|
||||
attributes.put("GROUPID",groupID);
|
||||
if (admID != null && admID.length()>0)
|
||||
attributes.put("ADMID", admID);
|
||||
if (mimeType != null && mimeType.length()>0)
|
||||
attributes.put("MIMETYPE", mimeType);
|
||||
if (checksumType != null && checksumType != null)
|
||||
if (checksumType != null && checksum != null)
|
||||
{
|
||||
attributes.put("CHECKSUM", checksum);
|
||||
attributes.put("CHECKSUMTYPE", checksumType);
|
||||
@@ -492,7 +567,7 @@ public abstract class AbstractAdapter
|
||||
* attributes describing the metadata type
|
||||
*/
|
||||
public static String[] METS_DEFINED_TYPES =
|
||||
{"MARC","MODS","EAD","DC","NISOIMG","LC-AV","VRA","TEIHDR","DDI","FGDC"/*,"OTHER"*/};
|
||||
{"MARC","MODS","EAD","DC","NISOIMG","LC-AV","VRA","TEIHDR","DDI","FGDC","PREMIS"/*,"OTHER"*/};
|
||||
|
||||
/**
|
||||
* Determine if the provided metadata type is a stardard METS
|
||||
|
@@ -64,7 +64,9 @@ import java.io.InputStream;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import org.dspace.content.DSpaceObject;
|
||||
|
||||
|
||||
/**
|
||||
@@ -100,7 +102,13 @@ public class ItemAdapter extends AbstractAdapter
|
||||
/** A space seperated list of descriptive metadata sections */
|
||||
private StringBuffer dmdSecIDS;
|
||||
|
||||
/** A space seperated list of administrative metadata sections (for item)*/
|
||||
private StringBuffer amdSecIDS;
|
||||
|
||||
/** A hashmap of all Files and their corresponding space separated list of
|
||||
administrative metadata sections */
|
||||
private HashMap<String,StringBuffer> fileAmdSecIDs = new HashMap<String,StringBuffer>();
|
||||
|
||||
/**
|
||||
* Construct a new ItemAdapter
|
||||
*
|
||||
@@ -189,6 +197,16 @@ public class ItemAdapter extends AbstractAdapter
|
||||
return "group_file_" + bitstream.getID();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a techMD id for a bitstream.
|
||||
*/
|
||||
protected String getAmdSecID(String admSecName, String mdType, DSpaceObject dso)
|
||||
{
|
||||
if (dso.getType() == Constants.BITSTREAM)
|
||||
return admSecName + "_" + getFileID((Bitstream)dso) + "_" + mdType;
|
||||
else
|
||||
return admSecName + "_" + dso.getID() + "_" + mdType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the METS descriptive section. This will create a new metadata
|
||||
@@ -427,6 +445,189 @@ public class ItemAdapter extends AbstractAdapter
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the METS administrative section.
|
||||
*
|
||||
* Example:
|
||||
* <amdSec>
|
||||
* <mdWrap MDTYPE="OTHER" OTHERMDTYPE="METSRights">
|
||||
* <xmlData>
|
||||
* ... content from the crosswalk ...
|
||||
* </xmlDate>
|
||||
* </mdWrap>
|
||||
* </amdSec>
|
||||
*/
|
||||
protected void renderAdministrativeSection() throws WingException, SAXException, CrosswalkException, IOException, SQLException
|
||||
{
|
||||
AttributeMap attributes;
|
||||
String groupID;
|
||||
|
||||
//Only create an <amdSec>, if we have amdTypes (or sub-sections) specified...
|
||||
// (this keeps our METS file small, by default, and hides all our admin metadata)
|
||||
if(amdTypes.size() > 0)
|
||||
{
|
||||
////////////////////////////////
|
||||
// Start an administrative wrapper
|
||||
|
||||
// Administrative element's ID
|
||||
String amdID = getGenericID("amd_");
|
||||
attributes = new AttributeMap();
|
||||
attributes.put("ID", amdID);
|
||||
startElement(METS, "amdSec", attributes);
|
||||
|
||||
groupID = getGenericID("group_amd_");
|
||||
attributes.put("GROUPID", groupID);
|
||||
}
|
||||
|
||||
// For each administrative metadata section specified
|
||||
for (String amdSecName : amdTypes.keySet())
|
||||
{
|
||||
//get a list of metadata crosswalks which will be used to build
|
||||
// this administrative metadata section
|
||||
List<String> mdTypes = amdTypes.get(amdSecName);
|
||||
|
||||
// For each crosswalk
|
||||
for (String mdType : mdTypes)
|
||||
{
|
||||
//get our dissemination crosswalk
|
||||
DisseminationCrosswalk crosswalk = getDisseminationCrosswalk(mdType);
|
||||
|
||||
//skip, if we cannot find this crosswalk in config file
|
||||
if (crosswalk == null)
|
||||
continue;
|
||||
|
||||
//First, check if this crosswalk can handle disseminating Item-level Administrative metadata
|
||||
if(crosswalk.canDisseminate(item))
|
||||
{
|
||||
//Since this crosswalk works with items, first render a section for entire item
|
||||
renderAmdSubSection(amdSecName, mdType, crosswalk, item);
|
||||
}
|
||||
|
||||
//Next, we'll try and render Bitstream-level administrative metadata
|
||||
// (Although, we're only rendering this metadata for the bundles specified)
|
||||
List<Bundle> bundles = findEnabledBundles();
|
||||
for (Bundle bundle : bundles)
|
||||
{
|
||||
Bitstream[] bitstreams = bundle.getBitstreams();
|
||||
|
||||
//Create a sub-section of <amdSec> for each bitstream in bundle
|
||||
for(Bitstream bitstream : bitstreams)
|
||||
{
|
||||
//Only render the section if crosswalk works with bitstreams
|
||||
if(crosswalk.canDisseminate(bitstream))
|
||||
{
|
||||
renderAmdSubSection(amdSecName, mdType, crosswalk, bitstream);
|
||||
}
|
||||
}//end for each bitstream
|
||||
}//end for each bundle
|
||||
}//end for each crosswalk
|
||||
}//end for each amdSec
|
||||
|
||||
if(amdTypes.size() > 0)
|
||||
{
|
||||
//////////////////////////////////
|
||||
// End administrative section
|
||||
endElement(METS,"amdSec");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a sub-section of the administrative metadata section.
|
||||
* Valid sub-sections include: techMD, rightsMD, sourceMD, digiprovMD
|
||||
*
|
||||
* Example:
|
||||
* <techMD>
|
||||
* <mdWrap MDTYPE="PREMIS">
|
||||
* <xmlData>
|
||||
* [PREMIS content ... ]
|
||||
* </xmlData>
|
||||
* </mdWrap>
|
||||
* </techMD>
|
||||
*
|
||||
* @param amdSecName Name of administrative metadata section
|
||||
* @param mdType Type of metadata section (e.g. PREMIS)
|
||||
* @param crosswalk The DisseminationCrosswalk to use to generate this section
|
||||
* @param dso The current DSpace object to use the crosswalk on
|
||||
*/
|
||||
protected void renderAmdSubSection(String amdSecName, String mdType, DisseminationCrosswalk crosswalk, DSpaceObject dso)
|
||||
throws WingException, SAXException, CrosswalkException, IOException, SQLException
|
||||
{
|
||||
/////////////////////////////////
|
||||
// Start administrative metadata section wrapper
|
||||
String amdSecID = getAmdSecID(amdSecName, mdType, dso);
|
||||
AttributeMap attributes = new AttributeMap();
|
||||
attributes.put("ID", amdSecID);
|
||||
startElement(METS, amdSecName, attributes);
|
||||
|
||||
//If this is a bitstream
|
||||
if (dso.getType() == Constants.BITSTREAM)
|
||||
{
|
||||
// Add this to our list of each file's administrative section IDs
|
||||
String fileID = getFileID((Bitstream) dso);
|
||||
if(fileAmdSecIDs.containsKey(fileID))
|
||||
fileAmdSecIDs.get(fileID).append(" " + amdSecID);
|
||||
else
|
||||
fileAmdSecIDs.put(fileID, new StringBuffer(amdSecID));
|
||||
}//else if an Item
|
||||
else if (dso.getType() == Constants.ITEM)
|
||||
{
|
||||
//Add this to our list of item's administrative section IDs
|
||||
if(amdSecIDS==null)
|
||||
amdSecIDS = new StringBuffer(amdSecID);
|
||||
else
|
||||
amdSecIDS.append(" " + amdSecID);
|
||||
}
|
||||
|
||||
////////////////////////////////
|
||||
// Start a metadata wrapper
|
||||
attributes = new AttributeMap();
|
||||
if (isDefinedMETStype(mdType))
|
||||
{
|
||||
attributes.put("MDTYPE", mdType);
|
||||
}
|
||||
else
|
||||
{
|
||||
attributes.put("MDTYPE","OTHER");
|
||||
attributes.put("OTHERMDTYPE", mdType);
|
||||
}
|
||||
startElement(METS,"mdWrap",attributes);
|
||||
|
||||
//////////////////////////////////
|
||||
// Start the xml data
|
||||
startElement(METS,"xmlData");
|
||||
|
||||
/////////////////////////////////
|
||||
// Send the actual XML content,
|
||||
// using the PREMIS crosswalk for each bitstream
|
||||
try {
|
||||
Element dissemination = crosswalk.disseminateElement(dso);
|
||||
|
||||
SAXFilter filter = new SAXFilter(contentHandler, lexicalHandler, namespaces);
|
||||
// Allow the basics for XML
|
||||
filter.allowElements().allowIgnorableWhitespace().allowCharacters().allowCDATA().allowPrefixMappings();
|
||||
|
||||
SAXOutputter outputter = new SAXOutputter();
|
||||
outputter.setContentHandler(filter);
|
||||
outputter.setLexicalHandler(filter);
|
||||
outputter.output(dissemination);
|
||||
}
|
||||
catch (JDOMException jdome)
|
||||
{
|
||||
throw new WingException(jdome);
|
||||
}
|
||||
catch (AuthorizeException ae)
|
||||
{
|
||||
// just ignore the authorize exception and continue on with
|
||||
//out parsing the xml document.
|
||||
}
|
||||
|
||||
// ////////////////////////////////
|
||||
// End elements
|
||||
endElement(METS,"xmlData");
|
||||
endElement(METS,"mdWrap");
|
||||
endElement(METS,amdSecName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the METS file section. This will contain a list of all bitstreams in the
|
||||
* item. Each bundle, even those that are not typically displayed will be listed.
|
||||
@@ -453,23 +654,9 @@ public class ItemAdapter extends AbstractAdapter
|
||||
// Start a new file section
|
||||
startElement(METS,"fileSec");
|
||||
|
||||
|
||||
// Check if the user is requested a specific bundle or
|
||||
// the all bundles.
|
||||
List<Bundle> bundles;
|
||||
if (fileGrpTypes.size() == 0)
|
||||
bundles = Arrays.asList(item.getBundles());
|
||||
else
|
||||
{
|
||||
bundles = new ArrayList<Bundle>();
|
||||
for (String fileGrpType : fileGrpTypes)
|
||||
{
|
||||
for (Bundle newBundle : item.getBundles(fileGrpType))
|
||||
{
|
||||
bundles.add(newBundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
List<Bundle> bundles = findEnabledBundles();
|
||||
|
||||
// Loop over all requested bundles
|
||||
for (Bundle bundle : bundles)
|
||||
@@ -491,11 +678,6 @@ public class ItemAdapter extends AbstractAdapter
|
||||
isDerivedBundle = true;
|
||||
}
|
||||
|
||||
if (fileGrpTypes.size() != 0 && !fileGrpTypes.contains(use))
|
||||
// The user requested specific file groups and this is not one of them.
|
||||
continue;
|
||||
|
||||
|
||||
// ///////////////////
|
||||
// Start bundle's file group
|
||||
attributes = new AttributeMap();
|
||||
@@ -513,8 +695,13 @@ public class ItemAdapter extends AbstractAdapter
|
||||
originalBitstream = findOriginalBitstream(item, bitstream);
|
||||
String groupID = getGroupFileID((originalBitstream == null) ? bitstream : originalBitstream );
|
||||
|
||||
//Check if there were administrative metadata sections corresponding to this file
|
||||
String admIDs = null;
|
||||
if(fileAmdSecIDs.containsKey(fileID))
|
||||
admIDs = fileAmdSecIDs.get(fileID).toString();
|
||||
|
||||
// Render the actual file & flocate elements.
|
||||
renderFile(item, bitstream, fileID, groupID);
|
||||
renderFile(item, bitstream, fileID, groupID, admIDs);
|
||||
|
||||
// Remember all the viewable content bitstreams for later in the
|
||||
// structMap.
|
||||
@@ -568,6 +755,9 @@ public class ItemAdapter extends AbstractAdapter
|
||||
// add references to the Descriptive metadata
|
||||
if (dmdSecIDS != null)
|
||||
attributes.put("DMDID", dmdSecIDS.toString());
|
||||
// add references to the Administrative metadata
|
||||
if (amdSecIDS != null)
|
||||
attributes.put("AMDID", amdSecIDS.toString());
|
||||
startElement(METS,"div",attributes);
|
||||
|
||||
// add a fptr pointer to the primary bitstream.
|
||||
@@ -664,8 +854,35 @@ public class ItemAdapter extends AbstractAdapter
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks which Bundles of current item a user has requested.
|
||||
* If none specifically requested, then all Bundles are returned.
|
||||
*
|
||||
* @return List of enabled bundles
|
||||
*/
|
||||
protected List<Bundle> findEnabledBundles() throws SQLException
|
||||
{
|
||||
// Check if the user is requested a specific bundle or
|
||||
// the all bundles.
|
||||
List<Bundle> bundles;
|
||||
if (fileGrpTypes.size() == 0)
|
||||
bundles = Arrays.asList(item.getBundles());
|
||||
else
|
||||
{
|
||||
bundles = new ArrayList<Bundle>();
|
||||
for (String fileGrpType : fileGrpTypes)
|
||||
{
|
||||
for (Bundle newBundle : item.getBundles(fileGrpType))
|
||||
{
|
||||
bundles.add(newBundle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return bundles;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* For a bitstream that's a thumbnail or extracted text, find the
|
||||
* corresponding bitstream it was derived from, in the ORIGINAL bundle.
|
||||
|
Reference in New Issue
Block a user