org.mycore.datamodel.metadata.MCRObjectService.java Source code

Java tutorial

Introduction

Here is the source code for org.mycore.datamodel.metadata.MCRObjectService.java

Source

/*
 * 
 * $Revision$ $Date$
 *
 * 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.datamodel.metadata;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;
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.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.
 * <p>
 * 
 * The dates are represent by a date and a type. Two types are in service data
 * at every time and can't remove:
 * <ul>
 * <li>createdate - for the creating date of the object, this was set only one
 * time</li>
 * <li>modifydate - for the accepting date of the object, this was set at every
 * changes</li>
 * </ul>
 * Other date types are optional, but as example in Dublin Core:
 * <ul>
 * <li>submitdate - for the submiting date of the object</li>
 * <li>acceptdate - for the accepting date of the object</li>
 * <li>validfromdate - for the date of the object, at this the object is valid
 * to use</li>
 * <li>validtodate - for the date of the object, at this the object is no more
 * valid to use</li>
 * </ul>
 * 
 * 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<MCRMetaISO8601Date> dates;

    private final ArrayList<MCRMetaAccessRule> rules;

    private final ArrayList<MCRMetaLangText> flags;

    private MCRCategoryID state;

    /**
     * This is the constructor of the MCRObjectService class. All data are set
     * to null.
     */
    public MCRObjectService() {
        dates = new ArrayList<MCRMetaISO8601Date>();

        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<MCRMetaAccessRule>();
        flags = new ArrayList<MCRMetaLangText>();
    }

    /**
     * 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
        org.jdom2.Element dates_element = service.getChild("servdates");
        dates.clear();

        if (dates_element != null) {
            List<Element> dateList = dates_element.getChildren();

            for (Element dateElement : dateList) {
                String date_element_name = dateElement.getName();

                if (!date_element_name.equals("servdate")) {
                    continue;
                }

                MCRMetaISO8601Date date = new MCRMetaISO8601Date();
                date.setFromDOM(dateElement);

                setDate(date);
            }
        }

        // Rule part
        Element servacls = service.getChild("servacls");
        if (servacls != null) {
            List<Element> 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
        org.jdom2.Element flagsElement = service.getChild("servflags");
        if (flagsElement != null) {
            List<Element> flagList = flagsElement.getChildren();
            for (Element flagElement : flagList) {
                if (!flagElement.getName().equals("servflag")) {
                    continue;
                }
                MCRMetaLangText flag = new MCRMetaLangText();
                flag.setFromDOM(flagElement);
                flags.add(flag);
            }
        }

        org.jdom2.Element statesElement = service.getChild("servstates");
        if (statesElement != null) {
            List<Element> 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<MCRMetaISO8601Date> 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(i -> dates.get(i)).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 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.error("Error at setting servstate classification.",
                        new MCRException("The category " + state.toString() + " does not exist."));
            }
        }
    }

    /**
     * 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
     */
    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 add a flag to the flag list.
     * 
     * @param value -
     *            the new flag as string
     */
    public final void addFlag(String value) {
        if (value == null || (value = value.trim()).length() == 0) {
            return;
        }

        MCRMetaLangText flag = new MCRMetaLangText("servflag", null, null, 0, null, value);
        flags.add(flag);
    }

    /**
     * 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) {
        if (value == null || (value = value.trim()).length() == 0) {
            return;
        }
        if (type == null || (type = type.trim()).length() == 0) {
            type = null;
        }

        MCRMetaLangText flag = new MCRMetaLangText("servflag", null, type, 0, null, value);
        flags.add(flag);
    }

    /**
     * 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<MCRMetaLangText> 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<MCRMetaLangText> 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<String> 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) {
        if (value == null || (value = value.trim()).length() == 0) {
            return false;
        }

        for (MCRMetaLangText flag : flags) {
            if (flag.getText().equals(value)) {
                return true;
            }
        }

        return 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) {
        ArrayList<MCRMetaLangText> internalList = getFlagsAsMCRMetaLangText(type);
        return internalList.size() > 0;
    }

    /**
     * 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<MCRMetaLangText> 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 {
        if (index < 0 || index > flags.size()) {
            throw new IndexOutOfBoundsException("Index error in replaceFlag.");
        }
        if (value == null || (value = value.trim()).length() == 0) {
            return;
        }
        MCRMetaLangText oldFlag = flags.get(index);
        MCRMetaLangText flag = new MCRMetaLangText("servflag", null, oldFlag.getType(), 0, null, value);
        flags.set(index, 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 {
        if (index < 0 || index > flags.size()) {
            throw new IndexOutOfBoundsException("Index error in replaceFlag.");
        }
        if (value == null || (value = value.trim()).length() == 0) {
            return;
        }
        MCRMetaLangText oldFlag = flags.get(index);
        MCRMetaLangText flag = new MCRMetaLangText("servflag", null, value, 0, null, oldFlag.getText());
        flags.set(index, flag);
    }

    /**
     * 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, org.jdom2.Element condition) {
        if (condition == null) {
            return;
        }
        if (permission == null || (permission = permission.trim()).length() == 0) {
            return;
        }
        if (getRuleIndex(permission) == -1) {
            MCRMetaAccessRule acl = new MCRMetaAccessRule("servacl", null, 0, permission, condition);
            rules.add(acl);
        }
    }

    /**
     * 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<MCRMetaAccessRule> 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 org.jdom2.Element createXML() throws MCRException {
        try {
            validate();
        } catch (MCRException exc) {
            throw new MCRException("The content is not valid.", exc);
        }
        org.jdom2.Element elm = new org.jdom2.Element("service");

        if (dates.size() != 0) {
            org.jdom2.Element elmm = new org.jdom2.Element("servdates");
            elmm.setAttribute("class", "MCRMetaISO8601Date");

            for (MCRMetaISO8601Date date : dates) {
                elmm.addContent(date.createXML());
            }

            elm.addContent(elmm);
        }

        if (rules.size() != 0) {
            org.jdom2.Element elmm = new org.jdom2.Element("servacls");
            elmm.setAttribute("class", "MCRMetaAccessRule");

            for (MCRMetaAccessRule rule : rules) {
                elmm.addContent(rule.createXML());
            }

            elm.addContent(elmm);
        }

        if (flags.size() != 0) {
            org.jdom2.Element elmm = new org.jdom2.Element("servflags");
            elmm.setAttribute("class", "MCRMetaLangText");

            for (MCRMetaLangText flag : flags) {
                elmm.addContent(flag.createXML());
            }

            elm.addContent(elmm);
        }
        if (state != null) {
            org.jdom2.Element elmm = new org.jdom2.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.
     * 
     * <pre>
     *   {
     *      dates: [
     *          {@link MCRMetaISO8601Date#createJSON()},
     *          ...
     *      ],
     *      rules: [
     *          {@link MCRMetaAccessRule#createJSON()},
     *          ...
     *      ],
     *      flags: [
     *          {@link MCRMetaLangText#createJSON()},
     *          ...
     *      ],
     *      state: {
     *          
     *      }
     *   }
     * </pre>
     * 
     * @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 <em>true</em> if
     * <ul>
     * <li>the date value of "createdate" is not null or empty
     * <li>the date value of "modifydate" is not null or empty
     * </ul>
     * otherwise the method return <em>false</em>
     * 
     * @return a boolean value
     */
    public final boolean isValid() {
        try {
            validate();
            return true;
        } catch (MCRException exc) {
            LOGGER.warn("The <service> part is invalid.");
        }
        return false;
    }

    /**
     * Validates the content of this class. This method throws an exception if:
     *  <ul>
     *  <li>the date value of "createdate" is not null or empty</li>
     *  <li>the date value of "modifydate" is not null or empty</li>
     *  </ul>
     * 
     * @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) {
        if (value == null || (value = value.trim()).length() == 0) {
            return -1;
        }
        for (int i = 0; i < flags.size(); i++) {
            if (flags.get(i).getText().equals(value)) {
                return i;
            }
        }
        return -1;
    }

}