Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* This file is part of *** M y C o R e ***
* See http://www.mycore.de/ for details.
*
* MyCoRe is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MyCoRe 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 MyCoRe. If not, see .
*/
package org.mycore.datamodel.metadata;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jdom2.Element;
import org.mycore.common.MCRException;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
/**
* This class implements code for the inheritance of metadata of linked objects
* and the linking of derivates onto an MCRObject. These links are described by
* the MCRMetaLink class. For links to another object, there are
* "locators" in use only, and the href variable gives the ID of the linked
* object, while the label and title attributes can be used freely. Subtag name = "
* <child>" means a child link from a "parent" object (collected in the
* "children" and "parents" section of the "structure" part, respectively). The
* child inherits all heritable metadata of the parent. If the parent itself is
* a child of another parent, the heritable metadata of this "grand parent" is
* inherited by the child as well. This mechanism recursively traces the full
* inheritance hierarchy. So if the grand parent itself has a parent, this grand
* parent parent's heritable metadata will be inherited and so on. Note, that it
* is impossible to inherit metadata from multiple parents. In cases of multiple
* inheritance request, an exception is thrown. A child link cannot occur twice
* from the same object to the same href (preventing from doubled links). Not
* supported by this class are links from or to a defined place of a document
* (inner structure and combination of inner and outer structures of the
* objects). This will possibly be done in a later extension of
* MCRMetaLink and MCRObjectStructure.
*
* @author Mathias Hegner
* @author Jens Kupferschmidt
* @version $Revision$ $Date: 2008-02-06 18:27:24 +0100 (Mi, 06 Feb
* 2008) $
*/
public class MCRObjectStructure {
private MCRMetaLinkID parent;
private final ArrayList children;
private final ArrayList derivates;
private static final Logger LOGGER = LogManager.getLogger();
/**
* The constructor initializes NL (non-static, in order to enable different
* NL's for different objects) and the link vectors the elements of which
* are MCRMetaLink's.
*/
public MCRObjectStructure() {
children = new ArrayList<>();
derivates = new ArrayList<>();
}
/**
* This method clean the data lists parent, children and derivates of this
* class.
*/
public final void clear() {
parent = null;
children.clear();
derivates.clear();
}
/**
* This method clean the data lists children of this class.
*/
public final void clearChildren() {
children.clear();
}
/**
* This method clean the data lists derivate of this class.
*/
public final void clearDerivates() {
derivates.clear();
}
/**
* The method returns the parent link.
*
* @return MCRMetaLinkID the corresponding link
*/
public final MCRMetaLinkID getParent() {
return parent;
}
/**
* The method return the parent reference as a MCRObjectID.
*
* @return the parent MCRObjectID or null if there is no parent present
*/
public final MCRObjectID getParentID() {
if (parent == null) {
return null;
}
return parent.getXLinkHrefID();
}
/**
* This method set the parent value from a given MCRMetaLinkID.
*
* @param parent
* the MCRMetaLinkID to set
*
*/
public final void setParent(MCRMetaLinkID parent) {
this.parent = parent;
}
public final void setParent(MCRObjectID parentID) {
setParent(parentID.toString());
}
public final void setParent(String parentID) {
parent = new MCRMetaLinkID();
parent.setSubTag("parent");
parent.setReference(parentID, null, null);
}
/**
* Removes the parent reference. Use this method with care!
*/
public final void removeParent() {
parent = null;
}
/**
* The method appends a child ID to the child link list if and only if it is
* not already contained in the list, preventing from doubly-linked objects.
* If the link could be added a "true" will be returned, otherwise "false".
*
* @param child
* the MCRMetaLinkID of the child
* @return boolean true, if successfully done
*/
public final boolean addChild(MCRMetaLinkID child) {
for (MCRMetaLinkID c : children) {
if (c.getXLinkHrefID().equals(child.getXLinkHrefID())) {
return false;
}
}
children.add(child);
return true;
}
/**
* removes a child link to another object.
* If the link was found a "true" will be returned, otherwise
* "false".
*
* @param href
* the MCRObjectID of the child
* @return boolean true, if successfully completed
*/
public final boolean removeChild(MCRObjectID href) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Remove child ID {}", href);
}
return removeMetaLink(getChildren(), href);
}
/**
* Checks if the child is in the children vector.
*
* @param childId child to check
*/
public final boolean containsChild(MCRObjectID childId) {
return getChildren().stream().map(MCRMetaLinkID::getXLinkHrefID).anyMatch(childId::equals);
}
/**
* removes a derivate link.
* If the link was found a "true" will be returned, otherwise
* "false".
*
* @param href
* the MCRObjectID of the child
* @return boolean true, if successfully completed
*/
public final boolean removeDerivate(MCRObjectID href) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Remove derivate ID {}", href);
}
return removeMetaLink(getDerivates(), href);
}
/**
* Removes a MCRMetaLinkID instance by it MCRObjectID.
* @param list
* @param href
* @return
*/
private boolean removeMetaLink(List list, MCRObjectID href) {
final List toRemove = list.stream()
.filter(ml -> ml.getXLinkHrefID().equals(href))
.collect(Collectors.toList());
return list.removeAll(toRemove);
}
/**
* Returns all children in this structure
* */
public final List getChildren() {
return children;
}
/**
* addDerivate methode append the given derivate link data to the
* derivate vector. If the link could be added a "true" will be returned,
* otherwise "false".
*
* @param derivate
* the link to be added as MCRMetaLinkID
*/
public final boolean addDerivate(MCRMetaEnrichedLinkID derivate) {
MCRObjectID href = derivate.getXLinkHrefID();
if (containsDerivate(href)) {
return false;
}
if (!MCRMetadataManager.exists(href)) {
LOGGER.warn("Cannot find derivate {}, will add it anyway.", href);
}
derivates.add(derivate);
derivates.sort(Comparator.comparingInt(MCRMetaEnrichedLinkID::getOrder));
return true;
}
/**
* Adds or updates the derivate link. Returns true if the derivate is added
* or updated. Returns false when nothing is done.
*
* @param derivateLink the link to add or update
* @return true when the structure is changed
*/
public final boolean addOrUpdateDerivate(MCRMetaEnrichedLinkID derivateLink) {
if (derivateLink == null) {
return false;
}
MCRObjectID derivateId = derivateLink.getXLinkHrefID();
MCRMetaLinkID oldLink = getDerivateLink(derivateId);
if (derivateLink.equals(oldLink)) {
return false;
}
if (oldLink != null) {
removeDerivate(oldLink.getXLinkHrefID());
}
return addDerivate(derivateLink);
}
/**
* Checks if the derivate is in the derivate vector.
*
* @param derivateId derivate to check
*/
public final boolean containsDerivate(MCRObjectID derivateId) {
return getDerivateLink(derivateId) != null;
}
/**
* Returns the derivate link by id or null.
*/
public final MCRMetaEnrichedLinkID getDerivateLink(MCRObjectID derivateId) {
return getDerivates().stream()
.filter(derivate -> derivate.getXLinkHrefID().equals(derivateId))
.findAny()
.orElse(null);
}
/**
* @return a list with all related derivate ids encapsulated within a {@link MCRMetaLinkID}
* */
public List getDerivates() {
return this.derivates;
}
/**
* While the preceding methods dealt with the structure's copy in memory
* only, the following three will affect the operations to or from datastore
* too. Thereby setFromDOM will read the structure data from an
* XML input stream (the "structure" entry).
*
* @param element
* the structure node list
*/
public final void setFromDOM(Element element) {
clear();
Element subElement = element.getChild("children");
if (subElement != null) {
List childList = subElement.getChildren();
for (Element linkElement : childList) {
MCRMetaLinkID link = new MCRMetaLinkID();
link.setFromDOM(linkElement);
children.add(link);
}
}
// Stricture parent part
subElement = element.getChild("parents");
if (subElement != null) {
parent = new MCRMetaLinkID();
parent.setFromDOM(subElement.getChild("parent"));
}
// Structure derivate part
subElement = element.getChild("derobjects");
if (subElement != null) {
List derobjectList = subElement.getChildren();
for (Element derElement : derobjectList) {
addDerivate(MCRMetaEnrichedLinkID.fromDom(derElement));
}
}
}
/**
* createXML is the inverse of setFromDOM and converts the
* structure's memory copy into XML.
*
* @exception MCRException
* if the content of this class is not valid
* @return the structure XML
*/
public final Element createXML() throws MCRException {
try {
validate();
} catch (MCRException exc) {
throw new MCRException("The content is not valid.", exc);
}
Element elm = new Element("structure");
if (parent != null) {
Element elmm = new Element("parents");
elmm.setAttribute("class", "MCRMetaLinkID");
elmm.addContent(parent.createXML());
elm.addContent(elmm);
}
if (children.size() > 0) {
Element elmm = new Element("children");
elmm.setAttribute("class", "MCRMetaLinkID");
for (MCRMetaLinkID child : getChildren()) {
elmm.addContent(child.createXML());
}
elm.addContent(elmm);
}
if (derivates.size() > 0) {
Element elmm = new Element("derobjects");
elmm.setAttribute("class", "MCRMetaEnrichedLinkID");
for (MCRMetaLinkID derivate : getDerivates()) {
elmm.addContent(derivate.createXML());
}
elm.addContent(elmm);
}
return elm;
}
/**
* Creates the JSON representation of this structure.
*
*
*
* @return a json gson representation of this structure
*/
public JsonObject createJSON() {
JsonObject structure = new JsonObject();
// parent
Optional.ofNullable(getParent()).ifPresent(link -> structure.add("parent", link.createJSON()));
// children
JsonArray children = new JsonArray();
getChildren().forEach(child -> children.add(child.createJSON()));
structure.add("children", children);
// derivates
JsonArray derivates = new JsonArray();
getDerivates().forEach(derivate -> derivates.add(derivate.createJSON()));
structure.add("derivates", derivates);
return structure;
}
/**
* The method print all informations about this MCRObjectStructure.
*/
public final void debug() {
if (LOGGER.isDebugEnabled()) {
for (MCRMetaLinkID linkID : derivates) {
linkID.debug();
}
if (parent != null) {
parent.debug();
}
for (MCRMetaLinkID linkID : children) {
linkID.debug();
}
}
}
/**
* isValid checks whether all of the MCRMetaLink's in the link
* vectors are valid or not.
*
* @return boolean true, if structure is valid
*/
public final boolean isValid() {
try {
validate();
return true;
} catch (MCRException exc) {
LOGGER.warn("The part of a is invalid.", exc);
}
return false;
}
/**
* Validates this MCRObjectStructure. This method throws an exception if:
*
*
the parent is not null but invalid
*
one of the children is invalid
*
one of the derivates is invalid
*
*
* @throws MCRException the MCRObjectStructure is invalid
*/
public void validate() throws MCRException {
for (MCRMetaLinkID child : getChildren()) {
try {
child.validate();
} catch (Exception exc) {
throw new MCRException("The link to the children '" + child.getXLinkHref() + "' is invalid.", exc);
}
}
if (parent != null) {
try {
parent.validate();
} catch (Exception exc) {
throw new MCRException("The link to the parent '" + parent.getXLinkHref() + "' is invalid.", exc);
}
}
for (MCRMetaLinkID derivate : getDerivates()) {
try {
derivate.validate();
} catch (Exception exc) {
throw new MCRException("The link to the derivate '" + derivate.getXLinkHref() + "' is invalid.", exc);
}
if (!derivate.getXLinkType().equals("locator")) {
throw new MCRException("The xlink:type of the derivate link '" + derivate.getXLinkHref()
+ "' has to be 'locator' and not '" + derivate.getXLinkType() + "'.");
}
String typeId = derivate.getXLinkHrefID().getTypeId();
if (!typeId.equals("derivate")) {
throw new MCRException("The derivate link '" + derivate.getXLinkHref()
+ "' is invalid. The _type_ has to be 'derivate' and not '" + typeId + "'.");
}
}
}
}