Package org.dspace.content.packager

Source Code of org.dspace.content.packager.AbstractMETSDisseminator

/*
* AbstractMETSDisseminator.java
*
* Version: $Revision: 3761 $
*
* Date: $Date: 2009-05-07 04:18:02 +0000 (Thu, 07 May 2009) $
*
* 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.packager;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.authorize.AuthorizeManager;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.crosswalk.CrosswalkException;
import org.dspace.content.crosswalk.DisseminationCrosswalk;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.PluginManager;
import org.dspace.core.Utils;
import org.jdom.Namespace;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;

import edu.harvard.hul.ois.mets.Agent;
import edu.harvard.hul.ois.mets.AmdSec;
import edu.harvard.hul.ois.mets.Checksumtype;
import edu.harvard.hul.ois.mets.Div;
import edu.harvard.hul.ois.mets.DmdSec;
import edu.harvard.hul.ois.mets.FLocat;
import edu.harvard.hul.ois.mets.FileGrp;
import edu.harvard.hul.ois.mets.FileSec;
import edu.harvard.hul.ois.mets.Fptr;
import edu.harvard.hul.ois.mets.Loctype;
import edu.harvard.hul.ois.mets.MdWrap;
import edu.harvard.hul.ois.mets.Mdtype;
import edu.harvard.hul.ois.mets.Mets;
import edu.harvard.hul.ois.mets.MetsHdr;
import edu.harvard.hul.ois.mets.Name;
import edu.harvard.hul.ois.mets.Role;
import edu.harvard.hul.ois.mets.StructMap;
import edu.harvard.hul.ois.mets.TechMD;
import edu.harvard.hul.ois.mets.Type;
import edu.harvard.hul.ois.mets.XmlData;
import edu.harvard.hul.ois.mets.helper.MetsElement;
import edu.harvard.hul.ois.mets.helper.MetsException;
import edu.harvard.hul.ois.mets.helper.MetsValidator;
import edu.harvard.hul.ois.mets.helper.MetsWriter;
import edu.harvard.hul.ois.mets.helper.PCData;
import edu.harvard.hul.ois.mets.helper.PreformedXML;

/**
* Base class for disseminator of
* METS (Metadata Encoding & Transmission Standard) Package.<br>
*   See <a href="http://www.loc.gov/standards/mets/">http://www.loc.gov/standards/mets/</a>
* <p>
* This is a generic packager framework intended to be subclassed to create
* packagers for more specific METS "profiles".   METS is an
* abstract and flexible framework that can encompass many
* different kinds of metadata and inner package structures.
* <p>
* <b>Package Parameters:</b><br>
* <code>manifestOnly</code> -- if true, generate a standalone XML
* document of the METS manifest instead of a complete package.  Any
* other metadata (such as licenses) will be encoded inline.
* Default is <code>false</code>.
*
*   <code>unauthorized</code> -- this determines what is done when the
*   packager encounters a Bundle or Bitstream it is not authorized to
*   read.  By default, it just quits with an AuthorizeException.
*   If this option is present, it must be one of the following values:
*     <code>skip</code> -- simply exclude unreadable content from package.
*     <code>zero</code> -- include unreadable bitstreams as 0-length files;
*       unreadable Bundles will still cause authorize errors.
*
* @author Larry Stone
* @author Robert Tansley
* @version $Revision: 3761 $
*/
public abstract class AbstractMETSDisseminator
    implements PackageDisseminator
{
    /** log4j category */
    private static Logger log = Logger.getLogger(AbstractMETSDisseminator.class);

    /** Filename of manifest, relative to package toplevel. */
    public static final String MANIFEST_FILE = "mets.xml";

    // JDOM xml output writer - indented format for readability.
    private static XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());

    // for gensym()
    private int idCounter = 1;

    /**
     * Table of files to add to package, such as mdRef'd metadata.
     * Key is relative pathname of file, value is <code>InputStream</code>
     * with contents to put in it.
     * New map is created by disseminate().
     */
    protected Map extraFiles = null;

    /**
     * Make a new unique ID with specified prefix.
     * @param prefix the prefix of the identifier, constrained to XML ID schema
     * @return a new string identifier unique in this session (instance).
     */
    protected String gensym(String prefix)
    {
        return prefix + "_" + String.valueOf(idCounter++);
    }

    public String getMIMEType(PackageParameters params)
    {
        return (params != null && params.getProperty("manifestOnly") != null) ?
                "text/xml" : "application/zip";
    }

    /**
     * Export the object (Item, Collection, or Community) to a
     * package file on the indicated OutputStream.
     * Gets an exception of the object cannot be packaged or there is
     * a failure creating the package.
     *
     * @param context - DSpace context.
     * @param dso - DSpace object (item, collection, etc)
     * @param pkg - output stream on which to write package
     * @throws PackageException if package cannot be created or there is
     *  a fatal error in creating it.
     */
    public void disseminate(Context context, DSpaceObject dso,
                            PackageParameters params, OutputStream pkg)
        throws PackageValidationException, CrosswalkException, AuthorizeException, SQLException, IOException
    {
        if (dso.getType() == Constants.ITEM)
        {
            Item item = (Item)dso;
            long lmTime = item.getLastModified().getTime();

            // how to handle unauthorized bundle/bitstream:
            String unauth = (params == null) ? null : params.getProperty("unauthorized");

            if (params != null && params.getProperty("manifestOnly") != null)
            {
                extraFiles = null;
                writeManifest(context, item, params, pkg);
            }
            else
            {
                extraFiles = new HashMap();
                ZipOutputStream zip = new ZipOutputStream(pkg);
                zip.setComment("METS archive created by DSpace METSDisseminationCrosswalk");

                // write manifest first.
                ZipEntry me = new ZipEntry(MANIFEST_FILE);
                me.setTime(lmTime);
                zip.putNextEntry(me);
                writeManifest(context, item, params, zip);
                zip.closeEntry();
               
                // copy extra (meta?) bitstreams into zip
                Iterator fi = extraFiles.keySet().iterator();
                while (fi.hasNext())
                {
                    String fname = (String)fi.next();
                    ZipEntry ze = new ZipEntry(fname);
                    ze.setTime(lmTime);
                    zip.putNextEntry(ze);
                    Utils.copy((InputStream)extraFiles.get(fname), zip);
                    zip.closeEntry();
                }

                // copy all non-meta bitstreams into zip
                Bundle bundles[] = item.getBundles();
                for (int i = 0; i < bundles.length; i++)
                {
                    if (!PackageUtils.isMetaInfoBundle(bundles[i]))
                    {
                        // unauthorized bundle?
                        if (!AuthorizeManager.authorizeActionBoolean(context,
                                    bundles[i], Constants.READ))
                        {
                            if (unauth != null &&
                                (unauth.equalsIgnoreCase("skip")))
                            {
                                log.warn("Skipping Bundle[\""+bundles[i].getName()+"\"] because you are not authorized to read it.");
                                continue;
                            }
                            else
                                throw new AuthorizeException("Not authorized to read Bundle named \""+bundles[i].getName()+"\"");
                        }
                        Bitstream[] bitstreams = bundles[i].getBitstreams();
                        for (int k = 0; k < bitstreams.length; k++)
                        {
                            boolean auth = AuthorizeManager.authorizeActionBoolean(context,
                                    bitstreams[k], Constants.READ);
                            if (auth ||
                                (unauth != null && unauth.equalsIgnoreCase("zero")))
                            {
                                ZipEntry ze = new ZipEntry(
                                    makeBitstreamName(bitstreams[k]));
                                ze.setTime(lmTime);
                                ze.setSize(auth ? bitstreams[k].getSize() : 0);
                                zip.putNextEntry(ze);
                                if (auth)
                                Utils.copy(bitstreams[k].retrieve(), zip);
                                else
                                    log.warn("Adding zero-length file for Bitstream, SID="+String.valueOf(bitstreams[k].getSequenceID())+", not authorized for READ.");
                                zip.closeEntry();
                            }
                            else if (unauth != null &&
                                     unauth.equalsIgnoreCase("skip"))
                            {
                                log.warn("Skipping Bitstream, SID="+String.valueOf(bitstreams[k].getSequenceID())+", not authorized for READ.");
                            }
                            else
                            {
                                throw new AuthorizeException("Not authorized to read Bitstream, SID="+String.valueOf(bitstreams[k].getSequenceID()));
                            }
                        }
                    }
                }
                zip.close();
                extraFiles = null;
            }

        }
        else
            throw new PackageValidationException("Can only disseminate an Item now.");
    }

    /**
     * Create name that bitstream will have in archive.  Name must
     * be unique and relative to archive top level, e.g. "bitstream_<id>.ext"
     */
    private String makeBitstreamName(Bitstream bitstream)
    {
        String base = "bitstream_"+String.valueOf(bitstream.getID());
        String ext[] = bitstream.getFormat().getExtensions();
        return (ext.length > 0) ? base+"."+ext[0] : base;
    }


    // set metadata type - if Mdtype.parse() gets exception,
    // that means it's not in the MDTYPE vocabulary, so use OTHER.
    private void setMdType(MdWrap mdWrap, String mdtype)
    {
        try
        {
            mdWrap.setMDTYPE(Mdtype.parse(mdtype));
        }
        catch (MetsException e)
        {
            mdWrap.setMDTYPE(Mdtype.OTHER);
            mdWrap.setOTHERMDTYPE(mdtype);
        }
    }

    /**
     * Write out a METS manifest.
     * Mostly lifted from Rob Tansley's METS exporter.
     */
    private void writeManifest(Context context, Item item,
                               PackageParameters params, OutputStream out)
        throws PackageValidationException, CrosswalkException, AuthorizeException, SQLException, IOException

    {
        try
        {
            // Create the METS file
            Mets mets = new Mets();
        
            // Top-level stuff
            mets.setID(gensym("mets"));
            mets.setOBJID("hdl:" + item.getHandle());
            mets.setLABEL("DSpace Item");
            mets.setPROFILE(getProfile());
        
            // MetsHdr
            MetsHdr metsHdr = new MetsHdr();
            metsHdr.setCREATEDATE(new Date()); // FIXME: CREATEDATE is now:
                                               // maybe should be item create
            // date?

            // Agent
            Agent agent = new Agent();
            agent.setROLE(Role.CUSTODIAN);
            agent.setTYPE(Type.ORGANIZATION);
            Name name = new Name();
            name.getContent()
                    .add(new PCData(ConfigurationManager
                                    .getProperty("dspace.name")));
            agent.getContent().add(name);
            metsHdr.getContent().add(agent);
            mets.getContent().add(metsHdr);
        
            // add DMD sections
            // Each type element MAY be either just a MODS-and-crosswalk name, OR
            // a combination "MODS-name:crosswalk-name" (e.g. "DC:qDC").
            String dmdTypes[] = getDmdTypes(params);

            // record of ID of each dmdsec to make DMDID in structmap.
            String dmdGroup = gensym("dmd_group");
            String dmdId[] = new String[dmdTypes.length];
            for (int i = 0; i < dmdTypes.length; ++i)
            {
                dmdId[i] = gensym("dmd");
                XmlData xmlData = new XmlData();
                String xwalkName, metsName;
                String parts[] = dmdTypes[i].split(":", 2);
                if (parts.length > 1)
                {
                    metsName = parts[0];
                    xwalkName = parts[1];
                }
                else
                    xwalkName = metsName = dmdTypes[i];

                DisseminationCrosswalk xwalk = (DisseminationCrosswalk)
                  PluginManager.getNamedPlugin(DisseminationCrosswalk.class, xwalkName);
                if (xwalk == null)
                    throw new PackageValidationException("Cannot find "+dmdTypes[i]+" crosswalk plugin!");
                else
                    crosswalkToMets(xwalk, item, xmlData);

                DmdSec dmdSec = new DmdSec();
                dmdSec.setID(dmdId[i]);
                dmdSec.setGROUPID(dmdGroup);
                MdWrap mdWrap = new MdWrap();
                setMdType(mdWrap, metsName);
                mdWrap.getContent().add(xmlData);
                dmdSec.getContent().add(mdWrap);
                mets.getContent().add(dmdSec);
            }
        
            // Only add license AMD section if there are any licenses.
            // Catch authorization failures accessing license bitstreams
            // only if we are skipping unauthorized bitstreams.
            String licenseID = null;
            try
            {
            AmdSec amdSec = new AmdSec();
            addRightsMd(context, item, amdSec);
            if (amdSec.getContent().size() > 0)
            {
                licenseID = gensym("license");
                amdSec.setID(licenseID);
                mets.getContent().add(amdSec);
            }
            }
            catch (AuthorizeException e)
            {
                String unauth = (params == null) ? null : params.getProperty("unauthorized");
                if (!(unauth != null && unauth.equalsIgnoreCase("skip")))
                    throw e;
                else
                    log.warn("Skipping license metadata because of access failure: "+e.toString());
            }

            // FIXME: History data???? Nooooo!!!!

            // fileSec - all non-metadata bundles go into fileGrp,
            // and each bitstream therein into a file.
            // Create the bitstream-level techMd and div's for structmap
            // at the same time so we can connec the IDREFs to IDs.
            FileSec fileSec = new FileSec();
        
            String techMdType = getTechMdType(params);
            String parts[] = techMdType.split(":", 2);
            String xwalkName, metsName;
            if (parts.length > 1)
            {
                metsName = parts[0];
                xwalkName = parts[1];
            }
            else
                xwalkName = metsName = techMdType;

            DisseminationCrosswalk xwalk = (DisseminationCrosswalk)
              PluginManager.getNamedPlugin(DisseminationCrosswalk.class, xwalkName);
            if (xwalk == null)
                throw new PackageValidationException("Cannot find "+xwalkName+" crosswalk plugin!");

            // log the primary bitstream for structmap
            String primaryBitstreamFileID = null;

            // accumulate content DIV items to put in structMap later.
            List contentDivs = new ArrayList();

            // how to handle unauthorized bundle/bitstream:
            String unauth = (params == null) ? null : params.getProperty("unauthorized");

            Bundle[] bundles = item.getBundles();
            for (int i = 0; i < bundles.length; i++)
            {
                if (PackageUtils.isMetaInfoBundle(bundles[i]))
                    continue;

                // unauthorized bundle?
                // NOTE: This must match the logic in disseminate()
                if (!AuthorizeManager.authorizeActionBoolean(context,
                            bundles[i], Constants.READ))
                {
                    if (unauth != null &&
                        (unauth.equalsIgnoreCase("skip")))
                        continue;
                    else
                        throw new AuthorizeException("Not authorized to read Bundle named \""+bundles[i].getName()+"\"");
                }

                Bitstream[] bitstreams = bundles[i].getBitstreams();

                // Create a fileGrp
                FileGrp fileGrp = new FileGrp();
        
                // Bundle name for USE attribute
                String bName = bundles[i].getName();
                if ((bName != null) && !bName.equals(""))
                    fileGrp.setUSE(bundleToFileGrp(bName));
        
                // watch for primary bitstream
                int primaryBitstreamID = -1;
                boolean isContentBundle = false;
                if ((bName != null) && bName.equals("ORIGINAL"))
                {
                    isContentBundle = true;
                    primaryBitstreamID = bundles[i].getPrimaryBitstreamID();
                }

                for (int bits = 0; bits < bitstreams.length; bits++)
                {
                    // Check for authorization.  Handle unauthorized
                    // bitstreams to match the logic in disseminate(),
                    // i.e. "unauth=zero" means include a 0-length bitstream,
                    // "unauth=skip" means to ignore it (and exclude from
                    // manifest).
                    boolean auth = AuthorizeManager.authorizeActionBoolean(context,
                            bitstreams[bits], Constants.READ);
                    if (!auth)
                    {
                        if (unauth != null && unauth.equalsIgnoreCase("skip"))
                            continue;
                        else if (!(unauth != null && unauth.equalsIgnoreCase("zero")))
                            throw new AuthorizeException("Not authorized to read Bitstream, SID="+String.valueOf(bitstreams[bits].getSequenceID()));
                    }

                    String sid = String.valueOf(bitstreams[bits].getSequenceID());
        
                    edu.harvard.hul.ois.mets.File file = new edu.harvard.hul.ois.mets.File();
        
                    String xmlIDstart = "bitstream_";
                    String fileID = xmlIDstart + sid;

                    file.setID(fileID);

                    // log primary bitstream for later (structMap)
                    if (bitstreams[bits].getID() == primaryBitstreamID)
                        primaryBitstreamFileID = fileID;

                    // if this is content, add to structmap too:
                    if (isContentBundle)
                    {
                        Div div = new Div();
                        div.setID(gensym("div"));
                        div.setTYPE("DSpace Content Bitstream");
                        Fptr fptr = new Fptr();
                        fptr.setFILEID(fileID);
                        div.getContent().add(fptr);
                        contentDivs.add(div);
                    }

                    file.setSEQ(bitstreams[bits].getSequenceID());
        
                    String groupID = "GROUP_" + xmlIDstart + sid;
        
                    /*
                     * If we're in THUMBNAIL or TEXT bundles, the bitstream is
                     * extracted text or a thumbnail, so we use the name to work
                     * out which bitstream to be in the same group as
                     */
                    if ((bundles[i].getName() != null)
                            && (bundles[i].getName().equals("THUMBNAIL") ||
                                bundles[i].getName().startsWith("TEXT")))
                    {
                        // Try and find the original bitstream, and chuck the
                        // derived bitstream in the same group
                        Bitstream original = findOriginalBitstream(item,
                                bitstreams[bits]);
        
                        if (original != null)
                        {
                            groupID = "GROUP_" + xmlIDstart
                                    + original.getSequenceID();
                        }
                    }
        
                    file.setGROUPID(groupID);
                    file.setMIMETYPE(bitstreams[bits].getFormat().getMIMEType());
        
                    // FIXME: CREATED: no date

                    file.setSIZE(auth ? bitstreams[bits].getSize() : 0);

                    // translate checksum and type to METS, if available.
                    String csType = bitstreams[bits].getChecksumAlgorithm();
                    String cs = bitstreams[bits].getChecksum();
                    if (auth && cs != null && csType != null)
                    {
                        try
                        {
                            file.setCHECKSUMTYPE(Checksumtype.parse(csType));
                            file.setCHECKSUM(cs);
                        }
                        catch (MetsException e)
                        {
                            log.warn("Cannot set bitstream checksum type="+csType+" in METS.");
                        }
                    }
        
                    // FLocat: filename is MD5 checksum
                    FLocat flocat = new FLocat();
                    flocat.setLOCTYPE(Loctype.URL);
                    flocat.setXlinkHref(makeBitstreamName(bitstreams[bits]));

                    // Make bitstream techMD metadata, add to file.
                    String techID = "techMd_for_bitstream_"+bitstreams[bits].getSequenceID();
                    AmdSec fAmdSec = new AmdSec();
                    fAmdSec.setID(techID);
                    TechMD techMd = new TechMD();
                    techMd.setID(gensym("tech"));
                    MdWrap mdWrap = new MdWrap();
                    setMdType(mdWrap, metsName);
                    XmlData xmlData = new XmlData();
                    mdWrap.getContent().add(xmlData);
                    techMd.getContent().add(mdWrap);
                    fAmdSec.getContent().add(techMd);
                    mets.getContent().add(fAmdSec);
                    crosswalkToMets(xwalk, bitstreams[bits], xmlData);
                    file.setADMID(techID);

                    // Add FLocat to File, and File to FileGrp
                    file.getContent().add(flocat);
                    fileGrp.getContent().add(file);
                }
        
                // Add fileGrp to fileSec
                fileSec.getContent().add(fileGrp);
            }
        
            // Add fileSec to document
            mets.getContent().add(fileSec);
        
            // Create simple structMap: initial div represents the Item,
            // and user-visible content bitstreams are in its child divs.
            StringBuffer dmdIds = new StringBuffer();
            for (int i = 0; i < dmdId.length; ++i)
                dmdIds.append(" "+dmdId[i]);
            StructMap structMap = new StructMap();
            structMap.setID(gensym("struct"));
            structMap.setTYPE("LOGICAL");
            structMap.setLABEL("DSpace");
            Div div0 = new Div();
            div0.setID(gensym("div"));
            div0.setTYPE("DSpace Item");
            div0.setDMDID(dmdIds.substring(1));
            if (licenseID != null)
                div0.setADMID(licenseID);

            // if there is a primary bitstream, add FPTR to it.
            if (primaryBitstreamFileID != null)
            {
                Fptr fptr = new Fptr();
                fptr.setFILEID(primaryBitstreamFileID);
                div0.getContent().add(fptr);
            }

            // add DIV for each content bitstream
            div0.getContent().addAll(contentDivs);

            structMap.getContent().add(div0);

            // Does subclass have something to add to structMap?
            addStructMap(context, item, params, mets);

            mets.getContent().add(structMap);

            mets.validate(new MetsValidator());
        
            mets.write(new MetsWriter(out));
        }
        catch (MetsException e)
        {
            // We don't pass up a MetsException, so callers don't need to
            // know the details of the METS toolkit
            // e.printStackTrace();
            throw new PackageValidationException(e);
        }
    }


    /**
     * For a bitstream that's a thumbnail or extracted text, find the
     * corresponding bitstream it was derived from, in the ORIGINAL bundle.
     *
     * @param item
     *            the item we're dealing with
     * @param derived
     *            the derived bitstream
     *
     * @return the corresponding original bitstream (or null)
     */
    protected static Bitstream findOriginalBitstream(Item item, Bitstream derived)
        throws SQLException
    {
        Bundle[] bundles = item.getBundles();

        // Filename of original will be filename of the derived bitstream
        // minus the extension (last 4 chars - .jpg or .txt)
        String originalFilename = derived.getName().substring(0,
                derived.getName().length() - 4);

        // First find "original" bundle
        for (int i = 0; i < bundles.length; i++)
        {
            if ((bundles[i].getName() != null)
                    && bundles[i].getName().equals("ORIGINAL"))
            {
                // Now find the corresponding bitstream
                Bitstream[] bitstreams = bundles[i].getBitstreams();

                for (int bsnum = 0; bsnum < bitstreams.length; bsnum++)
                {
                    if (bitstreams[bsnum].getName().equals(originalFilename))
                    {
                        return bitstreams[bsnum];
                    }
                }
            }
        }

        // Didn't find it
        return null;
    }

    // Get result from crosswalk plugin and add it to the document,
    // including namespaces and schema.
    private void crosswalkToMets(DisseminationCrosswalk xwalk,
                                 DSpaceObject dso, MetsElement me)
        throws CrosswalkException,
               IOException, SQLException, AuthorizeException
    {
        // add crosswalk's namespaces and schemaLocation to this element:
        String raw = xwalk.getSchemaLocation();
        String sloc[] = raw == null ? null : raw.split("\\s+");
        Namespace ns[] = xwalk.getNamespaces();
        for (int i = 0; i < ns.length; ++i)
        {
            String uri = ns[i].getURI();
            if (sloc != null && sloc.length > 1 && uri.equals(sloc[0]))
                me.setSchema(ns[i].getPrefix(), uri, sloc[1]);
            else
                me.setSchema(ns[i].getPrefix(), uri);
        }

        // add result of crosswalk
        PreformedXML pXML =
          new PreformedXML(
            xwalk.preferList() ?
              outputter.outputString(xwalk.disseminateList(dso)) :
              outputter.outputString(xwalk.disseminateElement(dso)));
        me.getContent().add(pXML);
    }

    /**
     * Returns name of METS profile to which this package conforms, e.g.
     *  "DSpace METS DIP Profile 1.0"
     * @return string name of profile.
     */
    abstract public String getProfile();

    /**
     * Returns fileGrp's USE attribute value corresponding to a DSpace bundle name.
     *
     * @param bname name of DSpace bundle.
     * @return string name of fileGrp
     */
    abstract public String bundleToFileGrp(String bname);

    /**
     * Get the types of Item-wide DMD to include in package.
     * Each element of the returned array is a String, which
     * MAY be just a simple name, naming both the Crosswalk Plugin and
     * the METS "MDTYPE", <em>or</em> a colon-separated pair consisting of
     * the METS name followed by a colon and the Crosswalk Plugin name.
     * E.g. the type string <code>"DC:qualifiedDublinCore"</code> tells it to
     * create a METS section with <code>MDTYPE="DC"</code> and use the plugin
     * named "qualifiedDublinCore" to obtain the data.
     * @param params the PackageParameters passed to the disseminator.
     * @return array of metadata type strings, never null.
     */
    abstract public String [] getDmdTypes(PackageParameters params)
        throws SQLException, IOException, AuthorizeException;

    /**
     * Get the type string of the technical metadata to create for each
     * Bitstream in the Item.  The type string may be a simple name or
     * colon-separated compound as specified for <code>getDmdTypes()</code> above.
     * @param params the PackageParameters passed to the disseminator.
     * @return array of metadata type strings, never null.
     */
    abstract public String getTechMdType(PackageParameters params)
        throws SQLException, IOException, AuthorizeException;

    /**
     * Add Rights metadata for the Item, in the form of
     * (<code>rightsMd</code> elements) to the given metadata section.
     *
     */
    abstract public void addRightsMd(Context context, Item item, AmdSec amdSec)
        throws SQLException, IOException, AuthorizeException, MetsException;

    /**
     * Add any additional <code>structMap</code> elements to the
     * METS document, as required by this subclass.  A simple default
     * structure map which fulfills the minimal DSpace METS DIP/SIP
     * requirements is already present, so this does not need to do anything.
     * @param mets the METS document to which to add structMaps
     */
    abstract public void addStructMap(Context context, Item item,
                               PackageParameters params, Mets mets)
        throws SQLException, IOException, AuthorizeException, MetsException;
}
TOP

Related Classes of org.dspace.content.packager.AbstractMETSDisseminator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.