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

org.dspace.administer.StructBuilder Maven / Gradle / Ivy

The 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.administer;

import static org.dspace.content.service.DSpaceObjectService.MD_COPYRIGHT_TEXT;
import static org.dspace.content.service.DSpaceObjectService.MD_INTRODUCTORY_TEXT;
import static org.dspace.content.service.DSpaceObjectService.MD_LICENSE;
import static org.dspace.content.service.DSpaceObjectService.MD_NAME;
import static org.dspace.content.service.DSpaceObjectService.MD_PROVENANCE_DESCRIPTION;
import static org.dspace.content.service.DSpaceObjectService.MD_SHORT_DESCRIPTION;
import static org.dspace.content.service.DSpaceObjectService.MD_SIDEBAR_TEXT;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.StringUtils;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.MetadataFieldName;
import org.dspace.content.MetadataSchemaEnum;
import org.dspace.content.MetadataValue;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.core.Context;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService;
import org.dspace.handle.factory.HandleServiceFactory;
import org.dspace.handle.service.HandleService;
import org.jdom2.Element;
import org.jdom2.output.Format;
import org.jdom2.output.XMLOutputter;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

/**
 * This class deals with importing community and collection structures from
 * an XML file.
 *
 * The XML file structure needs to be:
 * 
{@code
 * 
 *   
 *     ....
 *     ...
 *     
 *       ....
 *     
 *   
 * 
 * }
* *

* It can be arbitrarily deep, and supports all the metadata elements * that make up the community and collection metadata. See the system * documentation for more details. * * @author Richard Jones */ public class StructBuilder { /** Name of the root element for the document to be imported. */ static final String INPUT_ROOT = "import_structure"; /* * Name of the root element for the document produced by importing. * Community and collection elements are annotated with their identifiers. */ static final String RESULT_ROOT = "imported_structure"; /** * A table to hold metadata for the collection being worked on. */ private static final Map collectionMap = new HashMap<>(); /** * A table to hold metadata for the community being worked on. */ private static final Map communityMap = new HashMap<>(); protected static final CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService(); protected static final CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService(); protected static final EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService(); protected static final HandleService handleService = HandleServiceFactory.getInstance().getHandleService(); /** * Default constructor */ private StructBuilder() { } /** * Main method to be run from the command line to import a structure into * DSpacee or export existing structure to a file.The command is of the form: * *

{@code StructBuilder -f [XML source] -e [administrator email] -o [output file]} * *

to import, or * *

{@code StructBuilder -x -e [administrator email] -o [output file]}

* *

to export. The output will contain exactly the same as the source XML * document, but with the Handle for each imported item added as an attribute. * * * @param argv command line arguments. * @throws ParserConfigurationException passed through. * @throws SQLException passed through. * @throws FileNotFoundException if input or output could not be opened. * @throws TransformerException if the input document is invalid. * @throws XPathExpressionException passed through. */ public static void main(String[] argv) throws ParserConfigurationException, SQLException, IOException, TransformerException, XPathExpressionException { // Define command line options. Options options = new Options(); options.addOption("h", "help", false, "Print this help message."); options.addOption("?", "help"); options.addOption("x", "export", false, "Export the current structure as XML."); options.addOption("k", "keep-handles", false, "Apply Handles from input document."); options.addOption(Option.builder("e").longOpt("eperson") .desc("User who is manipulating the repository's structure.") .hasArg().argName("eperson").required().build()); options.addOption(Option.builder("f").longOpt("file") .desc("File of new structure information.") .hasArg().argName("input").build()); options.addOption(Option.builder("o").longOpt("output") .desc("File to receive the structure map ('-' for standard out).") .hasArg().argName("output").required().build()); // Parse the command line. CommandLineParser parser = new DefaultParser(); CommandLine line = null; try { line = parser.parse(options, argv); } catch (ParseException ex) { System.err.println(ex.getMessage()); usage(options); System.exit(1); } // If the user asked for help, give it and exit. if (line.hasOption('h') || line.hasOption('?')) { giveHelp(options); System.exit(0); } // Otherwise, analyze the command. // Must be import or export. if (!(line.hasOption('f') || line.hasOption('x'))) { giveHelp(options); System.exit(1); } // Open the output stream. String output = line.getOptionValue('o'); OutputStream outputStream; if ("-".equals(output)) { outputStream = System.out; } else { outputStream = new FileOutputStream(output); } // create a context Context context = new Context(); // set the context. String eperson = line.getOptionValue('e'); try { context.setCurrentUser(ePersonService.findByEmail(context, eperson)); } catch (SQLException ex) { System.err.format("That user could not be found: %s%n", ex.getMessage()); System.exit(1); } // Export? Import? if (line.hasOption('x')) { // export exportStructure(context, outputStream); outputStream.close(); } else { // Must be import String input = line.getOptionValue('f'); if (null == input) { usage(options); System.exit(1); } InputStream inputStream; if ("-".equals(input)) { inputStream = System.in; } else { inputStream = new FileInputStream(input); } boolean keepHandles = options.hasOption("k"); importStructure(context, inputStream, outputStream, keepHandles); inputStream.close(); outputStream.close(); // save changes from import context.complete(); } System.exit(0); } /** * Import new Community/Collection structure. * * @param context * @param input XML which describes the new communities and collections. * @param output input, annotated with the new objects' identifiers. * @param keepHandles true if Handles should be set from input. * @throws IOException * @throws ParserConfigurationException * @throws SAXException * @throws TransformerException * @throws SQLException */ static void importStructure(Context context, InputStream input, OutputStream output, boolean keepHandles) throws IOException, ParserConfigurationException, SQLException, TransformerException, XPathExpressionException { // load the XML Document document = null; try { document = loadXML(input); } catch (IOException ex) { System.err.format("The input document could not be read: %s%n", ex.getMessage()); System.exit(1); } catch (SAXException ex) { System.err.format("The input document could not be parsed: %s%n", ex.getMessage()); System.exit(1); } // run the preliminary validation, to be sure that the the XML document // is properly structured. try { validate(document); } catch (XPathExpressionException ex) { System.err.format("The input document is invalid: %s%n", ex.getMessage()); System.exit(1); } // Check for 'identifier' attributes -- possibly output by this class. XPath xPath = XPathFactory.newInstance().newXPath(); NodeList identifierNodes = (NodeList) xPath.compile("//*[@identifier]") .evaluate(document, XPathConstants.NODESET); if (identifierNodes.getLength() > 0) { if (!keepHandles) { System.err.println("The input document has 'identifier' attributes, which will be ignored."); } else { for (int i = 0; i < identifierNodes.getLength() ; i++) { String identifier = identifierNodes.item(i).getAttributes().item(0).getTextContent(); if (handleService.resolveToURL(context, identifier) != null) { System.err.printf("The input document contains handle %s," + " which is in use already. Aborting...%n", identifier); System.exit(1); } } } } // load the mappings into the member variable hashmaps communityMap.put("name", MD_NAME); communityMap.put("description", MD_SHORT_DESCRIPTION); communityMap.put("intro", MD_INTRODUCTORY_TEXT); communityMap.put("copyright", MD_COPYRIGHT_TEXT); communityMap.put("sidebar", MD_SIDEBAR_TEXT); collectionMap.put("name", MD_NAME); collectionMap.put("description", MD_SHORT_DESCRIPTION); collectionMap.put("intro", MD_INTRODUCTORY_TEXT); collectionMap.put("copyright", MD_COPYRIGHT_TEXT); collectionMap.put("sidebar", MD_SIDEBAR_TEXT); collectionMap.put("license", MD_LICENSE); collectionMap.put("provenance", MD_PROVENANCE_DESCRIPTION); Element[] elements = new Element[]{}; try { // get the top level community list NodeList first = (NodeList) xPath.compile("/import_structure/community") .evaluate(document, XPathConstants.NODESET); // run the import starting with the top level communities elements = handleCommunities(context, first, null, keepHandles); } catch (TransformerException ex) { System.err.format("Input content not understood: %s%n", ex.getMessage()); System.exit(1); } catch (AuthorizeException ex) { System.err.format("Not authorized: %s%n", ex.getMessage()); System.exit(1); } // generate the output final Element root = new Element(RESULT_ROOT); for (Element element : elements) { root.addContent(element); } // finally write the string into the output file. final org.jdom2.Document xmlOutput = new org.jdom2.Document(root); try { new XMLOutputter().output(xmlOutput, output); } catch (IOException e) { System.out.printf("Unable to write to output file %s: %s%n", output, e.getMessage()); System.exit(1); } } /** * Add a single community, and its children, to the Document. * * @param community * @return a fragment representing this Community. */ private static Element exportACommunity(Community community) { // Export this Community. Element element = new Element("community"); element.setAttribute("identifier", community.getHandle()); element.addContent(new Element("name").setText(community.getName())); element.addContent(new Element("description") .setText(communityService.getMetadataFirstValue(community, MetadataSchemaEnum.DC.getName(), "description", "abstract", Item.ANY))); element.addContent(new Element("intro") .setText(communityService.getMetadataFirstValue(community, MetadataSchemaEnum.DC.getName(), "description", null, Item.ANY))); element.addContent(new Element("copyright") .setText(communityService.getMetadataFirstValue(community, MetadataSchemaEnum.DC.getName(), "rights", null, Item.ANY))); element.addContent(new Element("sidebar") .setText(communityService.getMetadataFirstValue(community, MetadataSchemaEnum.DC.getName(), "description", "tableofcontents", Item.ANY))); // Export this Community's Community children. for (Community subCommunity : community.getSubcommunities()) { element.addContent(exportACommunity(subCommunity)); } // Export this Community's Collection children. for (Collection collection : community.getCollections()) { element.addContent(exportACollection(collection)); } return element; } /** * Add a single Collection to the Document. * * @param collection * @return a fragment representing this Collection. */ private static Element exportACollection(Collection collection) { // Export this Collection. Element element = new Element("collection"); element.setAttribute("identifier", collection.getHandle()); element.addContent(new Element("name").setText(collection.getName())); element.addContent(new Element("description") .setText(collectionService.getMetadataFirstValue(collection, MetadataSchemaEnum.DC.getName(), "description", "abstract", Item.ANY))); element.addContent(new Element("intro") .setText(collectionService.getMetadataFirstValue(collection, MetadataSchemaEnum.DC.getName(), "description", null, Item.ANY))); element.addContent(new Element("copyright") .setText(collectionService.getMetadataFirstValue(collection, MetadataSchemaEnum.DC.getName(), "rights", null, Item.ANY))); element.addContent(new Element("sidebar") .setText(collectionService.getMetadataFirstValue(collection, MetadataSchemaEnum.DC.getName(), "description", "tableofcontents", Item.ANY))); element.addContent(new Element("license") .setText(collectionService.getMetadataFirstValue(collection, MetadataSchemaEnum.DC.getName(), "rights", "license", Item.ANY))); // Provenance is special: multivalued for (MetadataValue value : collectionService.getMetadata(collection, MetadataSchemaEnum.DC.getName(), "provenance", null, Item.ANY)) { element.addContent(new Element("provenance") .setText(value.getValue())); } return element; } /** * Write out the existing Community/Collection structure. */ static void exportStructure(Context context, OutputStream output) { // Build a document from the Community/Collection hierarchy. Element rootElement = new Element(INPUT_ROOT); // To be read by importStructure, perhaps List communities = null; try { communities = communityService.findAllTop(context); } catch (SQLException ex) { System.out.printf("Unable to get the list of top-level communities: %s%n", ex.getMessage()); System.exit(1); } for (Community community : communities) { rootElement.addContent(exportACommunity(community)); } // Now write the structure out. org.jdom2.Document xmlOutput = new org.jdom2.Document(rootElement); try { XMLOutputter outputter = new XMLOutputter(Format.getPrettyFormat()); outputter.output(xmlOutput, output); } catch (IOException e) { System.out.printf("Unable to write to output file %s: %s%n", output, e.getMessage()); System.exit(1); } } /** * Output the usage information. */ private static void usage(Options options) { HelpFormatter helper = new HelpFormatter(); try (PrintWriter writer = new PrintWriter(System.out);) { helper.printUsage(writer, 80/* FIXME Magic */, "structure-builder", options); } } /** * Help the user more. */ private static void giveHelp(Options options) { HelpFormatter formatter = new HelpFormatter(); formatter.printHelp("struct-builder", "Import or export Community/Collection structure.", options, "When importing (-f), communities will be created from the " + "top level, and a map of communities to handles will " + "be returned in the output file. When exporting (-x)," + "the current structure will be written to the map file.", true); } /** * Validate the XML document. This method returns if the document is valid. * If validation fails it generates an error and ceases execution. * * @param document the XML document object * @throws TransformerException if transformer error */ private static void validate(org.w3c.dom.Document document) throws XPathExpressionException { StringBuilder err = new StringBuilder(); boolean trip = false; err.append("The following errors were encountered parsing the source XML.\n"); err.append("No changes have been made to the DSpace instance.\n\n"); XPath xPath = XPathFactory.newInstance().newXPath(); NodeList first = (NodeList) xPath.compile("/import_structure/community") .evaluate(document, XPathConstants.NODESET); if (first.getLength() == 0) { err.append("-There are no top level communities in the source document."); System.out.println(err.toString()); System.exit(1); } String errs = validateCommunities(first, 1); if (errs != null) { err.append(errs); trip = true; } if (trip) { System.out.println(err.toString()); System.exit(1); } } /** * Validate the communities section of the XML document. This returns a string * containing any errors encountered, or null if there were no errors. * * @param communities the NodeList of communities to validate * @param level the level in the XML document that we are at, for the purposes * of error reporting * @return the errors that need to be generated by the calling method, or null if * no errors. */ private static String validateCommunities(NodeList communities, int level) throws XPathExpressionException { StringBuilder err = new StringBuilder(); boolean trip = false; String errs = null; XPath xPath = XPathFactory.newInstance().newXPath(); for (int i = 0; i < communities.getLength(); i++) { Node n = communities.item(i); NodeList name = (NodeList) xPath.compile("name").evaluate(n, XPathConstants.NODESET); if (name.getLength() != 1) { String pos = Integer.toString(i + 1); err.append("-The level ").append(level) .append(" community in position ").append(pos) .append(" does not contain exactly one name field.\n"); trip = true; } // validate sub communities NodeList subCommunities = (NodeList) xPath.compile("community").evaluate(n, XPathConstants.NODESET); String comErrs = validateCommunities(subCommunities, level + 1); if (comErrs != null) { err.append(comErrs); trip = true; } // validate collections NodeList collections = (NodeList) xPath.compile("collection").evaluate(n, XPathConstants.NODESET); String colErrs = validateCollections(collections, level + 1); if (colErrs != null) { err.append(colErrs); trip = true; } } if (trip) { errs = err.toString(); } return errs; } /** * validate the collection section of the XML document. This generates a * string containing any errors encountered, or returns null if no errors. * * @param collections a NodeList of collections to validate * @param level the level in the XML document for the purposes of error reporting * @return the errors to be generated by the calling method, or null if none */ private static String validateCollections(NodeList collections, int level) throws XPathExpressionException { StringBuilder err = new StringBuilder(); boolean trip = false; String errs = null; XPath xPath = XPathFactory.newInstance().newXPath(); for (int i = 0; i < collections.getLength(); i++) { Node n = collections.item(i); NodeList name = (NodeList) xPath.compile("name").evaluate(n, XPathConstants.NODESET); if (name.getLength() != 1) { String pos = Integer.toString(i + 1); err.append("-The level ").append(level) .append(" collection in position ").append(pos) .append(" does not contain exactly one name field.\n"); trip = true; } } if (trip) { errs = err.toString(); } return errs; } /** * Load the XML document from input. * * @param input the filename to load from. * @return the DOM representation of the XML input. */ private static org.w3c.dom.Document loadXML(InputStream input) throws IOException, ParserConfigurationException, SAXException { DocumentBuilder builder = DocumentBuilderFactory.newInstance() .newDocumentBuilder(); org.w3c.dom.Document document = builder.parse(input); return document; } /** * Return the String value of a Node * * @param node the node from which we want to extract the string value * @return the string value of the node */ private static String getStringValue(Node node) { String value = node.getNodeValue(); if (node.hasChildNodes()) { Node first = node.getFirstChild(); if (first.getNodeType() == Node.TEXT_NODE) { return first.getNodeValue().trim(); } } return value; } /** * Take a node list of communities and build the structure from them, delegating * to the relevant methods in this class for sub-communities and collections * * @param context the context of the request * @param communities a nodelist of communities to create along with their sub-structures * @param parent the parent community of the nodelist of communities to create * @param keepHandles use Handles from input. * @return an element array containing additional information regarding the * created communities (e.g. the handles they have been assigned) */ private static Element[] handleCommunities(Context context, NodeList communities, Community parent, boolean keepHandles) throws TransformerException, SQLException, AuthorizeException, XPathExpressionException { Element[] elements = new Element[communities.getLength()]; XPath xPath = XPathFactory.newInstance().newXPath(); for (int i = 0; i < communities.getLength(); i++) { Node tn = communities.item(i); Node identifier = tn.getAttributes().getNamedItem("identifier"); // create the community or sub community Community community; if (null == identifier || StringUtils.isBlank(identifier.getNodeValue()) || !keepHandles) { community = communityService.create(parent, context); } else { community = communityService.create(parent, context, identifier.getNodeValue()); } // default the short description to be an empty string communityService.setMetadataSingleValue(context, community, MD_SHORT_DESCRIPTION, null, " "); // now update the metadata for (Map.Entry entry : communityMap.entrySet()) { NodeList nl = (NodeList) xPath.compile(entry.getKey()).evaluate(tn, XPathConstants.NODESET); if (nl.getLength() == 1) { communityService.setMetadataSingleValue(context, community, entry.getValue(), null, getStringValue(nl.item(0))); } } // FIXME: at the moment, if the community already exists by name // then this will throw an SQLException on a duplicate key // violation. // Ideally we'd skip this row and continue to create sub communities // and so forth where they don't exist, but it's proving difficult // to isolate the community that already exists without hitting // the database directly. communityService.update(context, community); // build the element with the handle that identifies the new // community // along with all the information that we imported here // This looks like a lot of repetition of getting information // from above // but it's here to keep it separate from the create process in // case // we want to move it or make it switchable later Element element = new Element("community"); element.setAttribute("identifier", community.getHandle()); Element nameElement = new Element("name"); nameElement.setText(communityService.getMetadataFirstValue( community, CommunityService.MD_NAME, Item.ANY)); element.addContent(nameElement); String fieldValue; fieldValue = communityService.getMetadataFirstValue(community, CommunityService.MD_SHORT_DESCRIPTION, Item.ANY); if (fieldValue != null) { Element descriptionElement = new Element("description"); descriptionElement.setText(fieldValue); element.addContent(descriptionElement); } fieldValue = communityService.getMetadataFirstValue(community, CommunityService.MD_INTRODUCTORY_TEXT, Item.ANY); if (fieldValue != null) { Element introElement = new Element("intro"); introElement.setText(fieldValue); element.addContent(introElement); } fieldValue = communityService.getMetadataFirstValue(community, CommunityService.MD_COPYRIGHT_TEXT, Item.ANY); if (fieldValue != null) { Element copyrightElement = new Element("copyright"); copyrightElement.setText(fieldValue); element.addContent(copyrightElement); } fieldValue = communityService.getMetadataFirstValue(community, CommunityService.MD_SIDEBAR_TEXT, Item.ANY); if (fieldValue != null) { Element sidebarElement = new Element("sidebar"); sidebarElement.setText(fieldValue); element.addContent(sidebarElement); } // handle sub communities NodeList subCommunities = (NodeList) xPath.compile("community") .evaluate(tn, XPathConstants.NODESET); Element[] subCommunityElements = handleCommunities(context, subCommunities, community, keepHandles); // handle collections NodeList collections = (NodeList) xPath.compile("collection") .evaluate(tn, XPathConstants.NODESET); Element[] collectionElements = handleCollections(context, collections, community, keepHandles); int j; for (j = 0; j < subCommunityElements.length; j++) { element.addContent(subCommunityElements[j]); } for (j = 0; j < collectionElements.length; j++) { element.addContent(collectionElements[j]); } elements[i] = element; } return elements; } /** * Take a node list of collections and create the structure from them * * @param context the context of the request * @param collections the node list of collections to be created * @param parent the parent community to whom the collections belong * @return an Element array containing additional information about the * created collections (e.g. the handle) */ private static Element[] handleCollections(Context context, NodeList collections, Community parent, boolean keepHandles) throws SQLException, AuthorizeException, XPathExpressionException { Element[] elements = new Element[collections.getLength()]; XPath xPath = XPathFactory.newInstance().newXPath(); for (int i = 0; i < collections.getLength(); i++) { Node tn = collections.item(i); Node identifier = tn.getAttributes().getNamedItem("identifier"); // Create the Collection. Collection collection; if (null == identifier || StringUtils.isBlank(identifier.getNodeValue()) || !keepHandles) { collection = collectionService.create(context, parent); } else { collection = collectionService.create(context, parent, identifier.getNodeValue()); } // default the short description to the empty string collectionService.setMetadataSingleValue(context, collection, MD_SHORT_DESCRIPTION, null, " "); // import the rest of the metadata for (Map.Entry entry : collectionMap.entrySet()) { NodeList nl = (NodeList) xPath.compile(entry.getKey()).evaluate(tn, XPathConstants.NODESET); if (nl.getLength() == 1) { collectionService.setMetadataSingleValue(context, collection, entry.getValue(), null, getStringValue(nl.item(0))); } } collectionService.update(context, collection); Element element = new Element("collection"); element.setAttribute("identifier", collection.getHandle()); Element nameElement = new Element("name"); nameElement.setText(collectionService.getMetadataFirstValue(collection, CollectionService.MD_NAME, Item.ANY)); element.addContent(nameElement); String fieldValue; fieldValue = collectionService.getMetadataFirstValue(collection, CollectionService.MD_SHORT_DESCRIPTION, Item.ANY); if (fieldValue != null) { Element descriptionElement = new Element("description"); descriptionElement.setText(fieldValue); element.addContent(descriptionElement); } fieldValue = collectionService.getMetadataFirstValue(collection, CollectionService.MD_INTRODUCTORY_TEXT, Item.ANY); if (fieldValue != null) { Element introElement = new Element("intro"); introElement.setText(fieldValue); element.addContent(introElement); } fieldValue = collectionService.getMetadataFirstValue(collection, CollectionService.MD_COPYRIGHT_TEXT, Item.ANY); if (fieldValue != null) { Element copyrightElement = new Element("copyright"); copyrightElement.setText(fieldValue); element.addContent(copyrightElement); } fieldValue = collectionService.getMetadataFirstValue(collection, CollectionService.MD_SIDEBAR_TEXT, Item.ANY); if (fieldValue != null) { Element sidebarElement = new Element("sidebar"); sidebarElement.setText(fieldValue); element.addContent(sidebarElement); } fieldValue = collectionService.getMetadataFirstValue(collection, CollectionService.MD_LICENSE, Item.ANY); if (fieldValue != null) { Element sidebarElement = new Element("license"); sidebarElement.setText(fieldValue); element.addContent(sidebarElement); } fieldValue = collectionService.getMetadataFirstValue(collection, CollectionService.MD_PROVENANCE_DESCRIPTION, Item.ANY); if (fieldValue != null) { Element sidebarElement = new Element("provenance"); sidebarElement.setText(fieldValue); element.addContent(sidebarElement); } elements[i] = element; } return elements; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy