All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.dspace.content.crosswalk.XSLTDisseminationCrosswalk Maven / Gradle / Ivy

There is a newer version: 8.0
Show newest version
/**
 * 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.CharArrayWriter;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.ArrayList;
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.lang3.ArrayUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.MetadataValue;
import org.dspace.content.Site;
import org.dspace.content.authority.Choices;
import org.dspace.content.dto.MetadataValueDTO;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.content.service.ItemService;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.factory.CoreServiceFactory;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.services.ConfigurationService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.Namespace;
import org.jdom.Verifier;
import org.jdom.output.Format;
import org.jdom.output.XMLOutputter;
import org.jdom.transform.JDOMResult;
import org.jdom.transform.JDOMSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Configurable XSLT-driven dissemination Crosswalk
 * 

* See the XSLTCrosswalk superclass for details on configuration. *

*

Additional Configuration of Dissemination crosswalk:

* The disseminator also needs to be configured with an XML Namespace * (including prefix and URI) and an XML Schema for output format. This * is configured on additional properties in the DSpace Configuration, i.e.: *
 *   crosswalk.dissemination.PluginName.namespace.Prefix = namespace-URI
 *   crosswalk.dissemination.PluginName.schemaLocation = schemaLocation value
 *   crosswalk.dissemination.PluginName.preferList = boolean (default is false)
 * 
* For example: *
 *   crosswalk.dissemination.qdc.namespace.dc = http://purl.org/dc/elements/1.1/
 *   crosswalk.dissemination.qdc.namespace.dcterms = http://purl.org/dc/terms/
 *   crosswalk.dissemination.qdc.schemaLocation = \
 *      http://purl.org/dc/elements/1.1/ http://dublincore.org/schemas/xmls/qdc/2003/04/02/qualifieddc.xsd
 *   crosswalk.dissemination.qdc.preferList = true
 * 
* * @author Larry Stone * @author Scott Phillips * @author Pascal-Nicolas Becker * @see XSLTCrosswalk */ public class XSLTDisseminationCrosswalk extends XSLTCrosswalk implements ParameterizedDisseminationCrosswalk { /** * log4j category */ private static final Logger LOG = LoggerFactory.getLogger(XSLTDisseminationCrosswalk.class); /** * DSpace context, will be created if XSLTDisseminationCrosswalk had been started by command-line. */ private static Context context; private static final String DIRECTION = "dissemination"; protected static final CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); protected static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected static final ItemService itemService = ContentServiceFactory.getInstance().getItemService(); protected static final ConfigurationService configurationService = DSpaceServicesFactory.getInstance().getConfigurationService(); private static final String aliases[] = makeAliases(DIRECTION); public static String[] getPluginNames() { return (String[]) ArrayUtils.clone(aliases); } // namespace and schema; don't worry about initializing these // until there's an instance, so do it in constructor. private String schemaLocation = null; private Namespace namespaces[] = null; private boolean preferList = false; // load the namespace and schema from config private void init() throws CrosswalkInternalException { if (namespaces != null || schemaLocation != null) { return; } String myAlias = getPluginInstanceName(); if (myAlias == null) { LOG.error("Must use PluginService to instantiate XSLTDisseminationCrosswalk so the class knows its name."); throw new CrosswalkInternalException( "Must use PluginService to instantiate XSLTDisseminationCrosswalk so the class knows its name."); } // all configs for this plugin instance start with this: String prefix = CONFIG_PREFIX + DIRECTION + "." + myAlias + "."; // get the schema location string, should already be in the // right format for value of "schemaLocation" attribute. schemaLocation = configurationService.getProperty(prefix + "schemaLocation"); if (schemaLocation == null) { LOG.warn("No schemaLocation for crosswalk=" + myAlias + ", key=" + prefix + "schemaLocation"); } else if (schemaLocation.length() > 0 && schemaLocation.indexOf(' ') < 0) { // sanity check: schemaLocation should have space. LOG.warn("Possible INVALID schemaLocation (no space found) for crosswalk=" + myAlias + ", key=" + prefix + "schemaLocation" + "\n\tCorrect format is \"{namespace} {schema-URL}\""); } // grovel for namespaces of the form: // crosswalk.diss.{PLUGIN_NAME}.namespace.{PREFIX} = {URI} String nsPrefix = prefix + "namespace."; List configKeys = configurationService.getPropertyKeys(nsPrefix); List nsList = new ArrayList<>(); for (String key : configKeys) { nsList.add(Namespace.getNamespace(key.substring(nsPrefix.length()), configurationService.getProperty(key))); } namespaces = nsList.toArray(new Namespace[nsList.size()]); preferList = configurationService.getBooleanProperty(prefix + "preferList", false); } /** * Return the namespace used by this crosswalk. * * @see DisseminationCrosswalk */ @Override public Namespace[] getNamespaces() { try { init(); } catch (CrosswalkInternalException e) { LOG.error(e.toString()); } return (Namespace[]) ArrayUtils.clone(namespaces); } /** * Return the schema location used by this crosswalk. * * @see DisseminationCrosswalk */ @Override public String getSchemaLocation() { try { init(); } catch (CrosswalkInternalException e) { LOG.error(e.toString()); } return schemaLocation; } @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 parameters) 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(); Transformer xform = getTransformer(DIRECTION); if (xform == null) { throw new CrosswalkInternalException( "Failed to initialize transformer, probably error loading stylesheet."); } for (Map.Entry parameter : parameters.entrySet()) { LOG.debug("Setting parameter {} to {}", parameter.getKey(), parameter.getValue()); xform.setParameter(parameter.getKey(), parameter.getValue()); } try { Document ddim = new Document(createDIM(dso)); JDOMResult result = new JDOMResult(); xform.transform(new JDOMSource(ddim), result); Element root = result.getDocument().getRootElement(); root.detach(); return root; } catch (TransformerException e) { LOG.error("Got error: " + e.toString()); throw new CrosswalkInternalException("XSL translation failed: " + e.toString(), e); } } /** * Disseminate the DSpace item, collection, or community. * * @param context context * @throws CrosswalkException crosswalk error * @throws IOException if IO error * @throws SQLException if database error * @throws AuthorizeException if authorization error * @see DisseminationCrosswalk */ @Override public List disseminateList(Context context, 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(); Transformer xform = getTransformer(DIRECTION); if (xform == null) { throw new CrosswalkInternalException( "Failed to initialize transformer, probably error loading stylesheet."); } try { JDOMResult result = new JDOMResult(); xform.transform(new JDOMSource(createDIM(dso).getChildren()), result); return result.getResult(); } catch (TransformerException e) { LOG.error("Got error: " + e.toString()); throw new CrosswalkInternalException("XSL translation failed: " + e.toString(), e); } } /** * Determine is this crosswalk can dessiminate the given object. * * @see DisseminationCrosswalk */ @Override public boolean canDisseminate(DSpaceObject dso) { return dso.getType() == Constants.ITEM; } /** * return true if this crosswalk prefers the list form over an single * element, otherwise false. * * @see DisseminationCrosswalk */ @Override public boolean preferList() { 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. * @param dcvs list of metadata * @return element */ public static Element createDIM(DSpaceObject dso, List dcvs) { Element dim = new Element("dim", DIM_NS); String type = Constants.typeText[dso.getType()]; dim.setAttribute("dspaceType", type); for (int i = 0; i < dcvs.size(); i++) { MetadataValueDTO dcv = dcvs.get(i); Element field = createField(dcv.getSchema(), dcv.getElement(), dcv.getQualifier(), dcv.getLanguage(), dcv.getValue(), dcv.getAuthority(), dcv.getConfidence()); dim.addContent(field); } return dim; } /** * Generate an intermediate representation of a DSpace object. * * @param dso The dspace object to build a representation of. * @return element */ public static Element createDIM(DSpaceObject dso) { if (dso.getType() == Constants.ITEM) { Item item = (Item) dso; return createDIM(dso, item2Metadata(item)); } 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 = collectionService.getMetadataFirstValue(collection, CollectionService.MD_INTRODUCTORY_TEXT, Item.ANY); String description_abstract = collectionService.getMetadataFirstValue(collection, CollectionService.MD_SHORT_DESCRIPTION, Item.ANY); String description_table = collectionService.getMetadataFirstValue(collection, CollectionService.MD_SIDEBAR_TEXT, Item.ANY); String identifier_uri = "hdl:" + collection.getHandle(); String provenance = collectionService.getMetadataFirstValue(collection, CollectionService.MD_PROVENANCE_DESCRIPTION, Item.ANY); String rights = collectionService.getMetadataFirstValue(collection, CollectionService.MD_COPYRIGHT_TEXT, Item.ANY); String rights_license = collectionService.getMetadataFirstValue(collection, CollectionService.MD_LICENSE, Item.ANY); String title = collectionService.getMetadataFirstValue(collection, CollectionService.MD_NAME, Item.ANY); 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 = communityService.getMetadataFirstValue(community, CommunityService.MD_INTRODUCTORY_TEXT, Item.ANY); String description_abstract = communityService.getMetadataFirstValue(community, CommunityService.MD_SHORT_DESCRIPTION, Item.ANY); String description_table = communityService.getMetadataFirstValue(community, CommunityService.MD_SIDEBAR_TEXT, Item.ANY); String identifier_uri = "hdl:" + community.getHandle(); String rights = communityService.getMetadataFirstValue(community, CommunityService.MD_COPYRIGHT_TEXT, Item.ANY); String title = communityService.getMetadataFirstValue(community, CommunityService.MD_NAME, Item.ANY); 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; } } protected static List item2Metadata(Item item) { List dcvs = itemService.getMetadata(item, Item.ANY, Item.ANY, Item.ANY, Item.ANY); List result = new ArrayList<>(); for (MetadataValue metadataValue : dcvs) { result.add(new MetadataValueDTO(metadataValue)); } return result; } /** * Create a new DIM field element with the given attributes. * * @param schema The schema the DIM field belongs to. * @param element The element the DIM field belongs to. * @param qualifier The qualifier the DIM field belongs to. * @param language The language the DIM field belongs to. * @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) { 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 to. * @param element The element the DIM field belongs to. * @param qualifier The qualifier the DIM field belongs to. * @param language The language the DIM field belongs to. * @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) { field.setAttribute("authority", authority); field.setAttribute("confidence", Choices.getConfidenceText(confidence)); } 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 { if (LOG.isDebugEnabled()) { LOG.debug("Filtering out non-XML characters in string, reason=" + reason); } StringBuilder result = new StringBuilder(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(); } } /** * Simple command-line rig for testing the DIM output of a stylesheet. * Usage: {@code java XSLTDisseminationCrosswalk [output-file]} * * @param argv the command line arguments given * @throws Exception if error */ public static void main(String[] argv) throws Exception { LOG.error("started."); if (argv.length < 2 || argv.length > 3) { System.err.println("Usage: java XSLTDisseminationCrosswalk [output-file]"); LOG.error("You started Dissemination Crosswalk Test/Export with a wrong number of parameters."); System.exit(1); } String xwalkname = argv[0]; String handle = argv[1]; OutputStream out = System.out; if (argv.length > 2) { try { out = new FileOutputStream(argv[2]); } catch (FileNotFoundException e) { System.err.format("Can't write to the specified file: %s%n", e.getMessage()); System.err.println("Will write output to stdout."); } } DisseminationCrosswalk xwalk = (DisseminationCrosswalk) CoreServiceFactory.getInstance() .getPluginService() .getNamedPlugin(DisseminationCrosswalk.class, xwalkname); if (xwalk == null) { System.err.format("Error: Cannot find a DisseminationCrosswalk plugin for: \"%s\"%n", xwalkname); LOG.error("Cannot find the Dissemination Crosswalk plugin."); System.exit(1); } context = new Context(); context.turnOffAuthorisationSystem(); DSpaceObject dso = null; try { dso = HandleServiceFactory.getInstance().getHandleService().resolveToObject(context, handle); } catch (SQLException e) { System.err .println("Error: A problem with the database connection occurred, check logs for further information."); System.exit(1); } if (null == dso) { System.err.format("Can't find a DSpaceObject with the handle \"%s\"%n", handle); System.exit(1); } if (!xwalk.canDisseminate(dso)) { System.err.println("Dissemination Crosswalk can't disseminate this DSpaceObject."); LOG.error("Dissemination Crosswalk can't disseminate this DSpaceObject."); System.exit(1); } Element root = null; try { root = xwalk.disseminateElement(context, dso); } catch (CrosswalkException | IOException | SQLException | AuthorizeException e) { // as this script is for testing dissemination crosswalks, we want // verbose information in case of an exception. System.err.println("An error occurred while processing the dissemination crosswalk."); System.err.println("=== Error Message ==="); System.err.println(e.getMessage()); System.err.println("=== Stack Trace ==="); e.printStackTrace(System.err); System.err.println("====================="); LOG.error("Caught: {}.", e.toString()); LOG.error(e.getMessage()); CharArrayWriter traceWriter = new CharArrayWriter(2048); e.printStackTrace(new PrintWriter(traceWriter)); LOG.error(traceWriter.toString()); System.exit(1); } try { XMLOutputter xmlout = new XMLOutputter(Format.getPrettyFormat()); xmlout.output(new Document(root), out); } catch (IOException e) { // as this script is for testing dissemination crosswalks, we want // verbose information in case of an exception. System.err.println("An error occurred after processing the dissemination crosswalk."); System.err.println("The error occurred while trying to print the generated XML."); System.err.println("=== Error Message ==="); System.err.println(e.getMessage()); System.err.println("=== Stack Trace ==="); e.printStackTrace(System.err); System.err.println("====================="); LOG.error("Caught: {}.", e.toString()); LOG.error(e.getMessage()); CharArrayWriter traceWriter = new CharArrayWriter(2048); e.printStackTrace(new PrintWriter(traceWriter)); LOG.error(traceWriter.toString()); System.exit(1); } context.complete(); if (out instanceof FileOutputStream) { out.close(); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy