org.mycore.mods.MCRMODSWrapper.java Source code

Java tutorial

Introduction

Here is the source code for org.mycore.mods.MCRMODSWrapper.java

Source

/*
 * $Revision: 5697 $ $Date: 07.04.2011 $
 *
 * This file is part of ***  M y C o R e  ***
 * See http://www.mycore.de/ for details.
 *
 * This program is free software; you can use it, redistribute it
 * and / or modify it under the terms of the GNU General Public License
 * (GPL) as published by the Free Software Foundation; either version 2
 * of the License or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program, in a file called gpl.txt or license.txt.
 * If not, write to the Free Software Foundation Inc.,
 * 59 Temple Place - Suite 330, Boston, MA  02111-1307 USA
 */

package org.mycore.mods;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.jdom2.Content;
import org.jdom2.Element;
import org.jdom2.JDOMException;
import org.jdom2.filter.Filters;
import org.jdom2.xpath.XPathExpression;
import org.jdom2.xpath.XPathFactory;
import org.mycore.common.MCRConstants;
import org.mycore.common.MCRException;
import org.mycore.datamodel.classifications2.MCRCategoryID;
import org.mycore.datamodel.metadata.MCRMetaElement;
import org.mycore.datamodel.metadata.MCRMetaXML;
import org.mycore.datamodel.metadata.MCRObject;
import org.mycore.datamodel.metadata.MCRObjectID;
import org.mycore.datamodel.metadata.MCRObjectMetadata;
import org.mycore.datamodel.metadata.MCRObjectService;
import org.mycore.mods.classification.MCRClassMapper;

/**
 * @author Frank L\u00FCtzenkirchen
 * @author Thomas Scheffler
 */
public class MCRMODSWrapper {

    //ancestor::mycoreobject required for MCR-927
    private static final String LINKED_RELATED_ITEMS = "mods:relatedItem[@type='host' and ancestor::mycoreobject/structure/parents/parent or"
            + " contains(@xlink:href,'_mods_') and" + " number(substring-after(@xlink:href,'_mods_')) > 0 and"
            + " contains('" + MCRMODSRelationshipType.xPathList() + "', @type)]";

    private static final String MODS_CONTAINER = "modsContainer";

    private static final String DEF_MODS_CONTAINER = "def.modsContainer";

    public static final String MODS_OBJECT_TYPE = "mods";

    private static final String MODS_DATAMODEL = "datamodel-mods.xsd";

    private static List<String> topLevelElementOrder = new ArrayList<String>();

    static {
        topLevelElementOrder.add("typeOfResource");
        topLevelElementOrder.add("titleInfo");
        topLevelElementOrder.add("name");
        topLevelElementOrder.add("genre");
        topLevelElementOrder.add("originInfo");
        topLevelElementOrder.add("language");
        topLevelElementOrder.add("abstract");
        topLevelElementOrder.add("note");
        topLevelElementOrder.add("subject");
        topLevelElementOrder.add("classification");
        topLevelElementOrder.add("relatedItem");
        topLevelElementOrder.add("identifier");
        topLevelElementOrder.add("location");
        topLevelElementOrder.add("accessCondition");
    }

    private static int getRankOf(Element topLevelElement) {
        return topLevelElementOrder.indexOf(topLevelElement.getName());
    }

    public static MCRObject wrapMODSDocument(Element modsDefinition, String projectID) {
        MCRMODSWrapper wrapper = new MCRMODSWrapper();
        wrapper.setID(projectID, 0);
        wrapper.setMODS(modsDefinition);
        return wrapper.getMCRObject();
    }

    /**
     * returns true if the given MCRObject can handle MODS metadata
     * @param obj - the MCRObject
     * @return true, if mods is supported
     */
    public static boolean isSupported(MCRObject obj) {
        if (MODS_OBJECT_TYPE.equals(obj.getId().getTypeId())) {
            return true;
        }
        if (obj.getMetadata() != null && obj.getMetadata().getMetadataElement(DEF_MODS_CONTAINER) != null && obj
                .getMetadata().getMetadataElement(DEF_MODS_CONTAINER).getElementByName(MODS_CONTAINER) != null) {
            return true;
        }
        return false;
    }

    private MCRObject object;

    public MCRMODSWrapper() {
        this(new MCRObject());
    }

    public MCRMODSWrapper(MCRObject object) {
        this.object = object;
        if (object.getSchema() == null || object.getSchema().isEmpty()) {
            object.setSchema(MODS_DATAMODEL);
        }
    }

    /**
     * @return the mods:mods Element at /metadata/def.modsContainer/modsContainer
     */
    public Element getMODS() {
        try {
            MCRMetaXML mx = (MCRMetaXML) (object.getMetadata().getMetadataElement(DEF_MODS_CONTAINER)
                    .getElement(0));
            for (Content content : mx.getContent()) {
                if (content instanceof Element) {
                    return (Element) content;
                }
            }
        } catch (NullPointerException | IndexOutOfBoundsException e) {
            //do nothing
        }
        return null;
    }

    public MCRObject getMCRObject() {
        return object;
    }

    public MCRObjectID setID(String projectID, int ID) {
        MCRObjectID objID = MCRObjectID.getInstance(MCRObjectID.formatID(projectID, MODS_OBJECT_TYPE, ID));
        object.setId(objID);
        return objID;
    }

    public void setMODS(Element mods) {
        MCRObjectMetadata om = object.getMetadata();
        if (om.getMetadataElement(DEF_MODS_CONTAINER) != null)
            om.removeMetadataElement(DEF_MODS_CONTAINER);

        MCRMetaXML modsContainer = new MCRMetaXML(MODS_CONTAINER, null, 0);
        List<MCRMetaXML> list = Collections.nCopies(1, modsContainer);
        MCRMetaElement defModsContainer = new MCRMetaElement(MCRMetaXML.class, DEF_MODS_CONTAINER, false, true,
                list);
        om.setMetadataElement(defModsContainer);

        modsContainer.addContent(mods);
    }

    private XPathExpression<Element> buildXPath(String xPath) throws JDOMException {
        return XPathFactory.instance().compile(xPath, Filters.element(), null, MCRConstants.MODS_NAMESPACE,
                MCRConstants.XLINK_NAMESPACE);
    }

    public Element getElement(String xPath) {
        try {
            return buildXPath(xPath).evaluateFirst(getMODS());
        } catch (JDOMException ex) {
            String msg = "Could not get MODS element from " + xPath;
            throw new MCRException(msg, ex);
        }
    }

    public List<Element> getElements(String xPath) {
        try {
            Element eMODS = getMODS();
            if (eMODS != null) {
                return buildXPath(xPath).evaluate(eMODS);
            } else {
                return Collections.<Element>emptyList();
            }
        } catch (JDOMException ex) {
            String msg = "Could not get elements at " + xPath;
            throw new MCRException(msg, ex);
        }
    }

    public List<Element> getLinkedRelatedItems() {
        return getElements(LINKED_RELATED_ITEMS);
    }

    public String getElementValue(String xPath) {
        Element element = getElement(xPath);
        return (element == null ? null : element.getTextTrim());
    }

    /**
     * Sets or adds an element with target name and value. The element name and attributes are used as xpath expression
     * to filter for an element. The attributes are used with and operation if present.
     */
    public Optional<Element> setElement(String elementName, String elementValue, Map<String, String> attributes) {
        boolean isAttributeDataPresent = attributes != null && !attributes.isEmpty();
        boolean isValuePresent = elementValue != null && !elementValue.isEmpty();

        if (!isValuePresent && !isAttributeDataPresent) {
            return Optional.empty();
        }

        StringBuilder xPath = new StringBuilder("mods:");
        xPath.append(elementName);

        // add attributes to xpath with and operator
        if (isAttributeDataPresent) {

            xPath.append("[");
            Iterator<Map.Entry<String, String>> attributeIterator = attributes.entrySet().iterator();
            while (attributeIterator.hasNext()) {
                Map.Entry<String, String> attribute = attributeIterator.next();
                xPath.append("@" + attribute.getKey() + "='" + attribute.getValue() + "']");

                if (attributeIterator.hasNext())
                    xPath.append(" and ");
            }
        }
        Element element = getElement(xPath.toString());

        if (element == null) {
            element = addElement(elementName);
            if (isAttributeDataPresent) {
                for (Map.Entry<String, String> entry : attributes.entrySet())
                    element.setAttribute(entry.getKey(), entry.getValue());
            }
        }

        if (isValuePresent)
            element.setText(elementValue.trim());

        return Optional.of(element);
    }

    public Optional<Element> setElement(String elementName, String attributeName, String attributeValue,
            String elementValue) {
        Map<String, String> attributes = Collections.emptyMap();
        if (attributeName != null && attributeValue != null) {
            attributes = new HashMap<>();
            attributes.put(attributeName, attributeValue);
        }
        return setElement(elementName, elementValue, attributes);
    }

    public Optional<Element> setElement(String elementName, String elementValue) {
        return setElement(elementName, null, null, elementValue);
    }

    public Element addElement(String elementName) {
        Element element = new Element(elementName, MCRConstants.MODS_NAMESPACE);
        insertTopLevelElement(element);
        return element;
    }

    public void addElement(Element element) {
        if (!element.getNamespace().equals(MCRConstants.MODS_NAMESPACE))
            throw new IllegalArgumentException("given element is no mods element");

        insertTopLevelElement(element);
    }

    private void insertTopLevelElement(Element element) {
        int rankOfNewElement = getRankOf(element);
        List<Element> topLevelElements = getMODS().getChildren();
        for (int pos = 0; pos < topLevelElements.size(); pos++)
            if (getRankOf(topLevelElements.get(pos)) > rankOfNewElement) {
                getMODS().addContent(pos, element);
                return;
            }

        getMODS().addContent(element);
    }

    public void removeElements(String xPath) {
        Iterator<Element> selected;
        try {
            selected = buildXPath(xPath).evaluate(getMODS()).iterator();
        } catch (JDOMException ex) {
            String msg = "Could not remove elements at " + xPath;
            throw new MCRException(msg, ex);
        }

        while (selected.hasNext()) {
            Element element = selected.next();
            element.detach();
        }
    }

    public void removeInheritedMetadata() {
        String xPath = LINKED_RELATED_ITEMS + "/*[local-name()!='part']";
        removeElements(xPath);
    }

    public String getServiceFlag(String type) {
        MCRObjectService os = object.getService();
        return (os.isFlagTypeSet(type) ? os.getFlags(type).get(0) : null);
    }

    public void setServiceFlag(String type, String value) {
        MCRObjectService os = object.getService();
        if (os.isFlagTypeSet(type))
            os.removeFlags(type);
        if ((value != null) && !value.trim().isEmpty())
            os.addFlag(type, value.trim());
    }

    public List<MCRCategoryID> getMcrCategoryIDs() {
        final List<Element> categoryNodes = getCategoryNodes();
        final List<MCRCategoryID> categories = new ArrayList<>(categoryNodes.size());
        for (Element node : categoryNodes) {
            final MCRCategoryID categoryID = MCRClassMapper.getCategoryID(node);
            if (categoryID != null) {
                categories.add(categoryID);
            }
        }
        return categories;
    }

    private List<Element> getCategoryNodes() {
        return getElements(
                "mods:typeOfResource | mods:accessCondition | .//*[(@authority or @authorityURI) and not(ancestor::mods:relatedItem[@type='host'])]");
    }
}