/* * DSS - Digital Signature Services * * Copyright (C) 2013 European Commission, Directorate-General Internal Market and Services (DG MARKT), B-1049 Bruxelles/Brussel * * Developed by: 2013 ARHS Developments S.A. (rue Nicolas Bové 2B, L-1253 Luxembourg) http://www.arhs-developments.com * * This file is part of the "DSS - Digital Signature Services" project. * * "DSS - Digital Signature Services" is free software: you can redistribute it and/or modify it under the terms of * the GNU Lesser General Public License as published by the Free Software Foundation, either version 2.1 of the * License, or (at your option) any later version. * * DSS 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 Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License along with * "DSS - Digital Signature Services". If not, see <http://www.gnu.org/licenses/>. */ package eu.europa.ec.markt.dss.validation102853.report; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.validation102853.rules.AttributeName; import eu.europa.ec.markt.dss.validation102853.rules.Indication; import eu.europa.ec.markt.dss.validation102853.rules.MessageTag; import eu.europa.ec.markt.dss.validation102853.rules.NodeName; import eu.europa.ec.markt.dss.validation102853.rules.SubIndication; import eu.europa.ec.markt.dss.validation102853.xml.XmlDom; import eu.europa.ec.markt.dss.validation102853.xml.XmlNode; /** * This class represents the conclusion (result) of the process, with at least the Indication, SubIndication (if any)... * This class can be derived to handle specific needs of the process. * * @author bielecro */ public class Conclusion implements Indication, SubIndication, NodeName, AttributeName { private String indication; private String subIndication; private XmlNode validationData; /** * The {@code List} of information */ private List<Info> infoList; /** * The {@code List} of warnings */ private List<Warning> warningList; /** * The {@code List} of errors */ private List<Error> errorList; /** * This class expresses an information. */ static public class Info extends BasicInfo { public Info() { super(INFO); } public Info(final String value) { super(INFO, value); } public Info(final String nameId, final String value) { super(nameId, INFO, value); } public Info(final MessageTag messageTag) { super(INFO, messageTag); } public Info(final MessageTag messageTag, final String... dynamicParameters) { super(INFO, messageTag, dynamicParameters); } public Info(final MessageTag messageTag, final Map<String, String> attributes) { super(INFO, messageTag, attributes); } } /** * This class expresses a warning. */ static public class Warning extends BasicInfo { public Warning() { super(WARNING); } public Warning(final String value) { super(WARNING, value); } public Warning(final String nameId, final String value) { super(nameId, WARNING, value); } public Warning(final MessageTag messageTag) { super(WARNING, messageTag); } public Warning(final MessageTag messageTag, final Map<String, String> attributes) { super(WARNING, messageTag, attributes); } } /** * This class expresses a warning. */ static public class Error extends BasicInfo { public Error() { super(ERROR); } public Error(String value) { super(ERROR, value); } public Error(final String nameId, final String value) { super(nameId, ERROR, value); } public Error(final MessageTag messageTag) { super(ERROR, messageTag); } public Error(final MessageTag messageTag, final Map<String, String> attributes) { super(ERROR, messageTag, attributes); } } /** * This class contains information provided by the validation process and to be included in the conclusion. */ static public class BasicInfo { /** * The tag to use to express the basic information: Info or Warning */ protected final String tag; /** * The content of the basic information */ protected String value; /** * The {@code HashMap} containing the node's attributes and their values. */ protected HashMap<String, String> attributes = new HashMap<String, String>(); /** * @param tag indicates the info type: Info or Warning */ protected BasicInfo(final String tag) { this.tag = tag; } public BasicInfo(final String tag, final String value) { this.tag = tag; this.value = value; } /** * @param nameId indicates the unique message identifier * @param tag indicates the info type: Info or Warning * @param value the value of the information */ protected BasicInfo(final String nameId, final String tag, final String value) { setAttribute(NAME_ID, nameId); this.tag = tag; this.value = value; } /** * @param tag indicates the info type: Info or Warning * @param messageTag indicates the unique message identifier */ protected BasicInfo(final String tag, final MessageTag messageTag) { setAttribute(NAME_ID, messageTag.name()); this.tag = tag; this.value = messageTag.getMessage(); } /** * @param tag indicates the info type: Info or Warning * @param messageTag indicates the unique message identifier */ protected BasicInfo(final String tag, final MessageTag messageTag, final String... dynamicParameters) { setAttribute(NAME_ID, messageTag.name()); this.tag = tag; final String message = String.format(messageTag.getMessage(), dynamicParameters); this.value = message; } /** * @param tag indicates the info type: Info or Warning * @param messageTag indicates the unique message identifier * @param attributes the value of the information */ protected BasicInfo(final String tag, final MessageTag messageTag, final Map<String, String> attributes) { setAttribute(NAME_ID, messageTag.name()); this.tag = tag; this.value = messageTag.getMessage(); if (attributes != null) { this.attributes.putAll(attributes); } } /** * This method adds the given pair: attribute name, attribute value, to the {@code BasicInfo}. If the attribute exists already then its value is updated. * * @param name attribute name * @param value attribute value * @return the instance of the current object */ public BasicInfo setAttribute(final String name, final String value) { attributes.put(name, value); return this; } public boolean hasAttribute(final String name) { return attributes.containsKey(name); } public boolean hasAttribute(final String name, final String value) { if (attributes.isEmpty()) { return false; } final String attributeValue = attributes.get(name); return attributeValue != null && attributeValue.equals(value); } public String getAttributeValue(final String name) { if (attributes.isEmpty()) { return null; } final String attributeValue = attributes.get(name); return attributeValue; } public String getValue() { return value; } public void setValue(final String value) { this.value = value; } /** * This method adds the Info {@code XmlNode} to the given {@code XmlNode} * * @param xmlNode The node to which the Info node is added */ public void addTo(final XmlNode xmlNode) { final XmlNode info = xmlNode.addChild(INFO, value); for (final Entry<String, String> entry : attributes.entrySet()) { info.setAttribute(entry.getKey(), entry.getValue()); } } public HashMap<String, String> getAttributes() { return attributes; } @Override public String toString() { String attributeString = ""; for (Entry<String, String> entry : attributes.entrySet()) { if ("NameId".equals(entry.getKey())) { continue; } attributeString += (attributeString.isEmpty() ? "" : ", ") + entry.getKey() + "=" + entry.getValue(); } if (!value.isEmpty() && !attributeString.isEmpty()) { attributeString = " [" + attributeString + "]"; } return value + (attributeString.isEmpty() ? "" : attributeString); } } public boolean isValid() { return VALID.equals(indication); } /** * @return the indication returned by the validation process. */ public String getIndication() { return indication; } /** * This method set the indication. * * @param indication to set */ public void setIndication(final String indication) { this.indication = indication; } /** * @param indication the indication to set * @param subIndication the sub-indication to set */ public void setIndication(final String indication, final String subIndication) { this.indication = indication; this.subIndication = subIndication; } /** * @return the sub-indication returned by the validation process */ public String getSubIndication() { return subIndication; } /** * @param subIndication the sub-indication to set */ public void setSubIndication(final String subIndication) { this.subIndication = subIndication; } /** * This method adds an {@code Info} to the information list. * * @return created {@code Info} */ public Info addInfo() { final Info info = new Info(); ensureInfoList(); infoList.add(info); return info; } /** * This method adds an {@code Info} to the information list. * * @param messageTag {@code MessageTag} contains the unique message identifier and the content of the warning * @return created {@code Info} */ public Info addInfo(final MessageTag messageTag) { final Info info = new Info(messageTag); ensureInfoList(); infoList.add(info); return info; } /** * This method adds an {@code Info} to the information list. * * @param messageTag {@code MessageTag} contains the unique message identifier and the content of the warning * @return created {@code Info} */ public Info addInfo(final MessageTag messageTag, final String... dynamicParameters) { final Info info = new Info(messageTag, dynamicParameters); ensureInfoList(); infoList.add(info); return info; } /** * This method adds an {@code Info} to the information list. * * @param messageTag {@code MessageTag} contains the unique message identifier and the content of the warning * @param attributes {@code Map} contains all attributes associated to the warning. * @return created {@code Info} */ public Info addInfo(final MessageTag messageTag, Map<String, String> attributes) { final Info info = new Info(messageTag, attributes); ensureInfoList(); infoList.add(info); return info; } /** * Adds to this conclusion the information list contained in the {@code conclusion} parameter. * * @param conclusion from which the information list must be integrated to the current one. */ public void addInfo(final Conclusion conclusion) { if (conclusion.infoList != null && !conclusion.infoList.isEmpty()) { ensureInfoList(); infoList.addAll(conclusion.infoList); } } /** * This method adds the content of nodes contained in the given {@code List} of {@code XmlDom}(s) as information. * * @param infoList the {@code List} of {@code XmlDom}(s) to be integrated. */ public void addInfo(final List<XmlDom> infoList) { if (infoList == null || infoList.isEmpty()) { return; } ensureInfoList(); for (final XmlDom xmlDom : infoList) { final String value = xmlDom.getText(); final Info info = new Info(value); copyAttributes(xmlDom, info); this.infoList.add(info); } } private void copyAttributes(final XmlDom xmlDom, final BasicInfo basicInfo) { final NamedNodeMap attributes = xmlDom.getAttributes(); for (int index = 0; index < attributes.getLength(); index++) { final Node attribute = attributes.item(index); final String attributeName = attribute.getNodeName(); final String attributeValue = attribute.getNodeValue(); basicInfo.setAttribute(attributeName, attributeValue); } } /** * The children of the given {@code XmlNode} are added to the list of information. * * @param infoContainerXmlNode the {@code XmlNode} to integrate. */ public void addInfo(final XmlNode infoContainerXmlNode) { List<XmlNode> children; if (infoContainerXmlNode == null || (children = infoContainerXmlNode.getChildren()).isEmpty()) { return; } ensureInfoList(); for (final XmlNode child : children) { final String value = child.getValue(); final String messageId = DSSUtils.getMessageId(value); final Info info = new Info(messageId, value); final Map<String, String> attributes = child.getAttributes(); for (final Entry<String, String> entry : attributes.entrySet()) { final String attributeName = entry.getKey(); final String attributeValue = entry.getValue(); info.setAttribute(attributeName, attributeValue); } infoList.add(info); } } public void copyBasicInfo(final XmlNode xmlNode) { if (xmlNode == null) { return; } final String name = xmlNode.getName(); final String value = xmlNode.getValue(); BasicInfo basicInfo = null; if (ERROR.equals(name)) { basicInfo = addError(); } else if (WARNING.equals(name)) { basicInfo = addWarning(); } else if (INFO.equals(name)) { basicInfo = addInfo(); } basicInfo.setValue(value); final Map<String, String> attributes = xmlNode.getAttributes(); for (final Entry<String, String> entry : attributes.entrySet()) { basicInfo.setAttribute(entry.getKey(), entry.getValue()); } } private BasicInfo addError() { final Error error = new Error(); ensureErrorList(); errorList.add(error); return error; } /** * This method adds the content of nodes contained in the given {@code List} of {@code XmlDom}(s) as error. * * @param errors the {@code List} of {@code XmlDom}(s) to be integrated. */ private void addErrors(final List<XmlDom> errors) { if (errors == null || errors.isEmpty()) { return; } ensureErrorList(); for (final XmlDom errorXmlDom : errors) { final String value = errorXmlDom.getText(); final Error error = new Error(value); copyAttributes(errorXmlDom, error); errorList.add(error); } } private void ensureInfoList() { if (infoList == null) { infoList = new ArrayList<Info>(); } } public Info getInfo(final String attributeName) { if (infoList == null) { return null; } for (Info info : infoList) { if (info.hasAttribute(attributeName)) { return info; } } return null; } public Info getInfo(final String attributeName, final String attributeValue) { if (infoList == null) { return null; } for (Info info : infoList) { if (info.hasAttribute(attributeName, attributeValue)) { return info; } } return null; } private BasicInfo addWarning() { final Warning warning = new Warning(); ensureWarningList(); warningList.add(warning); return warning; } /** * This method adds an {@code Warning} to the warning list. * * @param messageTag {@code MessageTag} contains the unique message identifier and the content of the warning * @param attributes {@code Map} contains all attributes associated to the warning. * @return created {@code Warning} */ public Warning addWarning(final MessageTag messageTag, Map<String, String> attributes) { final Warning warning = new Warning(messageTag, attributes); ensureWarningList(); warningList.add(warning); return warning; } /** * This method adds an {@code Warning} to the warning list. * * @param messageTag {@code MessageTag} contains the unique message identifier and the content of the warning * @return created {@code Warning} */ public Warning addWarning(final MessageTag messageTag) { final Warning warning = new Warning(messageTag); ensureWarningList(); warningList.add(warning); return warning; } /** * This method adds the content of nodes contained in the given {@code List} of {@code XmlDom}(s) as warning. * * @param warnings the {@code List} of {@code XmlDom}(s) to be integrated. */ private void addWarnings(List<XmlDom> warnings) { if (warnings == null || warnings.isEmpty()) { return; } ensureWarningList(); for (final XmlDom warningXmlDom : warnings) { final String value = warningXmlDom.getText(); final Warning warning = new Warning(value); copyAttributes(warningXmlDom, warning); warningList.add(warning); } } /** * Adds to this conclusion the warning list contained in the {@code conclusion} parameter. * * @param conclusion from which the warning list must be integrated to the current one. */ public void addWarnings(final Conclusion conclusion) { if (conclusion.warningList != null && !conclusion.warningList.isEmpty()) { ensureWarningList(); warningList.addAll(conclusion.warningList); } } private void ensureWarningList() { if (warningList == null) { warningList = new ArrayList<Warning>(); } } /** * This method adds an {@code Warning} to the warning list. * * @param messageTag {@code MessageTag} contains the unique message identifier and the content of the warning * @return created {@code Warning} */ public Error addError(final MessageTag messageTag) { final Error error = new Error(messageTag); ensureErrorList(); errorList.add(error); return error; } /** * This method adds an {@code Error} to the error list. * * @param messageTag {@code MessageTag} contains the unique message identifier and the content of the error * @param attributes {@code Map} contains all attributes associated to the error. * @return created {@code Error} */ public Error addError(final MessageTag messageTag, Map<String, String> attributes) { final Error error = new Error(messageTag, attributes); ensureErrorList(); errorList.add(error); return error; } private void ensureErrorList() { if (errorList == null) { errorList = new ArrayList<Error>(); } } public XmlNode getValidationData() { return validationData; } /** * This method sets the validation data (The Xml created during the validation process). The conclusion node is added based on the content of this object. This * method must be called at the end of the process. If the content of this object changes, then this method need to * be called again. * * @param validationData */ public void setValidationData(final XmlNode validationData) { validationData.addChild(this.toXmlNode()); this.validationData = validationData; } /** * This method creates {@code XmlNode} representing the conclusion of the validation process. * * @return {@code XmlNode} representing the conclusion of the validation process. */ public XmlNode toXmlNode() { final XmlNode conclusion = new XmlNode(CONCLUSION); conclusion.addChild(INDICATION, indication); if (subIndication != null) { conclusion.addChild(SUB_INDICATION, subIndication); } infoToXmlNode(conclusion); warningToXmlNode(conclusion); errorToXmlNode(conclusion); return conclusion; } public void infoToXmlNode(final XmlNode conclusion) { basicInfoToXmlNode(infoList, INFO, conclusion); } public void warningToXmlNode(final XmlNode conclusion) { basicInfoToXmlNode(warningList, WARNING, conclusion); } public void errorToXmlNode(final XmlNode conclusion) { basicInfoToXmlNode(errorList, ERROR, conclusion); } private void basicInfoToXmlNode(List<?> basicInfoList, final String infoLevel, final XmlNode conclusion) { if (basicInfoList != null) { for (final Object basicInfoObject : basicInfoList) { BasicInfo basicInfo = (BasicInfo) basicInfoObject; final XmlNode infoNode = conclusion.addChild(infoLevel, basicInfo.getValue()); for (final Entry<String, String> entry : basicInfo.attributes.entrySet()) { infoNode.setAttribute(entry.getKey(), entry.getValue()); } } } } public void copyConclusion(final XmlDom conclusionXmlDom) { final String indication = conclusionXmlDom.getValue("./Indication/text()"); if (!indication.isEmpty()) { this.indication = indication; } final String subIndication = conclusionXmlDom.getValue("./SubIndication/text()"); if (!subIndication.isEmpty()) { this.subIndication = subIndication; } final List<XmlDom> errors = conclusionXmlDom.getElements("./Error"); addErrors(errors); final List<XmlDom> warnings = conclusionXmlDom.getElements("./Warning"); addWarnings(warnings); final List<XmlDom> info = conclusionXmlDom.getElements("./Info"); addInfo(info); } public void copyWarnings(final XmlDom conclusionXmlDom) { final List<XmlDom> warnings = conclusionXmlDom.getElements("./Warning"); addWarnings(warnings); } public String toString() { return toXmlNode().toString(); } }