Index: NullStreamIngestionCrosswalk.java =================================================================== --- NullStreamIngestionCrosswalk.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 0) +++ NullStreamIngestionCrosswalk.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) @@ -0,0 +1,81 @@ +/* + * NullStreamIngestionCrosswalk + * + * Version: $Revision: 1.4 $ + * + * Date: $Date: 2006/04/10 04:11:09 $ + * + * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts + * Institute of Technology. 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 Hewlett-Packard Company nor the name of the + * Massachusetts Institute of Technology nor the names of their + * 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.InputStream; +import java.io.IOException; +import java.sql.SQLException; + +import org.apache.log4j.Logger; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.DSpaceObject; +import org.dspace.core.Context; + +/** + * A crosswalk to ignore and dispose of the ingested material. + *

+ * Specify this crosswalk in the mapping of e.g. METS metadata field + * types to crosswalks when you wish to ignore a redundant or unknown + * type of metadata. For example, when ingesting a DSpace AIP with an + * AIP ingester, it is best to ignore the rightsMD fields since they + * are already going to be ingested as member bitstreams anyway. + * + * @author Larry Stone + * @version $Revision: 1.0 $ + */ +public class NullStreamIngestionCrosswalk + implements StreamIngestionCrosswalk +{ + /** log4j logger */ + private static Logger log = Logger.getLogger(NullStreamIngestionCrosswalk.class); + + public void ingest(Context context, DSpaceObject dso, InputStream in, String MIMEType) + throws CrosswalkException, IOException, SQLException, AuthorizeException + { + in.close(); + } + + public String getMIMEType() + { + return "text/plain"; + } +} Index: CreativeCommonsTextStreamDisseminationCrosswalk.java =================================================================== --- CreativeCommonsTextStreamDisseminationCrosswalk.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 0) +++ CreativeCommonsTextStreamDisseminationCrosswalk.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) @@ -0,0 +1,102 @@ +/* + * CreativeCommonsTextStreamDisseminationCrosswalk + * + * Version: $Revision: 1.4 $ + * + * Date: $Date: 2006/04/10 04:11:09 $ + * + * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts + * Institute of Technology. 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 Hewlett-Packard Company nor the name of the + * Massachusetts Institute of Technology nor the names of their + * 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.OutputStream; +import java.io.IOException; +import java.sql.SQLException; + +import org.apache.log4j.Logger; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.Bitstream; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.core.Utils; +import org.dspace.license.CreativeCommons; + +/** + * Export the object's Creative Commons license, text form. + * + * @author Larry Stone + * @version $Revision: 1.0 $ + */ +public class CreativeCommonsTextStreamDisseminationCrosswalk + implements StreamDisseminationCrosswalk +{ + /** log4j logger */ + private static Logger log = Logger.getLogger(CreativeCommonsTextStreamDisseminationCrosswalk.class); + + public boolean canDisseminate(Context context, DSpaceObject dso) + { + try + { + return dso.getType() == Constants.ITEM && + CreativeCommons.getLicenseTextBitstream((Item)dso) != null; + } + catch (Exception e) + { + log.error("Failed getting CC license", e); + return false; + } + } + + public void disseminate(Context context, DSpaceObject dso, OutputStream out) + throws CrosswalkException, IOException, SQLException, AuthorizeException + { + if (dso.getType() == Constants.ITEM) + { + Bitstream cc = CreativeCommons.getLicenseTextBitstream((Item)dso); + if (cc != null) + { + Utils.copy(cc.retrieve(), out); + out.close(); + } + } + } + + public String getMIMEType() + { + return "text/plain"; + } +} Index: XSLTIngestionCrosswalk.java =================================================================== --- XSLTIngestionCrosswalk.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) +++ XSLTIngestionCrosswalk.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) @@ -47,11 +47,14 @@ import org.apache.log4j.Logger; import org.dspace.authorize.AuthorizeException; import org.dspace.content.DSpaceObject; +import org.dspace.content.Collection; +import org.dspace.content.Community; import org.dspace.content.Item; import org.dspace.content.MetadataField; import org.dspace.content.MetadataSchema; import org.dspace.content.MetadataValue; import org.dspace.content.authority.Choices; +import org.dspace.content.packager.PackageUtils; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.PluginManager; @@ -89,7 +92,7 @@ } // apply metadata values returned in DIM to the target item. - private void applyDim(List dimList, Item item) + private static void applyDim(List dimList, Item item) throws MetadataValidationException { Iterator di = dimList.iterator(); @@ -112,7 +115,7 @@ } // adds the metadata element from one - private void applyDimField(Element field, Item item) + private static void applyDimField(Element field, Item item) { String schema = field.getAttributeValue("mdschema"); String element = field.getAttributeValue("element"); @@ -121,6 +124,11 @@ String authority = field.getAttributeValue("authority"); String sconf = field.getAttributeValue("confidence"); + // sanity check: some XSL puts an empty string in qualifier, + // change it to null so we match the unqualified DC field: + if (qualifier != null && qualifier.equals("")) + qualifier = null; + if ((authority != null && authority.length() > 0) || (sconf != null && sconf.length() > 0)) { @@ -144,17 +152,13 @@ throws CrosswalkException, IOException, SQLException, AuthorizeException { - if (dso.getType() != Constants.ITEM) - throw new CrosswalkObjectNotSupported("XsltSubmissionionCrosswalk can only crosswalk to an Item."); - Item item = (Item)dso; - XSLTransformer xform = getTransformer(DIRECTION); if (xform == null) throw new CrosswalkInternalException("Failed to initialize transformer, probably error loading stylesheet."); try { List dimList = xform.transform(metadata); - applyDim(dimList, item); + ingestDIM(context, dso, dimList); } catch (XSLTransformException e) { @@ -171,17 +175,13 @@ public void ingest(Context context, DSpaceObject dso, Element root) throws CrosswalkException, IOException, SQLException, AuthorizeException { - if (dso.getType() != Constants.ITEM) - throw new CrosswalkObjectNotSupported("XsltSubmissionionCrosswalk can only crosswalk to an Item."); - Item item = (Item)dso; - XSLTransformer xform = getTransformer(DIRECTION); if (xform == null) throw new CrosswalkInternalException("Failed to initialize transformer, probably error loading stylesheet."); try { Document dimDoc = xform.transform(new Document((Element)root.clone())); - applyDim(dimDoc.getRootElement().getChildren(), item); + ingestDIM(context, dso, dimDoc.getRootElement().getChildren()); } catch (XSLTransformException e) { @@ -191,7 +191,89 @@ } + // return coll/comm "metadata" label corresponding to a DIM field. + private static String getMetadataForDIM(Element field) + { + // make up fieldname, then look for it in xwalk + String element = field.getAttributeValue("element"); + String qualifier = field.getAttributeValue("qualifier"); + String fname = "dc." + element; + if (qualifier != null) + fname += "." + qualifier; + return PackageUtils.dcToContainerMetadata(fname); + } + /** + * Ingest a DIM metadata expression directly, without + * translating some other format into DIM. + * The dim element is expected to be be the root of + * a DIM document. + *

+ * Note that this is ONLY implemented for Item, Collection, and + * Community objects. Also only works for the "dc" metadata schema. + *

+ * @param context the context + * @param dso object into which to ingest metadata + * @param dim root of a DIM expression + */ + + public static void ingestDIM(Context context, DSpaceObject dso, Element dim) + throws CrosswalkException, + IOException, SQLException, AuthorizeException + { + ingestDIM(context, dso, dim.getChildren()); + } + + public static void ingestDIM(Context context, DSpaceObject dso, List fields) + throws CrosswalkException, + IOException, SQLException, AuthorizeException + { + int type = dso.getType(); + if (type == Constants.ITEM) + { + Item item = (Item)dso; + applyDim(fields, item); + } + else if (type == Constants.COLLECTION || + type == Constants.COMMUNITY) + { + Iterator di = fields.iterator(); + while (di.hasNext()) + { + Element field = (Element)di.next(); + String schema = field.getAttributeValue("mdschema"); + if (field.getName().equals("dim") && + field.getNamespace().equals(DIM_NS)) + ingestDIM(context, dso, field.getChildren()); + + else if (field.getName().equals("field") && + field.getNamespace().equals(DIM_NS) && + schema != null && schema.equals("dc")) + { + String md = getMetadataForDIM(field); + if (md == null) + log.warn("Cannot map to Coll/Comm metadata field, DIM element="+ + field.getAttributeValue("element")+", qualifier="+field.getAttributeValue("qualifier")); + else + { + if (type == Constants.COLLECTION) + ((Collection)dso).setMetadata(md, field.getText()); + else + ((Community)dso).setMetadata(md, field.getText()); + } + } + + else + log.warn("ignoring unrecognized DIM element: "+field.toString()); + } + } + else + throw new CrosswalkObjectNotSupported("XsltSubmissionionCrosswalk can only crosswalk to an Item."); + + } + + + /** * Simple command-line rig for testing the DIM output of a stylesheet. * Usage: java XSLTIngestionCrosswalk */ Index: LicenseStreamIngestionCrosswalk.java =================================================================== --- LicenseStreamIngestionCrosswalk.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 0) +++ LicenseStreamIngestionCrosswalk.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) @@ -0,0 +1,97 @@ +/* + * LicenseStreamIngestionCrosswalk + * + * Version: $Revision: 1.4 $ + * + * Date: $Date: 2006/04/10 04:11:09 $ + * + * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts + * Institute of Technology. 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 Hewlett-Packard Company nor the name of the + * Massachusetts Institute of Technology nor the names of their + * 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.ByteArrayOutputStream; +import java.io.InputStream; +import java.io.IOException; +import java.sql.SQLException; + +import org.apache.log4j.Logger; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.content.packager.PackageUtils; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.core.Utils; + +/** + * Accept a DSpace deposit license. + *

+ * Note that this is NOT needed when ingesting a DSpace AIP, since the + * deposit license is stored as a Bitstream (or two) in a dedicated Bundle; + * the normal apparatus of ingestig the AIP will restore that Bitstream + * with its proper name and thus the presence of the deposit license. + *

+ * This crosswalk should only be used when ingesting other kinds of SIPs. + * + * @author Larry Stone + * @version $Revision: 1.0 $ + */ +public class LicenseStreamIngestionCrosswalk + implements StreamIngestionCrosswalk +{ + /** log4j logger */ + private static Logger log = Logger.getLogger(LicenseStreamIngestionCrosswalk.class); + + public void ingest(Context context, DSpaceObject dso, InputStream in, String MIMEType) + throws CrosswalkException, IOException, SQLException, AuthorizeException + { + // If package includes a Creative Commons license, add that: + if (dso.getType() == Constants.ITEM) + { + if (log.isDebugEnabled()) + log.debug("Reading a DSpace Deposit license, MIMEtype="+MIMEType); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + Utils.copy(in, baos); + PackageUtils.addDepositLicense(context, baos.toString(), + (Item)dso, null); + } + } + + public String getMIMEType() + { + return "text/plain"; + } +} Index: CreativeCommonsRDFStreamIngestionCrosswalk.java =================================================================== --- CreativeCommonsRDFStreamIngestionCrosswalk.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 0) +++ CreativeCommonsRDFStreamIngestionCrosswalk.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) @@ -0,0 +1,93 @@ +/* + * CreativeCommonsRDFStreamIngestionCrosswalk + * + * Version: $Revision: 1.4 $ + * + * Date: $Date: 2006/04/10 04:11:09 $ + * + * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts + * Institute of Technology. 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 Hewlett-Packard Company nor the name of the + * Massachusetts Institute of Technology nor the names of their + * 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.InputStream; +import java.io.IOException; +import java.sql.SQLException; + +import org.apache.log4j.Logger; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Item; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.license.CreativeCommons; + +/** + * Ingest a Creative Commons license, RDF form. + *

+ * Note that this is NOT needed when ingesting a DSpace AIP, since the + * CC license is stored as a Bitstream (or two) in a dedicated Bundle; + * the normal apparatus of ingestig the AIP will restore that Bitstream + * with its proper name and thus the presence of the CC license. + *

+ * This crosswalk should only be used when ingesting other kinds of SIPs. + * + * @author Larry Stone + * @version $Revision: 1.0 $ + */ +public class CreativeCommonsRDFStreamIngestionCrosswalk + implements StreamIngestionCrosswalk +{ + /** log4j logger */ + private static Logger log = Logger.getLogger(CreativeCommonsRDFStreamIngestionCrosswalk.class); + + public void ingest(Context context, DSpaceObject dso, InputStream in, String MIMEType) + throws CrosswalkException, IOException, SQLException, AuthorizeException + { + // If package includes a Creative Commons license, add that: + if (dso.getType() == Constants.ITEM) + { + if (log.isDebugEnabled()) + log.debug("Reading a Creative Commons license, MIMEtype="+MIMEType); + + CreativeCommons.setLicense(context, (Item)dso, in, MIMEType); + } + } + + + public String getMIMEType() + { + return "text/rdf"; + } +} Index: AIPDIMCrosswalk.java =================================================================== --- AIPDIMCrosswalk.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 0) +++ AIPDIMCrosswalk.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) @@ -0,0 +1,207 @@ +/* + * AIPDIMCrosswalk.java + * + * Version: $Revision: 1.2 $ + * + * Date: $Date: 2006/03/27 02:57:09 $ + * + * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts + * Institute of Technology. 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 Hewlett-Packard Company nor the name of the + * Massachusetts Institute of Technology nor the names of their + * 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.util.List; + +import java.sql.SQLException; + +import org.dspace.core.Context; +import org.dspace.content.DSpaceObject; +import org.dspace.authorize.AuthorizeException; + +import org.jdom.Element; +import org.jdom.Namespace; + +/** + * Crosswalk descriptive metadata to and from DIM (DSpace Intermediate + * Metadata) format, strictly for the purpose of including a precise and + * complete record of the DMD in an AIP. Although the DIM format was never + * intended to be used outside of DSpace, it is admirably suited to + * describing the exact state of the descriptive MD stored in the RDBMS. + * All crosswalks to standard formats such as MODS and even DC are necessarily + * "lossy" and inexact. Since the purpose of an AIP is to preserve and restore + * the state of an object exactly, DIM is the preferred format for + * recording its descriptive MD. + *

+ * In order to allow external applications to make sense of DSpace AIPs for + * preservation purposes, we recommend adding a parallel descriptive + * metadata section in one of the preferred standard formats such as MODS + * as well as the DIM. + * + * @author Larry Stone + * @version $Revision: 1.2 $ + */ +public class AIPDIMCrosswalk + implements DisseminationCrosswalk, IngestionCrosswalk +{ + /** + * Get XML namespaces of the elements this crosswalk may return. + * Returns the XML namespaces (as JDOM objects) of the root element. + * + * @return array of namespaces, which may be empty. + */ + public Namespace[] getNamespaces() + { + Namespace result[] = new Namespace[1]; + result[0] = XSLTCrosswalk.DIM_NS; + return result; + } + + /** + * Get the XML Schema location(s) of the target metadata format. + * Returns the string value of the xsi:schemaLocation + * attribute that should be applied to the generated XML. + *

+ * It may return the empty string if no schema is known, but crosswalk + * authors are strongly encouraged to implement this call so their output + * XML can be validated correctly. + * @return SchemaLocation string, including URI namespace, followed by + * whitespace and URI of XML schema document, or empty string if unknown. + */ + public String getSchemaLocation() + { + return ""; + } + + /** + * Predicate: Can this disseminator crosswalk the given object. + * Needed by OAI-PMH server implementation. + * + * @param dso dspace object, e.g. an Item. + * @return true when disseminator is capable of producing metadata. + */ + public boolean canDisseminate(DSpaceObject dso) + { + return true; + } + + /** + * Predicate: Does this disseminator prefer to return a list of Elements, + * rather than a single root Element? + *

+ * Some metadata formats have an XML schema without a root element, + * for example, the Dublin Core and Qualified Dublin Core formats. + * This would be true for a crosswalk into QDC, since + * it would "prefer" to return a list, since any root element it has + * to produce would have to be part of a nonstandard schema. In + * most cases your implementation will want to return + * false + * + * @return true when disseminator prefers you call disseminateList(). + */ + public boolean preferList() + { + return false; + } + + /** + * Execute crosswalk, returning List of XML elements. + * Returns a List of JDOM Element objects representing + * the XML produced by the crosswalk. This is typically called when + * a list of fields is desired, e.g. for embedding in a METS document + * xmlData field. + *

+ * When there are no results, an + * empty list is returned, but never null. + * + * @param dso the DSpace Object whose metadata to export. + * @return results of crosswalk as list of XML elements. + * + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. + */ + public List disseminateList(DSpaceObject dso) + throws CrosswalkException, IOException, SQLException, + AuthorizeException + { + Element dim = disseminateElement(dso); + return dim.getChildren(); + } + + /** + * Execute crosswalk, returning one XML root element as + * a JDOM Element object. + * This is typically the root element of a document. + *

+ * + * @param dso the DSpace Object whose metadata to export. + * @return root Element of the target metadata, never null + * + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. + */ + public Element disseminateElement(DSpaceObject dso) + throws CrosswalkException, IOException, SQLException, + AuthorizeException + { + return XSLTDisseminationCrosswalk.createDIM(dso); + } + + /** + * Ingest a whole document. Build Document object around root element, + * and feed that to the transformation, since it may get handled + * differently than a List of metadata elements. + */ + public void ingest(Context context, DSpaceObject dso, Element root) + throws CrosswalkException, IOException, SQLException, AuthorizeException + { + ingest(context, dso, root.getChildren()); + } + + /** + * Fields correspond directly to Item.addMetadata() calls so + * they are simply executed. + */ + public void ingest(Context context, DSpaceObject dso, List dimList) + throws CrosswalkException, + IOException, SQLException, AuthorizeException + { + XSLTIngestionCrosswalk.ingestDIM(context, dso, dimList); + } +} Index: XSLTDisseminationCrosswalk.java =================================================================== --- XSLTDisseminationCrosswalk.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) +++ XSLTDisseminationCrosswalk.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) @@ -48,15 +48,17 @@ import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCValue; import org.dspace.content.DSpaceObject; +import org.dspace.content.Collection; +import org.dspace.content.Community; import org.dspace.content.Item; +import org.dspace.content.Site; import org.dspace.content.authority.Choices; import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; import org.jdom.Document; import org.jdom.Element; import org.jdom.Namespace; -import org.jdom.output.Format; -import org.jdom.output.XMLOutputter; +import org.jdom.Verifier; import org.jdom.transform.XSLTransformException; import org.jdom.transform.XSLTransformer; @@ -84,6 +86,7 @@ * * * @author Larry Stone + * @author Scott Phillips * @version $Revision$ * @see XSLTCrosswalk */ @@ -96,8 +99,6 @@ private final static String DIRECTION = "dissemination"; - private static XMLOutputter outputPretty = new XMLOutputter(Format.getPrettyFormat()); - private static String aliases[] = makeAliases(DIRECTION); public static String[] getPluginNames() @@ -111,8 +112,6 @@ private Namespace namespaces[] = null; - private String rootName = null; - private boolean preferList = false; // load the namespace and schema from config @@ -160,6 +159,11 @@ preferList = ConfigurationManager.getBooleanProperty(prefix+"preferList", false); } + /** + * Return the namespace used by this crosswalk. + * + * @see DisseminationCrosswalk + */ public Namespace[] getNamespaces() { try @@ -173,6 +177,11 @@ return namespaces; } + /** + * Return the schema location used by this crosswalk. + * + * @see DisseminationCrosswalk + */ public String getSchemaLocation() { try @@ -186,24 +195,34 @@ return schemaLocation; } + /** + * Disseminate the DSpace item, collection, or community. + * + * @see DisseminationCrosswalk + */ public Element disseminateElement(DSpaceObject dso) throws CrosswalkException, IOException, SQLException, AuthorizeException { + int type = dso.getType(); + if (!(type == Constants.ITEM || + type == Constants.COLLECTION || + type == Constants.COMMUNITY)) + throw new CrosswalkObjectNotSupported("XSLTDisseminationCrosswalk can only crosswalk items, collections, and communities."); + init(); - if (dso.getType() != Constants.ITEM) - throw new CrosswalkObjectNotSupported("XSLTDisseminationCrosswalk can only crosswalk an Item."); - Item item = (Item)dso; XSLTransformer xform = getTransformer(DIRECTION); if (xform == null) throw new CrosswalkInternalException("Failed to initialize transformer, probably error loading stylesheet."); try { - Document ddim = new Document(getDim(item)); + Document ddim = new Document(createDIM(dso)); Document result = xform.transform(ddim); - return result.getRootElement(); + Element root = result.getRootElement(); + root.detach(); + return root; } catch (XSLTransformException e) { @@ -212,22 +231,30 @@ } } + /** + * Disseminate the DSpace item, collection, or community. + * + * @see DisseminationCrosswalk + */ public List disseminateList(DSpaceObject dso) throws CrosswalkException, IOException, SQLException, AuthorizeException { + int type = dso.getType(); + if (!(type == Constants.ITEM || + type == Constants.COLLECTION || + type == Constants.COMMUNITY)) + throw new CrosswalkObjectNotSupported("XSLTDisseminationCrosswalk can only crosswalk a items, collections, and communities."); + init(); - if (dso.getType() != Constants.ITEM) - throw new CrosswalkObjectNotSupported("XSLTDisseminationCrosswalk can only crosswalk an Item."); - Item item = (Item)dso; XSLTransformer xform = getTransformer(DIRECTION); if (xform == null) throw new CrosswalkInternalException("Failed to initialize transformer, probably error loading stylesheet."); try { - return xform.transform(getDim(item).getChildren()); + return xform.transform(createDIM(dso).getChildren()); } catch (XSLTransformException e) { @@ -236,48 +263,203 @@ } } + /** + * Determine is this crosswalk can dessiminate the given object. + * + * @see DisseminationCrosswalk + */ + public boolean canDisseminate(DSpaceObject dso) + { + return dso.getType() == Constants.ITEM; + } - // build DIM expression of Item's metadata. - private Element getDim(Item item) + /** + * return true if this crosswalk prefers the list form over an singe + * element, otherwise false. + * + * @see DisseminationCrosswalk + */ + public boolean preferList() { - DCValue[] dc = item.getMetadata(Item.ANY, Item.ANY, Item.ANY, Item.ANY); + try + { + init(); + } + catch (CrosswalkInternalException e) + { + log.error(e.toString()); + } + return preferList; + } + + /** + * Generate an intermediate representation of a DSpace object. + * + * @param dso The dspace object to build a representation of. + */ + public static Element createDIM(DSpaceObject dso, DCValue[] dcvs) + { Element dim = new Element("dim", DIM_NS); - for (int i = 0; i < dc.length; i++) + String type = Constants.typeText[dso.getType()]; + dim.setAttribute("dspaceType",type); + + for (int i = 0; i < dcvs.length; i++) { - Element field = new Element("field", DIM_NS); - field.setAttribute("mdschema", dc[i].schema); - field.setAttribute("element", dc[i].element); - if (dc[i].qualifier != null) - field.setAttribute("qualifier", dc[i].qualifier); - if (dc[i].language != null) - field.setAttribute("lang", dc[i].language); - if (dc[i].value != null) - field.setText(dc[i].value); - if (dc[i].authority != null) - { - field.setAttribute("authority", dc[i].authority); - field.setAttribute("confidence", Choices.getConfidenceText(dc[i].confidence)); - } + DCValue dcv = dcvs[i]; + Element field = + createField(dcv.schema, dcv.element, dcv.qualifier, + dcv.language, dcv.value, dcv.authority, dcv.confidence); dim.addContent(field); } return dim; } - public boolean canDisseminate(DSpaceObject dso) + /** + * Generate an intermediate representation of a DSpace object. + * + * @param dso The dspace object to build a representation of. + */ + public static Element createDIM(DSpaceObject dso) { - return dso.getType() == Constants.ITEM; + if (dso.getType() == Constants.ITEM) + { + Item item = (Item) dso; + return createDIM(dso, item.getMetadata(Item.ANY, Item.ANY, Item.ANY, Item.ANY)); + } + else + { + Element dim = new Element("dim", DIM_NS); + String type = Constants.typeText[dso.getType()]; + dim.setAttribute("dspaceType",type); + + if (dso.getType() == Constants.COLLECTION) + { + Collection collection = (Collection) dso; + + String description = collection.getMetadata("introductory_text"); + String description_abstract = collection.getMetadata("short_description"); + String description_table = collection.getMetadata("side_bar_text"); + String identifier_uri = "hdl:" + collection.getHandle(); + String provenance = collection.getMetadata("provenance_description"); + String rights = collection.getMetadata("copyright_text"); + String rights_license = collection.getMetadata("license"); + String title = collection.getMetadata("name"); + + dim.addContent(createField("dc","description",null,null,description)); + dim.addContent(createField("dc","description","abstract",null,description_abstract)); + dim.addContent(createField("dc","description","tableofcontents",null,description_table)); + dim.addContent(createField("dc","identifier","uri",null,identifier_uri)); + dim.addContent(createField("dc","provenance",null,null,provenance)); + dim.addContent(createField("dc","rights",null,null,rights)); + dim.addContent(createField("dc","rights","license",null,rights_license)); + dim.addContent(createField("dc","title",null,null,title)); + } + else if (dso.getType() == Constants.COMMUNITY) + { + Community community = (Community) dso; + + String description = community.getMetadata("introductory_text"); + String description_abstract = community.getMetadata("short_description"); + String description_table = community.getMetadata("side_bar_text"); + String identifier_uri = "hdl:" + community.getHandle(); + String rights = community.getMetadata("copyright_text"); + String title = community.getMetadata("name"); + + dim.addContent(createField("dc","description",null,null,description)); + dim.addContent(createField("dc","description","abstract",null,description_abstract)); + dim.addContent(createField("dc","description","tableofcontents",null,description_table)); + dim.addContent(createField("dc","identifier","uri",null,identifier_uri)); + dim.addContent(createField("dc","rights",null,null,rights)); + dim.addContent(createField("dc","title",null,null,title)); + } + else if (dso.getType() == Constants.SITE) + { + Site site = (Site) dso; + + String identifier_uri = "hdl:" + site.getHandle(); + String title = site.getName(); + String url = site.getURL(); + + //FIXME: adding two URIs for now (site handle and URL), in case site isn't using handles + dim.addContent(createField("dc","identifier","uri",null,identifier_uri)); + dim.addContent(createField("dc","identifier","uri",null,url)); + dim.addContent(createField("dc","title",null,null,title)); + } + // XXX FIXME: Nothing to crosswalk for bitstream? + return dim; + } } - public boolean preferList() + + /** + * Create a new DIM field element with the given attributes. + * + * @param schema The schema the DIM field belongs too. + * @param element The element the DIM field belongs too. + * @param qualifier The qualifier the DIM field belongs too. + * @param language The language the DIM field belongs too. + * @param value The value of the DIM field. + * @return A new DIM field element + */ + private static Element createField(String schema, String element, String qualifier, String language, String value) { - try + return createField(schema, element, qualifier, language, value, null, -1); + } + + /** + * Create a new DIM field element with the given attributes. + * + * @param schema The schema the DIM field belongs too. + * @param element The element the DIM field belongs too. + * @param qualifier The qualifier the DIM field belongs too. + * @param language The language the DIM field belongs too. + * @param value The value of the DIM field. + * @param authority The authority + * @param confidence confidence in the authority + * @return A new DIM field element + */ + private static Element createField(String schema, String element, String qualifier, String language, String value, + String authority, int confidence) + { + Element field = new Element("field",DIM_NS); + field.setAttribute("mdschema",schema); + field.setAttribute("element",element); + if (qualifier != null) + field.setAttribute("qualifier",qualifier); + if (language != null) + field.setAttribute("lang",language); + + field.setText(checkedString(value)); + + if (authority != null) { - init(); + field.setAttribute("authority", authority); + field.setAttribute("confidence", Choices.getConfidenceText(confidence)); } - catch (CrosswalkInternalException e) + + return field; + } + + // Return string with non-XML characters (i.e. low control chars) excised. + private static String checkedString(String value) + { + if (value == null) + return null; + String reason = Verifier.checkCharacterData(value); + if (reason == null) + return value; + else { - log.error(e.toString()); + if (log.isDebugEnabled()) + log.debug("Filtering out non-XML characters in string, reason="+reason); + StringBuffer result = new StringBuffer(value.length()); + for (int i = 0; i < value.length(); ++i) + { + char c = value.charAt(i); + if (Verifier.isXMLCharacter((int)c)) + result.append(c); + } + return result.toString(); } - return preferList; } } Index: LicenseStreamDisseminationCrosswalk.java =================================================================== --- LicenseStreamDisseminationCrosswalk.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 0) +++ LicenseStreamDisseminationCrosswalk.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) @@ -0,0 +1,103 @@ +/* + * LicenseStreamDisseminationCrosswalk + * + * Version: $Revision: 1.4 $ + * + * Date: $Date: 2006/04/10 04:11:09 $ + * + * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts + * Institute of Technology. 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 Hewlett-Packard Company nor the name of the + * Massachusetts Institute of Technology nor the names of their + * 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.OutputStream; +import java.io.IOException; +import java.sql.SQLException; + +import org.apache.log4j.Logger; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Bitstream; +import org.dspace.content.Item; +import org.dspace.content.packager.PackageUtils; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.core.Utils; + +/** + * Export the object's DSpace deposit license. + * + * @author Larry Stone + * @version $Revision: 1.0 $ + */ +public class LicenseStreamDisseminationCrosswalk + implements StreamDisseminationCrosswalk +{ + /** log4j logger */ + private static Logger log = Logger.getLogger(LicenseStreamDisseminationCrosswalk.class); + + public boolean canDisseminate(Context context, DSpaceObject dso) + { + try + { + return dso.getType() == Constants.ITEM && + PackageUtils.findDepositLicense(context, (Item)dso) != null; + } + catch (Exception e) + { + log.error("Failed getting Deposit license", e); + return false; + } + } + + public void disseminate(Context context, DSpaceObject dso, OutputStream out) + throws CrosswalkException, IOException, SQLException, AuthorizeException + { + if (dso.getType() == Constants.ITEM) + { + Bitstream licenseBs = PackageUtils.findDepositLicense(context, (Item)dso); + + if (licenseBs != null) + { + Utils.copy(licenseBs.retrieve(), out); + out.close(); + } + } + } + + public String getMIMEType() + { + return "text/plain"; + } +} Index: MODSDisseminationCrosswalk.java =================================================================== --- MODSDisseminationCrosswalk.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) +++ MODSDisseminationCrosswalk.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) @@ -54,7 +54,10 @@ import org.dspace.authorize.AuthorizeException; import org.dspace.content.DCValue; import org.dspace.content.DSpaceObject; +import org.dspace.content.Collection; +import org.dspace.content.Community; import org.dspace.content.Item; +import org.dspace.content.Site; import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; import org.dspace.core.SelfNamedPlugin; @@ -64,8 +67,8 @@ import org.jdom.JDOMException; import org.jdom.Namespace; import org.jdom.Text; +import org.jdom.Verifier; import org.jdom.input.SAXBuilder; -import org.jdom.output.Format; import org.jdom.output.XMLOutputter; import org.jdom.xpath.XPath; @@ -101,6 +104,7 @@ * by default. * * @author Larry Stone + * @author Scott Phillips * @version $Revision$ */ public class MODSDisseminationCrosswalk extends SelfNamedPlugin @@ -153,7 +157,6 @@ MODS_NS.getURI()+" "+MODS_XSD; private static XMLOutputter outputUgly = new XMLOutputter(); - private static XMLOutputter outputPretty = new XMLOutputter(Format.getPrettyFormat()); private static SAXBuilder builder = new SAXBuilder(); private HashMap modsMap = null; @@ -296,11 +299,17 @@ } } + /** + * Return the MODS namespace + */ public Namespace[] getNamespaces() { return namespaces; } + /** + * Return the MODS schema + */ public String getSchemaLocation() { return schemaLocation; @@ -316,6 +325,9 @@ return disseminateListInternal(dso, true); } + /** + * Disseminate an Item, Collection, or Community to MODS. + */ public Element disseminateElement(DSpaceObject dso) throws CrosswalkException, IOException, SQLException, AuthorizeException @@ -327,23 +339,42 @@ } private List disseminateListInternal(DSpaceObject dso, boolean addSchema) - throws CrosswalkException, - IOException, SQLException, AuthorizeException + throws CrosswalkException, IOException, SQLException, AuthorizeException { - if (dso.getType() != Constants.ITEM) - throw new CrosswalkObjectNotSupported("MODSDisseminationCrosswalk can only crosswalk an Item."); - Item item = (Item)dso; + DCValue[] dcvs = null; + if (dso.getType() == Constants.ITEM) + { + dcvs = item2Metadata((Item) dso); + } + else if (dso.getType() == Constants.COLLECTION) + { + dcvs = collection2Metadata((Collection) dso); + } + else if (dso.getType() == Constants.COMMUNITY) + { + dcvs = community2Metadata((Community) dso); + } + else if (dso.getType() == Constants.SITE) + { + dcvs = site2Metadata((Site) dso); + } + else + { + throw new CrosswalkObjectNotSupported( + "MODSDisseminationCrosswalk can only crosswalk Items, Collections, or Communities"); + } initMap(); - DCValue[] dc = item.getMetadata(Item.ANY, Item.ANY, Item.ANY, Item.ANY); - List result = new ArrayList(dc.length); - for (int i = 0; i < dc.length; i++) + List result = new ArrayList(dcvs.length); + + for(int i=0; i < dcvs.length; i++) { - // Compose qualified DC name - schema.element[.qualifier] - // e.g. "dc.title", "dc.subject.lcc", "lom.Classification.Keyword" - String qdc = dc[i].schema+"."+ - ((dc[i].qualifier == null) ? dc[i].element - : (dc[i].element + "." + dc[i].qualifier)); + String qdc = dcvs[i].schema + "." + dcvs[i].element; + if (dcvs[i].qualifier != null) + { + qdc += "." + dcvs[i].qualifier; + } + String value = dcvs[i].value; modsTriple trip = (modsTriple)modsMap.get(qdc); if (trip == null) @@ -365,11 +396,11 @@ { Object what = ni.next(); if (what instanceof Element) - ((Element)what).setText(dc[i].value); + ((Element)what).setText(checkedString(value)); else if (what instanceof Attribute) - ((Attribute)what).setValue(dc[i].value); + ((Attribute)what).setValue(checkedString(value)); else if (what instanceof Text) - ((Text)what).setText(dc[i].value); + ((Text)what).setText(checkedString(value)); else log.warn("Got unknown object from XPath, class="+what.getClass().getName()); } @@ -387,13 +418,191 @@ return result; } + /** + * ModsCrosswalk can disseminate: Items, Collections, Communities, and Site. + */ public boolean canDisseminate(DSpaceObject dso) { - return true; + if (dso.getType() == Constants.ITEM || + dso.getType() == Constants.COLLECTION || + dso.getType() == Constants.COMMUNITY || + dso.getType() == Constants.SITE) + return true; + else + return false; } + /** + * ModsCrosswalk prefer's element form over list. + */ public boolean preferList() { return false; } + + + /** + * Generate a list of metadata elements for the given DSpace + * site. + * + * @param site + * The site to derive metadata from + */ + protected DCValue[] site2Metadata(Site site) + { + List metadata = new ArrayList(); + + String identifier_uri = "http://hdl.handle.net/" + + site.getHandle(); + String title = site.getName(); + String url = site.getURL(); + + if (identifier_uri != null) + metadata.add(createDCValue("identifier.uri", null, identifier_uri)); + + //FIXME: adding two URIs for now (site handle and URL), in case site isn't using handles + if (url != null) + metadata.add(createDCValue("identifier.uri", null, url)); + + if (title != null) + metadata.add(createDCValue("title", null, title)); + + return (DCValue[]) metadata.toArray(new DCValue[metadata.size()]); + } + /** + * Generate a list of metadata elements for the given DSpace + * community. + * + * @param community + * The community to derive metadata from + */ + protected DCValue[] community2Metadata(Community community) + { + List metadata = new ArrayList(); + + String description = community.getMetadata("introductory_text"); + String description_abstract = community + .getMetadata("short_description"); + String description_table = community.getMetadata("side_bar_text"); + String identifier_uri = "http://hdl.handle.net/" + + community.getHandle(); + String rights = community.getMetadata("copyright_text"); + String title = community.getMetadata("name"); + + if (description != null) + metadata.add(createDCValue("description", null, description)); + + if (description_abstract != null) + metadata.add(createDCValue("description", "abstract", description_abstract)); + + if (description_table != null) + metadata.add(createDCValue("description", "tableofcontents", description_table)); + + if (identifier_uri != null) + metadata.add(createDCValue("identifier.uri", null, identifier_uri)); + + if (rights != null) + metadata.add(createDCValue("rights", null, rights)); + + if (title != null) + metadata.add(createDCValue("title", null, title)); + + return (DCValue[]) metadata.toArray(new DCValue[metadata.size()]); + } + + /** + * Generate a list of metadata elements for the given DSpace + * collection. + * + * @param collection + * The collection to derive metadata from + */ + protected DCValue[] collection2Metadata(Collection collection) + { + List metadata = new ArrayList(); + + String description = collection.getMetadata("introductory_text"); + String description_abstract = collection + .getMetadata("short_description"); + String description_table = collection.getMetadata("side_bar_text"); + String identifier_uri = "http://hdl.handle.net/" + + collection.getHandle(); + String provenance = collection.getMetadata("provenance_description"); + String rights = collection.getMetadata("copyright_text"); + String rights_license = collection.getMetadata("license"); + String title = collection.getMetadata("name"); + + if (description != null) + metadata.add(createDCValue("description",null, description)); + + if (description_abstract != null) + metadata.add(createDCValue("description","abstract",description_abstract)); + + if (description_table != null) + metadata.add(createDCValue("description","tableofcontents",description_table)); + + if (identifier_uri != null) + metadata.add(createDCValue("identifier","uri", identifier_uri)); + + if (provenance != null) + metadata.add(createDCValue("provenance", null, provenance)); + + if (rights != null) + metadata.add(createDCValue("rights", null, rights)); + + if (rights_license != null) + metadata.add(createDCValue("rights.license", null, rights_license)); + + if (title != null) + metadata.add(createDCValue("title", null, title)); + + return (DCValue[]) metadata.toArray(new DCValue[metadata.size()]); + } + + /** + * Generate a list of metadata elements for the given DSpace item. + * + * @param item + * The item to derive metadata from + */ + protected DCValue[] item2Metadata(Item item) + { + DCValue[] dcvs = item.getMetadata(Item.ANY, Item.ANY, Item.ANY, + Item.ANY); + + return dcvs; + } + + private DCValue createDCValue(String element, String qualifier, String value) { + DCValue dcv = new DCValue(); + dcv.schema = "dc"; + dcv.element = element; + dcv.qualifier = qualifier; + dcv.value = value; + return dcv; + } + + // check for non-XML characters + private String checkedString(String value) + { + if (value == null) + return null; + String reason = Verifier.checkCharacterData(value); + if (reason == null) + return value; + else + { + if (log.isDebugEnabled()) + log.debug("Filtering out non-XML characters in string, reason="+reason); + StringBuffer result = new StringBuffer(value.length()); + for (int i = 0; i < value.length(); ++i) + { + char c = value.charAt(i); + if (Verifier.isXMLCharacter((int)c)) + result.append(c); + } + return result.toString(); + } + } + } Index: XSLTCrosswalk.java =================================================================== --- XSLTCrosswalk.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) +++ XSLTCrosswalk.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) @@ -40,6 +40,8 @@ import java.io.File; import java.util.ArrayList; +import java.util.Map; +import java.util.HashMap; import java.util.Enumeration; import java.util.List; @@ -139,13 +141,15 @@ List aliasList = new ArrayList(); Enumeration pe = ConfigurationManager.propertyNames(); - log.debug("XSLTCrosswalk: Looking for config prefix = "+prefix); + if (log.isDebugEnabled()) + log.debug("XSLTCrosswalk: Looking for config prefix = "+prefix); while (pe.hasMoreElements()) { String key = (String)pe.nextElement(); if (key.startsWith(prefix) && key.endsWith(suffix)) { - log.debug("Getting XSLT plugin name from config line: "+key); + if(log.isDebugEnabled()) + log.debug("Getting XSLT plugin name from config line: "+key); aliasList.add(key.substring(prefix.length(), key.length()-suffix.length())); } } Index: CreativeCommonsRDFStreamDisseminationCrosswalk.java =================================================================== --- CreativeCommonsRDFStreamDisseminationCrosswalk.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 0) +++ CreativeCommonsRDFStreamDisseminationCrosswalk.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) @@ -0,0 +1,102 @@ +/* + * CreativeCommonsRDFStreamDisseminationCrosswalk + * + * Version: $Revision: 1.4 $ + * + * Date: $Date: 2006/04/10 04:11:09 $ + * + * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts + * Institute of Technology. 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 Hewlett-Packard Company nor the name of the + * Massachusetts Institute of Technology nor the names of their + * 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.OutputStream; +import java.io.IOException; +import java.sql.SQLException; + +import org.apache.log4j.Logger; + +import org.dspace.authorize.AuthorizeException; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Bitstream; +import org.dspace.content.Item; +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.core.Utils; +import org.dspace.license.CreativeCommons; + +/** + * Export the item's Creative Commons license, RDF form. + * + * @author Larry Stone + * @version $Revision: 1.0 $ + */ +public class CreativeCommonsRDFStreamDisseminationCrosswalk + implements StreamDisseminationCrosswalk +{ + /** log4j logger */ + private static Logger log = Logger.getLogger(CreativeCommonsRDFStreamDisseminationCrosswalk.class); + + public boolean canDisseminate(Context context, DSpaceObject dso) + { + try + { + return dso.getType() == Constants.ITEM && + CreativeCommons.getLicenseRdfBitstream((Item)dso) != null; + } + catch (Exception e) + { + log.error("Failed getting CC license", e); + return false; + } + } + + public void disseminate(Context context, DSpaceObject dso, OutputStream out) + throws CrosswalkException, IOException, SQLException, AuthorizeException + { + if (dso.getType() == Constants.ITEM) + { + Bitstream cc = CreativeCommons.getLicenseRdfBitstream((Item)dso); + if (cc != null) + { + Utils.copy(cc.retrieve(), out); + out.close(); + } + } + } + + public String getMIMEType() + { + return "text/xml"; + } +} Index: AIPTechMDCrosswalk.java =================================================================== --- AIPTechMDCrosswalk.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 0) +++ AIPTechMDCrosswalk.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) @@ -0,0 +1,511 @@ +/* + * AIPTechMDCrosswalk.java + * + * Version: $Revision: 1.2 $ + * + * Date: $Date: 2006/03/27 02:57:09 $ + * + * Copyright (c) 2002-2005, Hewlett-Packard Company and Massachusetts + * Institute of Technology. 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 Hewlett-Packard Company nor the name of the + * Massachusetts Institute of Technology nor the names of their + * 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.util.List; +import java.util.ArrayList; +import java.util.Iterator; + +import java.sql.SQLException; + +import org.dspace.core.Constants; +import org.dspace.core.Context; +import org.dspace.core.ConfigurationManager; +import org.dspace.content.DCValue; +import org.dspace.content.Item; +import org.dspace.content.Bitstream; +import org.dspace.content.BitstreamFormat; +import org.dspace.content.Collection; +import org.dspace.content.Community; +import org.dspace.content.DSpaceObject; +import org.dspace.content.Site; +import org.dspace.content.packager.PackageUtils; +import org.dspace.eperson.EPerson; +import org.dspace.authorize.AuthorizeException; + +import org.apache.log4j.Logger; +import org.dspace.content.packager.DSpaceAIPIngester; +import org.dspace.content.packager.METSManifest; + +import org.jdom.Element; +import org.jdom.Namespace; + +/** + * Crosswalk of technical metadata for DSpace AIP. This is + * only intended for use by the METS AIP packager. It borrows the + * DIM XML format and DC field names, although it abuses the meaning + * of Dublin Core terms and qualifiers because this format is + * ONLY FOR DSPACE INTERNAL USE AND INGESTION. It is needed to record + * a complete and accurate image of all of the attributes an object + * has in the RDBMS. + * + * It encodes the following common properties of all archival objects: + * + * identifier.uri -- persistent identifier of object in URI form (e.g. Handle URN) + * relation.isPartOf -- persistent identifier of object's parent in URI form (e.g. Handle URN) + * relation.isReferencedBy -- if relevant, persistent identifier of other objects that map this one as a child. May repeat. + * + * There may also be other fields, depending on the type of object, + * which encode attributes that are not part of the descriptive metadata and + * are not adequately covered by other technical MD formats (i.e. PREMIS). + * + * Configuration entries: + * aip.ingest.createEperson -- boolean, create EPerson for Submitter + * automatically, on ingest, if it doesn't exist. + * + * @author Larry Stone + * @version $Revision: 1.2 $ + */ +public class AIPTechMDCrosswalk + implements DisseminationCrosswalk, IngestionCrosswalk +{ + /** log4j category */ + private static Logger log = Logger.getLogger(AIPTechMDCrosswalk.class); + + /** + * Get XML namespaces of the elements this crosswalk may return. + * Returns the XML namespaces (as JDOM objects) of the root element. + * + * @return array of namespaces, which may be empty. + */ + public Namespace[] getNamespaces() + { + Namespace result[] = new Namespace[1]; + result[0] = XSLTCrosswalk.DIM_NS; + return result; + } + + /** + * Get the XML Schema location(s) of the target metadata format. + * Returns the string value of the xsi:schemaLocation + * attribute that should be applied to the generated XML. + *

+ * It may return the empty string if no schema is known, but crosswalk + * authors are strongly encouraged to implement this call so their output + * XML can be validated correctly. + * @return SchemaLocation string, including URI namespace, followed by + * whitespace and URI of XML schema document, or empty string if unknown. + */ + public String getSchemaLocation() + { + return ""; + } + + /** + * Predicate: Can this disseminator crosswalk the given object. + * Needed by OAI-PMH server implementation. + * + * @param dso dspace object, e.g. an Item. + * @return true when disseminator is capable of producing metadata. + */ + public boolean canDisseminate(DSpaceObject dso) + { + return true; + } + + /** + * Predicate: Does this disseminator prefer to return a list of Elements, + * rather than a single root Element? + *

+ * Some metadata formats have an XML schema without a root element, + * for example, the Dublin Core and Qualified Dublin Core formats. + * This would be true for a crosswalk into QDC, since + * it would "prefer" to return a list, since any root element it has + * to produce would have to be part of a nonstandard schema. In + * most cases your implementation will want to return + * false + * + * @return true when disseminator prefers you call disseminateList(). + */ + public boolean preferList() + { + return false; + } + + /** + * Execute crosswalk, returning List of XML elements. + * Returns a List of JDOM Element objects representing + * the XML produced by the crosswalk. This is typically called when + * a list of fields is desired, e.g. for embedding in a METS document + * xmlData field. + *

+ * When there are no results, an + * empty list is returned, but never null. + * + * @param dso the DSpace Object whose metadata to export. + * @return results of crosswalk as list of XML elements. + * + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. + */ + public List disseminateList(DSpaceObject dso) + throws CrosswalkException, IOException, SQLException, + AuthorizeException + { + Element dim = disseminateElement(dso); + return dim.getChildren(); + } + + /** + * Execute crosswalk, returning one XML root element as + * a JDOM Element object. + * This is typically the root element of a document. + *

+ * + * @param dso the DSpace Object whose metadata to export. + * @return root Element of the target metadata, never null + * + * @throws CrosswalkInternalException (CrosswalkException) failure of the crosswalk itself. + * @throws CrosswalkObjectNotSupported (CrosswalkException) Cannot crosswalk this kind of DSpace object. + * @throws IOException I/O failure in services this calls + * @throws SQLException Database failure in services this calls + * @throws AuthorizeException current user not authorized for this operation. + */ + public Element disseminateElement(DSpaceObject dso) + throws CrosswalkException, IOException, SQLException, + AuthorizeException + { + List dc = new ArrayList(); + if (dso.getType() == Constants.ITEM) + { + Item item = (Item)dso; + EPerson is = item.getSubmitter(); + if (is != null) + dc.add(makeDC("creator", null, is.getEmail())); + dc.add(makeDC("identifier", "uri", "hdl:" + item.getHandle())); + Collection owningColl = item.getOwningCollection(); + String owner = owningColl.getHandle(); + if (owner != null) + dc.add(makeDC("relation", "isPartOf", "hdl:"+owner)); + Collection inColl[] = item.getCollections(); + for (int i = 0; i < inColl.length; ++i) + { + if (inColl[i].getID() != owningColl.getID()) + { + String h = inColl[i].getHandle(); + if (h != null) + dc.add(makeDC("relation", "isReferencedBy", "hdl:"+h)); + } + } + if (item.isWithdrawn()) + dc.add(makeDC("rights", "accessRights", "WITHDRAWN")); + } + else if (dso.getType() == Constants.BITSTREAM) + { + Bitstream bitstream = (Bitstream)dso; + String bsName = bitstream.getName(); + if (bsName != null) + dc.add(makeDC("title", null, bsName)); + String bsSource = bitstream.getSource(); + if (bsSource != null) + dc.add(makeDC("title", "alternative", bsSource)); + String bsDesc = bitstream.getDescription(); + if (bsDesc != null) + dc.add(makeDC("description", null, bsDesc)); + String bsUfmt = bitstream.getUserFormatDescription(); + if (bsUfmt != null) + dc.add(makeDC("format", null, bsUfmt)); + BitstreamFormat bsf = bitstream.getFormat(); + dc.add(makeDC("format", "medium", bsf.getShortDescription())); + dc.add(makeDC("format", "mimetype", bsf.getMIMEType())); + dc.add(makeDC("format", "supportlevel", BitstreamFormat.supportLevelText[bsf.getSupportLevel()])); + dc.add(makeDC("format", "internal", Boolean.toString(bsf.isInternal()))); + } + else if (dso.getType() == Constants.COLLECTION) + { + Collection collection = (Collection)dso; + dc.add(makeDC("identifier", "uri", "hdl:" + dso.getHandle())); + Community owners[] = collection.getCommunities(); + String ownerHdl = owners[0].getHandle(); + if (ownerHdl != null) + dc.add(makeDC("relation", "isPartOf", "hdl:" + ownerHdl)); + for (int i = 1; i < owners.length; ++i) + { + String h = owners[i].getHandle(); + if (h != null) + dc.add(makeDC("relation", "isReferencedBy", "hdl:" + h)); + } + } + else if (dso.getType() == Constants.COMMUNITY) + { + Community community = (Community)dso; + dc.add(makeDC("identifier", "uri", "hdl:" + dso.getHandle())); + Community owner = community.getParentCommunity(); + String ownerHdl = null; + if (owner == null) + ownerHdl = Site.getSiteHandle(); + else + ownerHdl = owner.getHandle(); + if (ownerHdl != null) + dc.add(makeDC("relation", "isPartOf", "hdl:" + ownerHdl)); + } + else if (dso.getType() == Constants.SITE) + { + Site site = (Site) dso; + + //FIXME: adding two URIs for now (site handle and URL), in case site isn't using handles + dc.add(makeDC("identifier", "uri", "hdl:" + site.getHandle())); + dc.add(makeDC("identifier", "uri", site.getURL())); + } + + DCValue result[] = (DCValue[])dc.toArray(new DCValue[dc.size()]); + return XSLTDisseminationCrosswalk.createDIM(dso, result); + } + + private static DCValue makeDC(String element, String qualifier, String value) + { + DCValue dcv = new DCValue(); + dcv.schema = "dc"; + dcv.language = null; + dcv.element = element; + dcv.qualifier = qualifier; + dcv.value = value; + return dcv; + } + + /** + * Ingest a whole document. Build Document object around root element, + * and feed that to the transformation, since it may get handled + * differently than a List of metadata elements. + */ + public void ingest(Context context, DSpaceObject dso, Element root) + throws CrosswalkException, IOException, SQLException, AuthorizeException + { + ingest(context, dso, root.getChildren()); + } + + /** + * Translate metadata with XSL stylesheet and ingest it. + * Translation produces a list of DIM "field" elements; + * these correspond directly to Item.addMetadata() calls so + * they are simply executed. + */ + public void ingest(Context context, DSpaceObject dso, List dimList) + throws CrosswalkException, + IOException, SQLException, AuthorizeException + { + int type = dso.getType(); + + // accumulate values for bitstream format in case we have to make one + String bsfShortName = null; + String bsfMIMEType = null; + int bsfSupport = BitstreamFormat.KNOWN; + boolean bsfInternal = false; + + Iterator di = dimList.iterator(); + while (di.hasNext()) + { + Element field = (Element)di.next(); + + // if we get in a list, recurse. + if (field.getName().equals("dim") && field.getNamespace().equals(XSLTCrosswalk.DIM_NS)) + ingest(context, dso, field.getChildren()); + else if (field.getName().equals("field") && field.getNamespace().equals(XSLTCrosswalk.DIM_NS)) + { + String schema = field.getAttributeValue("mdschema"); + if (schema.equals("dc")) + { + String dcField = field.getAttributeValue("element"); + String qualifier = field.getAttributeValue("qualifier"); + if (qualifier != null) + dcField += "."+qualifier; + String value = field.getText(); + + if (type == Constants.BITSTREAM) + { + Bitstream bitstream = (Bitstream)dso; + if (dcField.equals("title")) + { + bitstream.setName(value); + } + else if (dcField.equals("title.alternative")) + { + bitstream.setSource(value); + } + else if (dcField.equals("description")) + { + bitstream.setDescription(value); + } + else if (dcField.equals("format")) + { + bitstream.setUserFormatDescription(value); + } + else if (dcField.equals("format.medium")) + { + bsfShortName = value; + } + else if (dcField.equals("format.mimetype")) + { + bsfMIMEType = value; + } + else if (dcField.equals("format.supportlevel")) + { + int sl = BitstreamFormat.getSupportLevelID(value); + if (sl < 0) + throw new MetadataValidationException("Got unrecognized value for bitstream support level: "+value); + else + bsfSupport = sl; + } + else if (dcField.equals("format.internal")) + { + bsfInternal = (Boolean.valueOf(value)).booleanValue(); + } + else + log.warn("Got unrecognized DC field for Bitstream: "+dcField); + } + else if (type == Constants.ITEM) + { + Item item = (Item)dso; + + // item submitter + if (dcField.equals("creator")) + { + EPerson sub = EPerson.findByEmail(context, value); + + // if eperson doesn't exist yet, optionally create it: + if (sub == null) + { + //This class works in conjunction with the DSpaceAIPIngester. + // so, we'll use the configuration settings for that ingester + String configName = new DSpaceAIPIngester().getConfigurationName(); + + //Create the EPerson if specified and person doesn't already exit + if (ConfigurationManager.getBooleanProperty(METSManifest.CONFIG_METS_PREFIX + configName + ".ingest.createSubmitter")) + { + sub = EPerson.create(context); + sub.setEmail(value); + sub.setCanLogIn(false); + sub.update(); + } + else + log.warn("Ignoring unknown Submitter="+value+" in AIP Tech MD, no matching EPerson and aip.ingest.createEperson is false."); + } + if (sub != null) + item.setSubmitter(sub); + } + else if (dcField.equals("rights.accessRights")) + { + //check if item is withdrawn + if (value.equalsIgnoreCase("WITHDRAWN")) + item.withdraw(); + } + else if(dcField.equals("identifier.uri") || + dcField.equals("relation.isPartOf")) + { + // Ignore identifier.uri (which specifies object handle) + // and relation.isPartOf (which specifies primary parent object) + // Both of these should already be set on object, as they + // are required/generated when a DSpaceObject is created. + } + else if (dcField.equals("relation.isReferencedBy")) + { + // Ignore relation.isReferencedBy since it only + // lists _extra_ mapped parents, not the primary one. + // These get connected when collections are re-mapped. + } + else + log.warn("Got unrecognized DC field for Item: "+dcField); + + } + else if (type == Constants.COMMUNITY || + type == Constants.COLLECTION) + { + if (dcField.equals("identifier.uri") || + dcField.equals("relation.isPartOf")) + { + // Ignore identifier.uri (which specifies object handle) + // and relation.isPartOf (which specifies primary parent object) + // Both of these should already be set on object, as they + // are required/generated when a DSpaceObject is created. + } + else if (dcField.equals("relation.isReferencedBy")) + { + // Ignore relation.isReferencedBy since it only + // lists _extra_ mapped parents, not the primary one. + // These get connected when collections are re-mapped. + } + else + log.warn("Got unrecognized DC field for Collection/Community: "+dcField); + } + } + else + log.warn("Skipping DIM field with mdschema=\""+schema+"\"."); + + } + else + { + log.error("Got unexpected element in DIM list: "+field.toString()); + throw new MetadataValidationException("Got unexpected element in DIM list: "+field.toString()); + } + } + + // final step: find or create bitstream format since it + // takes the accumulation of a few values: + if (type == Constants.BITSTREAM && bsfShortName != null) + { + BitstreamFormat bsf = BitstreamFormat.findByShortDescription(context, bsfShortName); + if (bsf == null && bsfMIMEType != null) + bsf = PackageUtils.findOrCreateBitstreamFormat(context, + bsfShortName, + bsfMIMEType, + bsfShortName, + bsfSupport, + bsfInternal); + if (bsf != null) + ((Bitstream)dso).setFormat(bsf); + else + 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; + } +} Index: METSDisseminationCrosswalk.java =================================================================== --- METSDisseminationCrosswalk.java (.../dspace/trunk/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) +++ METSDisseminationCrosswalk.java (.../sandbox/aip-external-1_6-prototype/dspace-api/src/main/java/org/dspace/content/crosswalk) (revision 5257) @@ -38,8 +38,7 @@ package org.dspace.content.crosswalk; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; +import java.io.File; import java.io.IOException; import java.sql.SQLException; import java.util.ArrayList; @@ -52,6 +51,7 @@ import org.dspace.content.packager.PackageDisseminator; import org.dspace.content.packager.PackageException; import org.dspace.content.packager.PackageParameters; +import org.dspace.core.ConfigurationManager; import org.dspace.core.Constants; import org.dspace.core.Context; import org.dspace.core.PluginManager; @@ -60,8 +60,6 @@ import org.jdom.JDOMException; import org.jdom.Namespace; import org.jdom.input.SAXBuilder; -import org.jdom.output.Format; -import org.jdom.output.XMLOutputter; /** * METS dissemination crosswalk @@ -94,7 +92,7 @@ /** METS namespace -- includes "mets" prefix for use in XPaths */ - private static Namespace METS_NS = Namespace + private static final Namespace METS_NS = Namespace .getNamespace("mets", "http://www.loc.gov/METS/"); private static final Namespace namespaces[] = { METS_NS, MODS_NS, XLINK_NS }; @@ -105,10 +103,6 @@ private static final String schemaLocation = METS_NS.getURI()+" "+METS_XSD; - private static XMLOutputter outputUgly = new XMLOutputter(); - private static XMLOutputter outputPretty = new XMLOutputter(Format.getPrettyFormat()); - private static SAXBuilder builder = new SAXBuilder(); - public Namespace[] getNamespaces() { return namespaces; @@ -147,16 +141,19 @@ PackageParameters pparams = new PackageParameters(); pparams.put("manifestOnly", "true"); - // "pipe" the output into a parser to create JDOM document. - ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // Create a temporary file to disseminate into + String tempDirectory = ConfigurationManager.getProperty("upload.temp.dir"); + File tempFile = File.createTempFile("METSDissemination" + item.hashCode(), null, new File(tempDirectory)); + tempFile.deleteOnExit(); + + // Disseminate METS to temp file Context context = new Context(); - dip.disseminate(context, item, pparams, baos); - ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); + dip.disseminate(context, item, pparams, tempFile); try { SAXBuilder builder = new SAXBuilder(); - Document metsDocument = builder.build(bais); + Document metsDocument = builder.build(tempFile); return metsDocument.getRootElement(); } catch (JDOMException je)