[DS-2949] Use a more flexible transformer and pass parameters to the transform.

This commit is contained in:
Mark H. Wood
2015-12-13 16:41:43 -05:00
committed by Mark H. Wood
parent b6875cddaa
commit a4caeef8ff
8 changed files with 335 additions and 214 deletions

View File

@@ -0,0 +1,49 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.content.crosswalk;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Map;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject;
import org.dspace.core.Context;
import org.jdom.Element;
/**
* Translate DSpace native metadata into an external XML format, with parameters.
* This extends {@link DisseminationCrosswalk} by accepting a table of XSL-T global
* parameter names and values, which will be passed to the selected transform.
*
* @author mhwood
*/
public interface ParameterizedDisseminationCrosswalk
extends DisseminationCrosswalk
{
/**
* Execute crosswalk, returning one XML root element as
* a JDOM <code>Element</code> object.
* This is typically the root element of a document.
* <p>
*
* @param context
* @param dso the DSpace Object whose metadata to export.
* @param parameters
* names and values of parameters to be passed into the transform.
* @return root Element of the target metadata, never <code>null</code>.
*
* @throws CrosswalkInternalException (<code>CrosswalkException</code>) failure of the crosswalk itself.
* @throws CrosswalkObjectNotSupported (<code>CrosswalkException</code>) 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(Context context, DSpaceObject dso,
Map<String, String> parameters)
throws CrosswalkException, IOException, SQLException, AuthorizeException;
}

View File

@@ -8,16 +8,24 @@
package org.dspace.content.crosswalk;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stax.StAXSource;
import org.apache.log4j.Logger;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.SelfNamedPlugin;
import org.jdom.Namespace;
import org.jdom.transform.XSLTransformException;
import org.jdom.transform.XSLTransformer;
/**
* Configurable XSLT-driven Crosswalk
@@ -81,7 +89,7 @@ import org.jdom.transform.XSLTransformer;
public abstract class XSLTCrosswalk extends SelfNamedPlugin
{
/** log4j category */
private static Logger log = Logger.getLogger(XSLTCrosswalk.class);
private static final Logger log = Logger.getLogger(XSLTCrosswalk.class);
/**
* DSpace XML Namespace in JDOM form.
@@ -96,16 +104,19 @@ public abstract class XSLTCrosswalk extends SelfNamedPlugin
/**
* Derive list of plugin name from DSpace configuration entries
* for crosswalks. The <em>direction</em> parameter should be either
* "dissemination" or "submission", so it looks for keys like
* <code>crosswalk.submission.{NAME}.stylesheet</code>
* for crosswalks.
*
* @param direction
* "dissemination" or "submission", so it looks for keys like
* <code>crosswalk.submission.{NAME}.stylesheet</code>
* @return names to be given to the plugins of that direction.
*/
protected static String[] makeAliases(String direction)
{
String prefix = CONFIG_PREFIX+direction+".";
String suffix = CONFIG_STYLESHEET;
List<String> aliasList = new ArrayList<String>();
List<String> aliasList = new ArrayList<>();
Enumeration<String> pe = (Enumeration<String>)ConfigurationManager.propertyNames();
log.debug("XSLTCrosswalk: Looking for config prefix = "+prefix);
@@ -121,7 +132,7 @@ public abstract class XSLTCrosswalk extends SelfNamedPlugin
return aliasList.toArray(new String[aliasList.size()]);
}
private XSLTransformer transformer = null;
private Transformer transformer = null;
private File transformerFile = null;
private long transformerLastModified = 0;
@@ -131,7 +142,7 @@ public abstract class XSLTCrosswalk extends SelfNamedPlugin
* "dissemination"
* @return transformer or null if there was error initializing.
*/
protected XSLTransformer getTransformer(String direction)
protected Transformer getTransformer(String direction)
{
if (transformerFile == null)
{
@@ -165,10 +176,18 @@ public abstract class XSLTCrosswalk extends SelfNamedPlugin
{
log.debug((transformer == null ? "Loading " : "Reloading")+
getPluginInstanceName()+" XSLT stylesheet from "+transformerFile.toString());
transformer = new XSLTransformer(transformerFile);
Reader transformReader = new FileReader(transformerFile);
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
XMLStreamReader xsltReader
= inputFactory.createXMLStreamReader(transformReader);
TransformerFactory transformerFactory = TransformerFactory.newInstance();
transformer = transformerFactory.newTransformer(
new StAXSource(xsltReader));
transformerLastModified = transformerFile.lastModified();
}
catch (XSLTransformException e)
catch (TransformerConfigurationException | XMLStreamException | FileNotFoundException e)
{
log.error("Failed to initialize XSLTCrosswalk("+getPluginInstanceName()+"):"+e.toString());
}

View File

@@ -14,7 +14,11 @@ import java.io.OutputStream;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;
@@ -36,8 +40,8 @@ import org.jdom.Namespace;
import org.jdom.Verifier;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.transform.XSLTransformException;
import org.jdom.transform.XSLTransformer;
import org.jdom.transform.JDOMResult;
import org.jdom.transform.JDOMSource;
/**
* Configurable XSLT-driven dissemination Crosswalk
@@ -65,15 +69,14 @@ import org.jdom.transform.XSLTransformer;
* @author Larry Stone
* @author Scott Phillips
* @author Pascal-Nicolas Becker
* @version $Revision$
* @see XSLTCrosswalk
*/
public class XSLTDisseminationCrosswalk
extends XSLTCrosswalk
implements DisseminationCrosswalk
implements ParameterizedDisseminationCrosswalk
{
/** log4j category */
private static Logger log = Logger.getLogger(XSLTDisseminationCrosswalk.class);
private static final Logger log = Logger.getLogger(XSLTDisseminationCrosswalk.class);
/** DSpace context, will be created if XSLTDisseminationCrosswalk had been started by command-line. */
private static Context context;
@@ -84,7 +87,7 @@ public class XSLTDisseminationCrosswalk
protected static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
protected static final ItemService itemService = ContentServiceFactory.getInstance().getItemService();
private static String aliases[] = makeAliases(DIRECTION);
private static final String aliases[] = makeAliases(DIRECTION);
public static String[] getPluginNames()
{
@@ -137,7 +140,7 @@ public class XSLTDisseminationCrosswalk
// crosswalk.diss.{PLUGIN_NAME}.namespace.{PREFIX} = {URI}
String nsPrefix = prefix + "namespace.";
Enumeration<String> pe = (Enumeration<String>)ConfigurationManager.propertyNames();
List<Namespace> nsList = new ArrayList<Namespace>();
List<Namespace> nsList = new ArrayList<>();
while (pe.hasMoreElements())
{
String key = pe.nextElement();
@@ -190,13 +193,16 @@ public class XSLTDisseminationCrosswalk
return schemaLocation;
}
/**
* Disseminate the DSpace item, collection, or community.
*
* @see DisseminationCrosswalk
*/
@Override
public Element disseminateElement(Context context, DSpaceObject dso)
throws CrosswalkException, IOException, SQLException, AuthorizeException
{
return disseminateElement(context, dso, new HashMap());
}
@Override
public Element disseminateElement(Context context, DSpaceObject dso,
Map<String, String> parameters)
throws CrosswalkException,
IOException, SQLException, AuthorizeException
{
@@ -210,21 +216,27 @@ public class XSLTDisseminationCrosswalk
init();
XSLTransformer xform = getTransformer(DIRECTION);
Transformer xform = getTransformer(DIRECTION);
if (xform == null)
{
throw new CrosswalkInternalException("Failed to initialize transformer, probably error loading stylesheet.");
}
for (Map.Entry<String, String> parameter : parameters.entrySet())
{
xform.setParameter(parameter.getKey(), parameter.getValue());
}
try
{
Document ddim = new Document(createDIM(dso));
Document result = xform.transform(ddim);
Element root = result.getRootElement();
JDOMResult result = new JDOMResult();
xform.transform(new JDOMSource(ddim), result);
Element root = result.getDocument().getRootElement();
root.detach();
return root;
}
catch (XSLTransformException e)
catch (TransformerException e)
{
log.error("Got error: "+e.toString());
throw new CrosswalkInternalException("XSL translation failed: "+e.toString(), e);
@@ -251,7 +263,7 @@ public class XSLTDisseminationCrosswalk
init();
XSLTransformer xform = getTransformer(DIRECTION);
Transformer xform = getTransformer(DIRECTION);
if (xform == null)
{
throw new CrosswalkInternalException("Failed to initialize transformer, probably error loading stylesheet.");
@@ -259,9 +271,11 @@ public class XSLTDisseminationCrosswalk
try
{
return xform.transform(createDIM(dso).getChildren());
JDOMResult result = new JDOMResult();
xform.transform(new JDOMSource(createDIM(dso).getChildren()), result);
return result.getResult();
}
catch (XSLTransformException e)
catch (TransformerException e)
{
log.error("Got error: "+e.toString());
throw new CrosswalkInternalException("XSL translation failed: "+e.toString(), e);
@@ -525,8 +539,10 @@ public class XSLTDisseminationCrosswalk
}
}
DisseminationCrosswalk xwalk = (DisseminationCrosswalk) CoreServiceFactory.getInstance().getPluginService().getNamedPlugin(
DisseminationCrosswalk.class, xwalkname);
DisseminationCrosswalk xwalk
= (DisseminationCrosswalk) CoreServiceFactory.getInstance()
.getPluginService()
.getNamedPlugin(DisseminationCrosswalk.class, xwalkname);
if (xwalk == null)
{
System.err.println("Error: Cannot find a DisseminationCrosswalk plugin for: \"" + xwalkname + "\"");
@@ -566,7 +582,7 @@ public class XSLTDisseminationCrosswalk
{
root = xwalk.disseminateElement(context, dso);
}
catch (Exception e)
catch (CrosswalkException | IOException | SQLException | AuthorizeException e)
{
// as this script is for testing dissemination crosswalks, we want
// verbose information in case of an exception.

View File

@@ -12,6 +12,8 @@ import java.io.IOException;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.List;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;
@@ -36,8 +38,8 @@ import org.jdom.Element;
import org.jdom.input.SAXBuilder;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.transform.XSLTransformException;
import org.jdom.transform.XSLTransformer;
import org.jdom.transform.JDOMResult;
import org.jdom.transform.JDOMSource;
/**
* Configurable XSLT-driven ingestion Crosswalk
@@ -45,7 +47,6 @@ import org.jdom.transform.XSLTransformer;
* See the XSLTCrosswalk superclass for details on configuration.
*
* @author Larry Stone
* @version $Revision$
* @see XSLTCrosswalk
*/
public class XSLTIngestionCrosswalk
@@ -57,7 +58,7 @@ public class XSLTIngestionCrosswalk
private static final String DIRECTION = "submission";
private static String aliases[] = makeAliases(DIRECTION);
private static final String aliases[] = makeAliases(DIRECTION);
private static final CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
private static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
@@ -127,21 +128,23 @@ public class XSLTIngestionCrosswalk
* they are simply executed.
*/
@Override
public void ingest(Context context, DSpaceObject dso, List<Element> metadata, boolean createMissingMetadataFields)
public void ingest(Context context, DSpaceObject dso, List<Element> metadata,
boolean createMissingMetadataFields)
throws CrosswalkException,
IOException, SQLException, AuthorizeException
{
XSLTransformer xform = getTransformer(DIRECTION);
Transformer xform = getTransformer(DIRECTION);
if (xform == null)
{
throw new CrosswalkInternalException("Failed to initialize transformer, probably error loading stylesheet.");
}
try
{
List dimList = xform.transform(metadata);
ingestDIM(context, dso, dimList, createMissingMetadataFields);
JDOMResult result = new JDOMResult();
xform.transform(new JDOMSource(metadata), result);
ingestDIM(context, dso, result.getResult(), createMissingMetadataFields);
}
catch (XSLTransformException e)
catch (TransformerException e)
{
log.error("Got error: "+e.toString());
throw new CrosswalkInternalException("XSL Transformation failed: "+e.toString(), e);
@@ -157,17 +160,20 @@ public class XSLTIngestionCrosswalk
public void ingest(Context context, DSpaceObject dso, Element root, boolean createMissingMetadataFields)
throws CrosswalkException, IOException, SQLException, AuthorizeException
{
XSLTransformer xform = getTransformer(DIRECTION);
Transformer 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()));
JDOMSource source = new JDOMSource(new Document((Element)root.cloneContent()));
JDOMResult result = new JDOMResult();
xform.transform(source, result);
Document dimDoc = result.getDocument();
ingestDIM(context, dso, dimDoc.getRootElement().getChildren(), createMissingMetadataFields);
}
catch (XSLTransformException e)
catch (TransformerException e)
{
log.error("Got error: "+e.toString());
throw new CrosswalkInternalException("XSL Transformation failed: "+e.toString(), e);
@@ -295,7 +301,7 @@ public class XSLTIngestionCrosswalk
System.exit(1);
}
XSLTransformer xform = ((XSLTIngestionCrosswalk)xwalk).getTransformer(DIRECTION);
Transformer xform = ((XSLTIngestionCrosswalk)xwalk).getTransformer(DIRECTION);
if (xform == null)
{
throw new CrosswalkInternalException("Failed to initialize transformer, probably error loading stylesheet.");
@@ -304,16 +310,21 @@ public class XSLTIngestionCrosswalk
SAXBuilder builder = new SAXBuilder();
Document inDoc = builder.build(new FileInputStream(argv[i+1]));
XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat());
Document dimDoc = null;
List dimList = null;
List dimList;
if (list)
{
dimList = xform.transform(inDoc.getRootElement().getChildren());
JDOMSource source = new JDOMSource(inDoc.getRootElement().getChildren());
JDOMResult result = new JDOMResult();
xform.transform(source, result);
dimList = result.getResult();
outputter.output(dimList, System.out);
}
else
{
dimDoc = xform.transform(inDoc);
JDOMSource source = new JDOMSource(inDoc);
JDOMResult result = new JDOMResult();
xform.transform(source, result);
Document dimDoc = result.getDocument();
outputter.output(dimDoc, System.out);
dimList = dimDoc.getRootElement().getChildren();
}

View File

@@ -8,11 +8,20 @@
package org.dspace.identifier;
import java.io.IOException;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.DSpaceObject;
import org.dspace.content.crosswalk.CrosswalkException;
import org.dspace.content.crosswalk.DisseminationCrosswalk;
import org.dspace.content.crosswalk.ParameterizedDisseminationCrosswalk;
import org.dspace.core.Context;
import org.dspace.core.factory.CoreServiceFactory;
import org.dspace.services.ConfigurationService;
import org.dspace.utils.DSpace;
import org.jdom.Element;
import org.jdom.output.XMLOutputter;
@@ -25,7 +34,7 @@ import org.jdom.output.XMLOutputter;
public class DataCiteXMLCreator
{
/** log4j category */
private static Logger log = Logger.getLogger(DataCiteXMLCreator.class);
private static final Logger log = Logger.getLogger(DataCiteXMLCreator.class);
/**
* Name of crosswalk to convert metadata into DataCite Metadata Scheme.
@@ -37,7 +46,7 @@ public class DataCiteXMLCreator
* name of the crosswalk is set by {@link setDisseminationCrosswalk(String)
* setDisseminationCrosswalk} which instantiates the crosswalk.
*/
protected DisseminationCrosswalk xwalk;
protected ParameterizedDisseminationCrosswalk xwalk;
public String getXMLString(Context context, DSpaceObject dso)
{
@@ -57,12 +66,26 @@ public class DataCiteXMLCreator
return null;
}
Element root = null;
// Set the transform's parameters.
// XXX Should the actual list be configurable?
ConfigurationService cfg = new DSpace().getConfigurationService();
Map<String, String> parameters = new HashMap<>();
if (null != cfg.getProperty("identifier.doi.prefix"))
parameters.put("prefix", cfg.getProperty("identifier.doi.prefix"));
if (null != cfg.getProperty("crosswalk.dissemination.DataCite.publisher"))
parameters.put("publisher", cfg.getProperty("crosswalk.dissemination.DataCite.publisher"));
if (null != cfg.getProperty("crosswalk.dissemination.DataCite.dataManager"))
parameters.put("datamanager", cfg.getProperty("crosswalk.dissemination.DataCite.dataManager"));
if (null != cfg.getProperty("crosswalk.dissemination.DataCite.hostingInstitution"))
parameters.put("hostinginstitution", cfg.getProperty("crosswalk.dissemination.DataCite.hostingInstitution"));
// Transform the metadata
Element root;
try
{
root = xwalk.disseminateElement(context, dso);
root = xwalk.disseminateElement(context, dso, parameters);
}
catch (Exception e)
catch (CrosswalkException | IOException | SQLException | AuthorizeException e)
{
log.error(
"Exception while crosswolking DSO " + "with type "
@@ -73,7 +96,6 @@ public class DataCiteXMLCreator
XMLOutputter xOut = new XMLOutputter();
return xOut.outputString(root);
}
/**
@@ -93,8 +115,9 @@ public class DataCiteXMLCreator
if (null != this.xwalk)
return;
this.xwalk = (DisseminationCrosswalk) CoreServiceFactory.getInstance().getPluginService().getNamedPlugin(
DisseminationCrosswalk.class, this.CROSSWALK_NAME);
this.xwalk = (ParameterizedDisseminationCrosswalk) CoreServiceFactory
.getInstance().getPluginService()
.getNamedPlugin(DisseminationCrosswalk.class, this.CROSSWALK_NAME);
if (this.xwalk == null)
{

View File

@@ -15,11 +15,11 @@
<!-- CONFIGURATION -->
<!-- The content of the following variable will be used as element publisher. -->
<xsl:variable name="publisher">My University</xsl:variable>
<xsl:param name="publisher">My University</xsl:param>
<!-- The content of the following variable will be used as element contributor with contributorType datamanager. -->
<xsl:variable name="datamanager"><xsl:value-of select="$publisher" /></xsl:variable>
<xsl:param name="datamanager"><xsl:value-of select="$publisher" /></xsl:param>
<!-- The content of the following variable will be used as element contributor with contributorType hostingInstitution. -->
<xsl:variable name="hostinginstitution"><xsl:value-of select="$publisher" /></xsl:variable>
<xsl:param name="hostinginstitution"><xsl:value-of select="$publisher" /></xsl:param>
<!-- Please take a look into the DataCite schema documentation if you want to know how to use these elements.
http://schema.datacite.org -->

View File

@@ -14,11 +14,11 @@
<!-- CONFIGURATION -->
<!-- The content of the following variable will be used as element publisher. -->
<xsl:variable name="publisher">My University</xsl:variable>
<xsl:param name="publisher">My University</xsl:param>
<!-- The content of the following variable will be used as element contributor with contributorType datamanager. -->
<xsl:variable name="datamanager"><xsl:value-of select="$publisher" /></xsl:variable>
<xsl:param name="datamanager"><xsl:value-of select="$publisher" /></xsl:param>
<!-- The content of the following variable will be used as element contributor with contributorType hostingInstitution. -->
<xsl:variable name="hostinginstitution"><xsl:value-of select="$publisher" /></xsl:variable>
<xsl:param name="hostinginstitution"><xsl:value-of select="$publisher" /></xsl:param>
<!-- Please take a look into the DataCite schema documentation if you want to know how to use these elements.
http://schema.datacite.org -->

View File

@@ -475,6 +475,9 @@ crosswalk.dissemination.DataCite.schemaLocation = \
http://datacite.org/schema/kernel-2.2 \
http://schema.datacite.org/meta/kernel-2.2/metadata.xsd
crosswalk.dissemination.DataCite.preferList = false
crosswalk.dissemination.DataCite.publisher = My University
#crosswalk.dissemination.DataCite.dataManager = # defaults to publisher
#crosswalk.dissemination.DataCite.hostingInstitution = # defaults to publisher
# Crosswalk Plugin Configuration:
# The purpose of Crosswalks is to translate an external metadata format to/from