org.mycore.datamodel.metadata.MCRObjectService Maven / Gradle / Ivy
/*
* 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.Date;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.jdom2.Element;
import org.mycore.common.MCRException;
import org.mycore.common.MCRUtils;
import org.mycore.common.config.MCRConfiguration2;
import org.mycore.datamodel.classifications2.MCRCategoryDAOFactory;
import org.mycore.datamodel.classifications2.MCRCategoryID;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
/**
* This class implements all methods for handling MCRObject service data.
* The service data stores technical information that is no metadata.
* The service data holds three types of data, dates, flags and states.
* The flags are text strings and are optional.
*
*
* The dates are represent by a date and a type. Two types are in service data
* at every time and can't remove:
*
* - createdate - for the creating date of the object, this was set only one
* time
* - modifydate - for the accepting date of the object, this was set at every
* changes
*
* Other date types are optional, but as example in Dublin Core:
*
* - submitdate - for the submiting date of the object
* - acceptdate - for the accepting date of the object
* - validfromdate - for the date of the object, at this the object is valid
* to use
* - validtodate - for the date of the object, at this the object is no more
* valid to use
*
*
* The state is optional and represented by a MyCoRe classification object.
*
* @author Jens Kupferschmidt
* @author Matthias Eichner
* @author Robert Stephan
* @version $Revision$ $Date$
*/
public class MCRObjectService {
private static Logger LOGGER = LogManager.getLogger();
/**
* constant for create date
*/
public static final String DATE_TYPE_CREATEDATE = "createdate";
/**
* constant for modify date
*/
public static final String DATE_TYPE_MODIFYDATE = "modifydate";
/**
* constant for create user
*/
public static final String FLAG_TYPE_CREATEDBY = "createdby";
/**
* constant for modify user
*/
public static final String FLAG_TYPE_MODIFIEDBY = "modifiedby";
private final ArrayList dates;
private final ArrayList rules;
private final ArrayList flags;
private MCRCategoryID state;
/**
* This is the constructor of the MCRObjectService class. All data are set
* to null.
*/
public MCRObjectService() {
dates = new ArrayList<>();
Date curTime = new Date();
MCRMetaISO8601Date d = new MCRMetaISO8601Date("servdate", DATE_TYPE_CREATEDATE, 0);
d.setDate(curTime);
dates.add(d);
d = new MCRMetaISO8601Date("servdate", DATE_TYPE_MODIFYDATE, 0);
d.setDate(curTime);
dates.add(d);
rules = new ArrayList<>();
flags = new ArrayList<>();
}
/**
* This method read the XML input stream part from a DOM part for the
* structure data of the document.
*
* @param service
* a list of relevant DOM elements for the metadata
*/
public final void setFromDOM(Element service) {
// Date part
Element servdates = service.getChild("servdates");
dates.clear();
if (servdates != null) {
List dateList = servdates.getChildren();
for (Element dateElement : dateList) {
String dateElementName = dateElement.getName();
if (!"servdate".equals(dateElementName)) {
continue;
}
MCRMetaISO8601Date date = new MCRMetaISO8601Date();
date.setFromDOM(dateElement);
setDate(date);
}
}
// Rule part
Element servacls = service.getChild("servacls");
if (servacls != null) {
List ruleList = servacls.getChildren();
for (Element ruleElement : ruleList) {
if (!ruleElement.getName().equals("servacl")) {
continue;
}
MCRMetaAccessRule user = new MCRMetaAccessRule();
user.setFromDOM(ruleElement);
rules.add(user);
}
}
// Flag part
Element flagsElement = service.getChild("servflags");
if (flagsElement != null) {
List flagList = flagsElement.getChildren();
for (Element flagElement : flagList) {
if (!flagElement.getName().equals("servflag")) {
continue;
}
MCRMetaLangText flag = new MCRMetaLangText();
flag.setFromDOM(flagElement);
flags.add(flag);
}
}
Element statesElement = service.getChild("servstates");
if (statesElement != null) {
List flagList = statesElement.getChildren();
for (Element stateElement : flagList) {
if (!stateElement.getName().equals("servstate")) {
continue;
}
MCRMetaClassification stateClass = new MCRMetaClassification();
stateClass.setFromDOM(stateElement);
state = new MCRCategoryID(stateClass.getClassId(), stateClass.getCategId());
}
}
}
/**
* This method return the size of the date list.
*
* @return the size of the date list
*/
public final int getDateSize() {
return dates.size();
}
/**
* Returns the dates.
*
* @return list of dates
*/
protected ArrayList getDates() {
return dates;
}
/**
* This method returns the status classification
*
* @return the status as MCRMetaClassification,
* can return null
*
*/
public final MCRCategoryID getState() {
return state;
}
/**
* This method get a date for a given type. If the type was not found, an
* null was returned.
*
* @param type
* the type of the date
* @return the date as GregorianCalendar
*
* @see MCRObjectService#DATE_TYPE_CREATEDATE
* @see MCRObjectService#DATE_TYPE_MODIFYDATE
*/
public final Date getDate(String type) {
MCRMetaISO8601Date isoDate = getISO8601Date(type);
if (isoDate == null) {
return null;
}
return isoDate.getDate();
}
private MCRMetaISO8601Date getISO8601Date(String type) {
if (type == null || type.length() == 0) {
return null;
}
return IntStream.range(0, dates.size())
.mapToObj(dates::get)
.filter(d -> d.getType().equals(type))
.findAny()
.orElse(null);
}
/**
* This method set a date element in the dates list to a actual date value.
* If the given type exists, the date was update.
*
* @param type
* the type of the date
*/
public final void setDate(String type) {
setDate(type, new Date());
}
/**
* This method set a date element in the dates list to a given date value.
* If the given type exists, the date was update.
*
* @param type
* the type of the date
* @param date
* set time to this Calendar
* null means the actual date
*/
public final void setDate(String type, Date date) {
MCRMetaISO8601Date d = getISO8601Date(type); //search date in ArrayList
if (d == null) {
d = new MCRMetaISO8601Date("servdate", type, 0);
d.setDate(date);
dates.add(d);
} else {
d.setDate(date); // alter date found in ArrayList
}
}
/**
* This method set a date element in the dates list to a given date value.
* If the given type exists, the date was update.
*
* @param date
* set time to this Calendar
*/
private void setDate(MCRMetaISO8601Date date) {
MCRMetaISO8601Date d = getISO8601Date(date.getType()); //search date in ArrayList
if (d == null) {
dates.add(date);
} else {
d.setDate(date.getDate()); // alter date found in ArrayList
}
}
/**
* This method removes the date of the specified type from
* the date list.
*
* @param type
* a type as string
*/
public final void removeDate(String type) {
if (DATE_TYPE_CREATEDATE.equals(type) || DATE_TYPE_MODIFYDATE.equals(type)) {
LOGGER.error("Cannot delete built-in date: " + type);
} else {
MCRMetaISO8601Date d = getISO8601Date(type);
if (d != null) {
dates.remove(d);
}
}
}
/**
* This method sets the status classification
*/
public final void setState(MCRCategoryID state) {
if (state == null) {
this.state = state;
} else {
if (MCRCategoryDAOFactory.getInstance().exist(state)) {
this.state = state;
} else {
LOGGER.warn("Error at setting servstate classification.",
new MCRException("The category " + state + " does not exist."));
}
}
}
/**
* This method sets the status classification with the given string as categid
* and the default classid ('state')
*/
public final void setState(String state) {
if (state == null) {
this.state = null;
} else {
MCRCategoryID categState = new MCRCategoryID(
MCRConfiguration2.getString("MCR.Metadata.Service.State.Classification.ID").orElse("state"),
state);
setState(categState);
}
}
/**
* This method removes the current state
*/
public final void removeState() {
this.state = null;
}
/**
* This method add a flag to the flag list.
*
* @param value -
* the new flag as string
*/
public final void addFlag(String value) {
addFlag(null, value);
}
/**
* This method adds a flag to the flag list.
*
* @param type
* a type as string
* @param value
* the new flag value as string
*/
public final void addFlag(String type, String value) {
String lType = MCRUtils.filterTrimmedNotEmpty(type).orElse(null);
MCRUtils.filterTrimmedNotEmpty(value)
.map(flagValue -> new MCRMetaLangText("servflag", null, lType, 0, null, flagValue))
.ifPresent(flags::add);
}
/**
* This method get all flags from the flag list as a string.
*
* @return the flags string
*/
public final String getFlags() {
StringBuilder sb = new StringBuilder();
for (MCRMetaLangText flag : flags) {
sb.append(flag.getText()).append(" ");
}
return sb.toString();
}
/**
* Returns the flags as list.
*
* @return flags as list
*/
protected final List getFlagsAsList() {
return flags;
}
/**
* This method returns all flag values of the specified type.
*
* @param type
* a type as string.
* @return a list of flag values
*/
protected final ArrayList getFlagsAsMCRMetaLangText(String type) {
return flags.stream()
.filter(metaLangText -> type.equals(metaLangText.getType()))
.collect(Collectors.toCollection(ArrayList::new));
}
/**
* This method returns all flag values of the specified type.
*
* @param type
* a type as string.
* @return a list of flag values
*/
public final ArrayList getFlags(String type) {
return getFlagsAsMCRMetaLangText(type).stream()
.map(MCRMetaLangText::getText)
.collect(Collectors.toCollection(ArrayList::new));
}
/**
* This method return the size of the flag list.
*
* @return the size of the flag list
*/
public final int getFlagSize() {
return flags.size();
}
/**
* This method get a single flag from the flag list as a string.
*
* @exception IndexOutOfBoundsException
* throw this exception, if the index is false
* @return a flag string
*/
public final String getFlag(int index) throws IndexOutOfBoundsException {
if (index < 0 || index > flags.size()) {
throw new IndexOutOfBoundsException("Index error in getFlag.");
}
return flags.get(index).getText();
}
/**
* This method gets a single flag type from the flag list as a string.
*
* @exception IndexOutOfBoundsException
* throw this exception, if the index is false
* @return a flag type
*/
public final String getFlagType(int index) throws IndexOutOfBoundsException {
if (index < 0 || index > flags.size()) {
throw new IndexOutOfBoundsException("Index error in getFlagType.");
}
return flags.get(index).getType();
}
/**
* This method return a boolean value if the given flag is set or not.
*
* @param value
* a searched flag
* @return true if the flag was found in the list
*/
public final boolean isFlagSet(String value) {
return MCRUtils.filterTrimmedNotEmpty(value)
.map(flagValue -> flags.stream().anyMatch(flag -> flag.getText().equals(flagValue)))
.orElse(false);
}
/**
* Proves if the type is set in the flag list.
* @param type
* a type as string
* @return true if the flag list contains flags with this type,
* otherwise false
*/
public final boolean isFlagTypeSet(String type) {
return MCRUtils.filterTrimmedNotEmpty(type)
.map(flagType -> flags.stream().anyMatch(flag -> flag.getType().equals(flagType)))
.orElse(false);
}
/**
* This method remove a flag from the flag list.
*
* @param index
* a index in the list
* @exception IndexOutOfBoundsException
* throw this exception, if the index is false
*/
public final void removeFlag(int index) throws IndexOutOfBoundsException {
if (index < 0 || index > flags.size()) {
throw new IndexOutOfBoundsException("Index error in removeFlag.");
}
flags.remove(index);
}
/**
* This method removes all flags of the specified type from
* the flag list.
*
* @param type
* a type as string
*/
public final void removeFlags(String type) {
ArrayList internalList = getFlagsAsMCRMetaLangText(type);
flags.removeAll(internalList);
}
/**
* This method set a flag in the flag list.
*
* @param index
* a index in the list
* @param value
* the value of a flag as string
* @exception IndexOutOfBoundsException
* throw this exception, if the index is false
*/
public final void replaceFlag(int index, String value) throws IndexOutOfBoundsException {
MCRUtils.filterTrimmedNotEmpty(value)
.ifPresent(flagValue -> updateFlag(index, flag -> flag.setText(value)));
}
private void updateFlag(int index, Consumer flagUpdater) {
MCRMetaLangText flag = flags.get(index);
flagUpdater.accept(flag);
}
/**
* This method sets the type value of a flag at the specified index.
*
* @param index
* a index in the list
* @param value
* the value of a flag as string
* @exception IndexOutOfBoundsException
* throw this exception, if the index is false
*/
public final void replaceFlagType(int index, String value) throws IndexOutOfBoundsException {
MCRUtils.filterTrimmedNotEmpty(value)
.ifPresent(flagValue -> updateFlag(index, flag -> flag.setType(value)));
}
/**
* This method add a rule to the rules list.
*
* @param permission -
* the new permission as string
* @param condition -
* the new rule as JDOM tree Element
*/
public final void addRule(String permission, Element condition) {
if (condition == null) {
return;
}
MCRUtils.filterTrimmedNotEmpty(permission)
.filter(p -> getRuleIndex(p) == -1)
.map(p -> new MCRMetaAccessRule("servacl", null, 0, p, condition))
.ifPresent(rules::add);
}
/**
* This method return the size of the rules list.
*
* @return the size of the rules list
*/
public final int getRulesSize() {
return rules.size();
}
/**
* This method return the index of a permission in the rules list.
*
* @return the index of a permission in the rules list
*/
public final int getRuleIndex(String permission) {
int notFound = -1;
if (permission == null || permission.trim().length() == 0) {
return notFound;
}
return IntStream.range(0, rules.size())
.filter(i -> rules.get(i).getPermission().equals(permission))
.findAny()
.orElse(notFound);
}
/**
* This method get a single rule from the rules list as a JDOM Element.
*
* @exception IndexOutOfBoundsException
* throw this exception, if the index is false
* @return a the MCRMetaAccessRule instance
*/
public final MCRMetaAccessRule getRule(int index) throws IndexOutOfBoundsException {
if (index < 0 || index > rules.size()) {
throw new IndexOutOfBoundsException("Index error in getRule.");
}
return rules.get(index);
}
/**
* This method get a single permission name of rule from the rules list as a
* string.
*
* @exception IndexOutOfBoundsException
* throw this exception, if the index is false
* @return a rule permission string
*/
public final String getRulePermission(int index) throws IndexOutOfBoundsException {
if (index < 0 || index > rules.size()) {
throw new IndexOutOfBoundsException("Index error in getRulePermission.");
}
return rules.get(index).getPermission();
}
/**
* This method remove a rule from the rules list.
*
* @param index
* a index in the list
* @exception IndexOutOfBoundsException
* throw this exception, if the index is false
*/
public final void removeRule(int index) throws IndexOutOfBoundsException {
if (index < 0 || index > rules.size()) {
throw new IndexOutOfBoundsException("Index error in removeRule.");
}
rules.remove(index);
}
/**
* Returns the rules.
*
* @return list of rules
*/
protected final ArrayList getRules() {
return rules;
}
/**
* This method create a XML stream for all structure data.
*
* @exception MCRException
* if the content of this class is not valid
* @return a JDOM Element with the XML data of the structure data part
*/
public final Element createXML() throws MCRException {
try {
validate();
} catch (MCRException exc) {
throw new MCRException("The content is not valid.", exc);
}
Element elm = new Element("service");
if (dates.size() != 0) {
Element elmm = new Element("servdates");
elmm.setAttribute("class", "MCRMetaISO8601Date");
for (MCRMetaISO8601Date date : dates) {
elmm.addContent(date.createXML());
}
elm.addContent(elmm);
}
if (rules.size() != 0) {
Element elmm = new Element("servacls");
elmm.setAttribute("class", "MCRMetaAccessRule");
for (MCRMetaAccessRule rule : rules) {
elmm.addContent(rule.createXML());
}
elm.addContent(elmm);
}
if (flags.size() != 0) {
Element elmm = new Element("servflags");
elmm.setAttribute("class", "MCRMetaLangText");
for (MCRMetaLangText flag : flags) {
elmm.addContent(flag.createXML());
}
elm.addContent(elmm);
}
if (state != null) {
Element elmm = new Element("servstates");
elmm.setAttribute("class", "MCRMetaClassification");
MCRMetaClassification stateClass = new MCRMetaClassification("servstate", 0, null, state);
elmm.addContent(stateClass.createXML());
elm.addContent(elmm);
}
return elm;
}
/**
* Creates the JSON representation of this service.
*
*
* {
* dates: [
* {@link MCRMetaISO8601Date#createJSON()},
* ...
* ],
* rules: [
* {@link MCRMetaAccessRule#createJSON()},
* ...
* ],
* flags: [
* {@link MCRMetaLangText#createJSON()},
* ...
* ],
* state: {
*
* }
* }
*
*
* @return a json gson representation of this service
*/
public final JsonObject createJSON() {
JsonObject service = new JsonObject();
// dates
if (!getDates().isEmpty()) {
JsonObject dates = new JsonObject();
getDates()
.stream()
.forEachOrdered(date -> {
JsonObject jsonDate = date.createJSON();
jsonDate.remove("type");
dates.add(date.getType(), jsonDate);
});
service.add("dates", dates);
}
// rules
if (!getRules().isEmpty()) {
JsonArray rules = new JsonArray();
getRules()
.stream()
.map(MCRMetaAccessRule::createJSON)
.forEachOrdered(rules::add);
service.add("rules", rules);
}
// flags
if (!getFlags().isEmpty()) {
JsonArray flags = new JsonArray();
getFlagsAsList()
.stream()
.map(MCRMetaLangText::createJSON)
.forEachOrdered(flags::add);
service.add("flags", flags);
}
// state
Optional.ofNullable(getState()).ifPresent(stateId -> {
JsonObject state = new JsonObject();
if (stateId.getID() != null) {
state.addProperty("id", stateId.getID());
}
state.addProperty("rootId", stateId.getRootID());
});
return service;
}
/**
* This method check the validation of the content of this class. The method
* returns true if
*
* - the date value of "createdate" is not null or empty
*
- the date value of "modifydate" is not null or empty
*
* otherwise the method return false
*
* @return a boolean value
*/
public final boolean isValid() {
try {
validate();
return true;
} catch (MCRException exc) {
LOGGER.warn("The part is invalid.");
}
return false;
}
/**
* Validates the content of this class. This method throws an exception if:
*
* - the date value of "createdate" is not null or empty
* - the date value of "modifydate" is not null or empty
*
*
* @throws MCRException the content is invalid
*/
public void validate() {
// TODO: this makes no sense - there is nothing to validate
if (getISO8601Date(DATE_TYPE_CREATEDATE) == null) {
setDate(DATE_TYPE_CREATEDATE);
}
if (getISO8601Date(DATE_TYPE_MODIFYDATE) == null) {
setDate(DATE_TYPE_MODIFYDATE);
}
}
/**
* This method returns the index for the given flag value.
*
* @param value
* the value of a flag as string
* @return the index number or -1 if the value was not found
*/
public final int getFlagIndex(String value) {
return MCRUtils.filterTrimmedNotEmpty(value)
.map(v -> {
for (int i = 0; i < flags.size(); i++) {
if (flags.get(i).getText().equals(v)) {
return i;
}
}
return -1;
})
.orElse(-1);
}
}