/* * 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.policy; import java.util.HashMap; import java.util.List; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import eu.europa.ec.markt.dss.DSSUtils; import eu.europa.ec.markt.dss.exception.DSSException; import eu.europa.ec.markt.dss.validation102853.RuleUtils; import eu.europa.ec.markt.dss.validation102853.report.Conclusion; import eu.europa.ec.markt.dss.validation102853.rules.AttributeName; import eu.europa.ec.markt.dss.validation102853.rules.AttributeValue; 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.NodeValue; 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 a constraint and indicates its level: IGNORE, INFORM, WARN, FAIL. * <p/> * DISCLAIMER: Project owner DG-MARKT. * * @author <a href="mailto:dgmarkt.Project-DSS@arhs-developments.com">ARHS Developments</a> * @version $Revision: 1016 $ - $Date: 2011-06-17 15:30:45 +0200 (Fri, 17 Jun 2011) $ */ public class Constraint implements NodeName, NodeValue, AttributeName, AttributeValue, Indication, SubIndication { private static final Logger LOG = LoggerFactory.getLogger(Constraint.class); /** * Diagnostic data containing all static information */ protected XmlDom diagnosticData; /** * This field represents the {@code XmlNode} of the constraint */ protected XmlNode node; /** * This field represents the simple {@code String} value of the constraint */ protected String value; /** * This field represent the {@code List} of {@code String} values of the constraint */ private List<String> valueList; /** * This field represents the simple {@code String} expected value of the constraint */ protected String expectedValue; /** * This field represents the list of acceptable identifiers */ protected List<String> identifiers; protected String indication; protected String subIndication; protected MessageTag failureMessageTag; protected Map<String, String> messageAttributes = new HashMap<String, String>(); protected Conclusion conclusion; public static enum Level {IGNORE, INFORM, WARN, FAIL} private Level level; /** * This is the default constructor. It takes a level of the constraint as parameter. The string representing the level is trimmed and capitalized. If there is no corresponding * {@code Level} then the {@code DSSException} is raised. * * @param level the constraint level string. */ public Constraint(final String level) throws DSSException { try { this.level = Level.valueOf(level.trim().toUpperCase()); } catch (IllegalArgumentException e) { throw new DSSException("The validation policy configuration file should be checked: " + e.getMessage(), e); } } /** * This method creates the constraint {@code XmlNode}. * * @param parentNode Represents the parent {@code XmlNode} to which the constraint node should be attached. * @param messageTag is the message describing the constraint. * @return the {@code XmlNode} representing the current constraint in the validation process */ public XmlNode create(final XmlNode parentNode, final MessageTag messageTag) { this.node = parentNode.addChild(CONSTRAINT); this.node.addChild(NAME, messageTag.getMessage()).setAttribute(NAME_ID, messageTag.name()); return this.node; } /** * This method creates the constraint {@code XmlNode}. This method should be used when the message describing the constraint comports dynamic parameters. * * @param parentNode Represents the parent {@code XmlNode} to which the constraint node should be attached. * @param messageTag is the message describing the constraint. * @param parameters the dynamic parameters to integrate into the message. * @return the {@code XmlNode} representing the current constraint in the validation process. */ public XmlNode create(final XmlNode parentNode, final MessageTag messageTag, final String parameters) { this.node = parentNode.addChild(CONSTRAINT); final String message = String.format(messageTag.getMessage(), parameters); this.node.addChild(NAME, message).setAttribute(NAME_ID, messageTag.name()); return this.node; } /** * @return {@code XmlDom} representing encapsulated diagnostic data */ public XmlDom getDiagnosticData() { return diagnosticData; } /** * Allows to link the diagnostic data to the {@code Constraint} * * @param diagnosticData {@code XmlDom} representing diagnostic data */ public void setDiagnosticData(final XmlDom diagnosticData) { this.diagnosticData = diagnosticData; } /** * @param value the simple value of the constraint to set. */ public void setValue(final String value) { this.value = value; } /** * @param booleanValue the simple value of the constraint to set. The {@code boolean} is converted to its {@code String} representation. */ public void setValue(final boolean booleanValue) { this.value = String.valueOf(booleanValue); } /** * Sets the list of real values. * * @param stringList {@code List} of {@code String}s */ public void setValue(final List<String> stringList) { this.valueList = stringList; } /** * @return the simple value of the constraint. */ public String getValue() { return value; } public String getExpectedValue() { return expectedValue; } /** * @param expectedValue the simple expected value of the constraint to set. */ public void setExpectedValue(final String expectedValue) { this.expectedValue = expectedValue; } /** * This method carry out the validation of the constraint. * * @return true if the constraint is met, false otherwise. */ public boolean check() { if (ignore()) { node.addChild(STATUS, IGNORED); return true; } if (inform()) { node.addChild(STATUS, INFORMATION); node.addChild(INFO, null, messageAttributes).setAttribute(EXPECTED_VALUE, expectedValue).setAttribute(CONSTRAINT_VALUE, value); return true; } boolean error = value.isEmpty(); if (!error) { if (!"*".equals(expectedValue)) { error = expectedValue != null && !expectedValue.equals(value); } } if (error) { if (warn()) { node.addChild(STATUS, WARN); final XmlNode xmlNode = node.addChild(WARNING, failureMessageTag, messageAttributes); if (DSSUtils.isNotBlank(expectedValue) && !expectedValue.equals("true") && !expectedValue.equals("false")) { xmlNode.setAttribute(EXPECTED_VALUE, expectedValue).setAttribute(CONSTRAINT_VALUE, value); } conclusion.addWarning(failureMessageTag, messageAttributes); return true; } node.addChild(STATUS, KO); if (DSSUtils.isNotBlank(expectedValue) && !expectedValue.equals("true") && !expectedValue.equals("false")) { node.addChild(INFO).setAttribute(EXPECTED_VALUE, expectedValue).setAttribute(CONSTRAINT_VALUE, value); } if (DSSUtils.isNotBlank(indication)) { conclusion.setIndication(indication, subIndication); } conclusion.addError(failureMessageTag, messageAttributes); return false; } node.addChild(STATUS, OK); if (!messageAttributes.isEmpty()) { node.addChild(INFO, null, messageAttributes); } return true; } /** * This method carries out the validation of the constraint. * * @return true if the constraint is met, false otherwise. */ public boolean checkInList() { if (ignore()) { node.addChild(STATUS, IGNORED); return true; } if (inform()) { node.addChild(STATUS, INFORMATION); node.addChild(INFO, null, messageAttributes).setAttribute("ExpectedValue", expectedValue).setAttribute("ConstraintValue", value); return true; } final boolean contains; if (value != null && "*".equals(expectedValue)) { contains = true; } else if (!DSSUtils.isEmpty(valueList)) { contains = valueList.containsAll(identifiers); value = valueList.toString(); } else { contains = RuleUtils.contains1(value, identifiers); } if (!contains) { if (warn()) { node.addChild(STATUS, WARN); node.addChild(WARNING, failureMessageTag, messageAttributes).setAttribute(EXPECTED_VALUE, expectedValue).setAttribute(CONSTRAINT_VALUE, value); conclusion.addWarning(failureMessageTag, messageAttributes); return true; } node.addChild(STATUS, KO); node.addChild(INFO).setAttribute(EXPECTED_VALUE, expectedValue).setAttribute(CONSTRAINT_VALUE, value); conclusion.setIndication(indication, subIndication); conclusion.addError(failureMessageTag, messageAttributes); return false; } node.addChild(STATUS, OK); node.addChild(INFO, null, messageAttributes); return true; } /** * @param indication to return when failure * @param subIndication to return when failure * @param failureMessageTag is the answer to be done in case of the constraint failure. */ public void setIndications(final String indication, final String subIndication, final MessageTag failureMessageTag) { this.indication = indication; this.subIndication = subIndication; this.failureMessageTag = failureMessageTag; } /** * This method should be called when the failure of the constraint does not cause the failure of the process. * * @param failureMessageTag is the answer to be done in case of the constraint failure. */ public void setIndications(final MessageTag failureMessageTag) { this.failureMessageTag = failureMessageTag; } public void setConclusionReceiver(final Conclusion conclusion) { this.conclusion = conclusion; } /** * @param identifiers the {@code List} of identifiers to set. */ public void setIdentifiers(final List<String> identifiers) { this.identifiers = identifiers; } public List<String> getIdentifiers() { return identifiers; } /** * This method allows to add an attribute to the answer node (to the message). * * @param attributeName the attribute name * @param attributeValue the attribute value */ public Constraint setAttribute(final String attributeName, final String attributeValue) { messageAttributes.put(attributeName, attributeValue); return this; } /** * This method returns the constraint's level. * * @return the {@code Level} of the constraint */ public Level getLevel() { return level; } /** * Says if the constraint should be ignored. * * @return true if the constraint should be ignored. */ public boolean ignore() { return level.equals(Level.IGNORE); } /** * Indicates if the constraint should only return information. * * @return true if the constraint should only return information. */ public boolean inform() { return level.equals(Level.INFORM); } /** * Says if the result of the constraint should be considered as warning. * * @return true if the constraint should be considered as warning. */ public boolean warn() { return level.equals(Level.WARN); } /** * Indicates whether the constraint should fail when it is not met. * * @return true if the constraint should fail. */ public boolean fail() { return level.equals(Level.FAIL); } }