diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/BasicTypeValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/BasicTypeValidator.java index db302e2a9eba8b8fdc3da55ed6ac9d161372ab62..18e984c60558fc5adb375b330d695354b5f1e81f 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/BasicTypeValidator.java +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/BasicTypeValidator.java @@ -27,7 +27,7 @@ import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.DiagnosticChain; import fr.centralesupelec.edf.riseclipse.iec61850.nsd.BasicType; -import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.AbstractDataAttribute; import fr.centralesupelec.edf.riseclipse.iec61850.scl.Val; import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL; import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole; @@ -44,7 +44,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "BOOLEAN", new BasicTypeValidator( "BOOLEAN" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { switch( value ) { case "0" : case "1" : @@ -61,7 +61,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "INT8", new BasicTypeValidator( "INT8" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { try { new Byte( value ); } @@ -76,7 +76,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "INT16", new BasicTypeValidator( "INT16" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { try { new Short( value ); } @@ -91,7 +91,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "INT32", new BasicTypeValidator( "INT32" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { try { new Integer( value ); } @@ -106,7 +106,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "INT64", new BasicTypeValidator( "INT64" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { try { new Long( value ); } @@ -121,7 +121,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "INT8U", new BasicTypeValidator( "INT8U" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { Long v; try { v = new Long( value ); @@ -137,7 +137,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "INT16U", new BasicTypeValidator( "INT16U" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { Long v; try { v = new Long( value ); @@ -153,7 +153,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "INT32U", new BasicTypeValidator( "INT32U" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { Long v; try { v = new Long( value ); @@ -169,7 +169,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "FLOAT32", new BasicTypeValidator( "FLOAT32" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { try { new Float( value ); } @@ -184,7 +184,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "Octet64", new BasicTypeValidator( "Octet64" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { return addDiagnosticErrorIfTrue( value.getBytes().length > 64, value, da, diagnostics ); } @@ -193,7 +193,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "VisString64", new BasicTypeValidator( "VisString64" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO: what is a VisString ? return addDiagnosticErrorIfTrue( value.getBytes().length > 64, value, da, diagnostics ); } @@ -203,7 +203,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "VisString129", new BasicTypeValidator( "VisString129" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO: what is a VisString ? return addDiagnosticErrorIfTrue( value.getBytes().length > 129, value, da, diagnostics ); } @@ -213,7 +213,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "VisString255", new BasicTypeValidator( "VisString255" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO: what is a VisString ? return addDiagnosticErrorIfTrue( value.getBytes().length > 255, value, da, diagnostics ); } @@ -223,7 +223,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "Unicode255", new BasicTypeValidator( "Unicode255" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO: how do we handle Unicode ? return addDiagnosticErrorIfTrue( value.getBytes().length > 255, value, da, diagnostics ); } @@ -233,7 +233,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "PhyComAddr", new BasicTypeValidator( "PhyComAddr" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO return addDiagnosticWarningNotImplemented( value, da, diagnostics ); } @@ -243,7 +243,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "ObjRef", new BasicTypeValidator( "ObjRef" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO return addDiagnosticWarningNotImplemented( value, da, diagnostics ); } @@ -253,7 +253,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "EntryID", new BasicTypeValidator( "EntryID" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO return addDiagnosticWarningNotImplemented( value, da, diagnostics ); } @@ -280,7 +280,7 @@ public abstract class BasicTypeValidator extends TypeValidator { "XPD", "XPF", "XPT", "XSU", "XTS", "XUA", "XXX", "YER", "ZAR", "ZMW", "ZWL", "XXX" )); @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO: what means "The concrete coding shall be defined by the SCSMs." ? return addDiagnosticErrorIfTrue( ! ISO_4217_3_characterCurrencyCode.contains( value ), value, da, diagnostics ); } @@ -290,7 +290,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "Timestamp", new BasicTypeValidator( "Timestamp" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO return addDiagnosticWarningNotImplemented( value, da, diagnostics ); } @@ -300,7 +300,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "Quality", new BasicTypeValidator( "Quality" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO return addDiagnosticWarningNotImplemented( value, da, diagnostics ); } @@ -310,7 +310,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "EntryTime", new BasicTypeValidator( "EntryTime" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO return addDiagnosticWarningNotImplemented( value, da, diagnostics ); } @@ -320,7 +320,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "TrgOps", new BasicTypeValidator( "TrgOps" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO return addDiagnosticWarningNotImplemented( value, da, diagnostics ); } @@ -330,7 +330,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "OptFlds", new BasicTypeValidator( "OptFlds" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO return addDiagnosticWarningNotImplemented( value, da, diagnostics ); } @@ -340,7 +340,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "SvOptFlds", new BasicTypeValidator( "SvOptFlds" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO return addDiagnosticWarningNotImplemented( value, da, diagnostics ); } @@ -350,7 +350,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "Check", new BasicTypeValidator( "Check" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO return addDiagnosticWarningNotImplemented( value, da, diagnostics ); } @@ -360,7 +360,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "Tcmd", new BasicTypeValidator( "Tcmd" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO return addDiagnosticWarningNotImplemented( value, da, diagnostics ); } @@ -370,7 +370,7 @@ public abstract class BasicTypeValidator extends TypeValidator { validators.put( "Dbpos", new BasicTypeValidator( "Dbpos" ) { @Override - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ) { // TODO return addDiagnosticWarningNotImplemented( value, da, diagnostics ); } @@ -390,34 +390,32 @@ public abstract class BasicTypeValidator extends TypeValidator { } @Override - public boolean validateDA( DA da, DiagnosticChain diagnostics ) { - AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] BasicTypeValidator.validateDA( " + da.getName() + " ) at line " + da.getLineNumber() ); + public boolean validateAbstractDataAttribute( AbstractDataAttribute ada, DiagnosticChain diagnostics ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] BasicTypeValidator.validateDA( " + ada.getName() + " ) at line " + ada.getLineNumber() ); boolean res = true; - if( ! getName().equals( da.getBType() )) { + if( ! getName().equals( ada.getBType() )) { diagnostics.add( new BasicDiagnostic( Diagnostic.ERROR, RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, - "[NSD validation] type of DA " + da.getName() + " in DOType (id = " + da.getParentDOType().getId() - + ", line = " + da.getParentDOType().getLineNumber() + ") is not " + getName(), - new Object[] { da } )); + "[NSD validation] type of DA/BDA " + ada.getName() + " line = " + ada.getLineNumber() + ") is not " + getName(), + new Object[] { ada } )); res = false; } - for( Val val : da.getVal() ) { - res = validateValue( da, val.getValue(), diagnostics ) && res; + for( Val val : ada.getVal() ) { + res = validateValue( ada, val.getValue(), diagnostics ) && res; } return res; } - protected boolean addDiagnosticErrorIfTrue( boolean condition, String value, DA da, DiagnosticChain diagnostics ) { + protected boolean addDiagnosticErrorIfTrue( boolean condition, String value, AbstractDataAttribute da, DiagnosticChain diagnostics ) { if( condition ) { diagnostics.add( new BasicDiagnostic( Diagnostic.ERROR, RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, - "[NSD validation] value " + value + " of Val in DA " + da + " in DOType (id = " + da.getParentDOType().getId() - + ", line = " + da.getParentDOType().getLineNumber() + ") is not a valid " + getName() + " value", + "[NSD validation] value " + value + " of Val in DA/BDA " + da + " line = " + da.getLineNumber() + ") is not a valid " + getName() + " value", new Object[] { da } )); return false; @@ -425,17 +423,16 @@ public abstract class BasicTypeValidator extends TypeValidator { return true; } - protected boolean addDiagnosticWarningNotImplemented( String value, DA da, DiagnosticChain diagnostics ) { + protected boolean addDiagnosticWarningNotImplemented( String value, AbstractDataAttribute da, DiagnosticChain diagnostics ) { diagnostics.add( new BasicDiagnostic( Diagnostic.WARNING, RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, - "[NSD validation] verification of value " + value + " of Val in DA " + da + " in DOType (id = " + da.getParentDOType().getId() - + ", line = " + da.getParentDOType().getLineNumber() + ") is not implemented for BasicType " + getName(), + "[NSD validation] verification of value " + value + " of Val in DA/BDA " + da + " line = " + da.getLineNumber() + ") is not implemented for BasicType " + getName(), new Object[] { da } )); return true; } - protected abstract boolean validateValue( DA da, String value, DiagnosticChain diagnostics ); + protected abstract boolean validateValue( AbstractDataAttribute da, String value, DiagnosticChain diagnostics ); } diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/CDCValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/CDCValidator.java index 53d9a37708fd75b6701ebecce6ed27d229321dba..f57a6dcb4a57ea392bdd021eb61b3adc7a97447c 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/CDCValidator.java +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/CDCValidator.java @@ -101,10 +101,11 @@ public class CDCValidator { for( DA da : doType.getDA() ) { TypeValidator validator = dataAttributeValidatorMap.get( da.getName() ); if( validator != null ) { - validator.validateDA( da, diagnostics ); + validator.validateAbstractDataAttribute( da, diagnostics ); } else { - AbstractRiseClipseConsole.getConsole().warning( "[NSD validation] while validating DOType (line " + doType.getLineNumber() + "): validator for DA " + da.getName() + " not found" ); + // DA not allowed, error will be reported by PresenceConditionValidator + //AbstractRiseClipseConsole.getConsole().warning( "[NSD validation] while validating DOType (line " + doType.getLineNumber() + "): validator for DA " + da.getName() + " not found" ); } } @@ -112,7 +113,6 @@ public class CDCValidator { CDCValidator validator = subDataObjectValidatorMap.get( sdo.getName() ); if( validator != null ) { if( sdo.getRefersToDOType() != null ) { - AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validateDOType( " + doType.getId() + " ) on sdo " + sdo.getName() ); res = validator.validateDOType( sdo.getRefersToDOType(), diagnostics ) && res; } else { diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/ConstructedAttributeValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/ConstructedAttributeValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..1cdbe9dbfbc2e6d6f97b0d49e490760e6133d307 --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/ConstructedAttributeValidator.java @@ -0,0 +1,91 @@ +/** + * Copyright (c) 2019 CentraleSupélec & EDF. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * This file is part of the RiseClipse tool + * + * Contributors: + * Computer Science Department, CentraleSupélec + * EDF R&D + * Contacts: + * dominique.marcadet@centralesupelec.fr + * aurelie.dehouck-neveu@edf.fr + * Web site: + * http://wdi.supelec.fr/software/RiseClipse/ + */ +package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd; + +import java.util.HashMap; +import java.util.HashSet; + +import org.eclipse.emf.common.util.DiagnosticChain; + +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.ConstructedAttribute; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.SubDataAttribute; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.AbstractDataAttribute; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.BDA; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DAType; +import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole; + +public class ConstructedAttributeValidator extends TypeValidator { + + private SubDataAttributePresenceConditionValidator subDataAttributePresenceConditionValidator; + private HashMap< String, TypeValidator > subDataAttributeValidatorMap = new HashMap<>(); + private HashSet< DAType > validatedDAType = new HashSet<>(); + + public ConstructedAttributeValidator( ConstructedAttribute contructedAttribute ) { + subDataAttributePresenceConditionValidator = SubDataAttributePresenceConditionValidator.get( contructedAttribute ); + + for( SubDataAttribute sda : contructedAttribute.getSubDataAttribute() ) { + TypeValidator validator = TypeValidator.get( sda.getType() ); + if( validator != null ) { + subDataAttributeValidatorMap.put( sda.getName(), validator ); + } + else { + AbstractRiseClipseConsole.getConsole().warning( "[NSD setup] Type not found for DataAttribute " + sda.getName() ); + } + } + } + + @Override + public boolean validateAbstractDataAttribute( AbstractDataAttribute da, DiagnosticChain diagnostics ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] ConstructedAttributeValidator.validateBDA( " + da.getName() + " ) at line " + da.getLineNumber() ); + boolean res = true; + + if( da.getRefersToDAType() != null ) { + res = validateDAType( da.getRefersToDAType(), diagnostics ) && res; + } + return res; + } + + private boolean validateDAType( DAType daType, DiagnosticChain diagnostics ) { + if( validatedDAType.contains( daType )) return true; + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] ConstructedAttributeValidator.validateDAType( " + daType.getId() + " ) at line " + daType.getLineNumber() ); + validatedDAType.add( daType ); + + subDataAttributePresenceConditionValidator.reset(); + daType + .getBDA() + .stream() + .forEach( bda -> subDataAttributePresenceConditionValidator.addBDA( bda, diagnostics )); + + boolean res = subDataAttributePresenceConditionValidator.validate( daType, diagnostics ); + + for( BDA bda : daType.getBDA() ) { + TypeValidator validator = subDataAttributeValidatorMap.get( bda.getName() ); + if( validator != null ) { + validator.validateAbstractDataAttribute( bda, diagnostics ); + } + else { + // BDA not allowed, error will be reported by PresenceConditionValidator + //AbstractRiseClipseConsole.getConsole().warning( "[NSD validation] while validating DAType (line " + daType.getLineNumber() + "): validator for BDA " + bda.getName() + " not found" ); + } + } + + return res; + } + +} diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DataAttributePresenceConditionValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DataAttributePresenceConditionValidator.java index 1ef79a842f99bf06b9bd609e3277aa163dea6046..1e18a8d20a35b4c595dc5d158ce16a5fe19c0896 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DataAttributePresenceConditionValidator.java +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DataAttributePresenceConditionValidator.java @@ -496,42 +496,42 @@ public class DataAttributePresenceConditionValidator { if( mandatoryIfSiblingPresentElseForbidden != null ) { for( Entry< String, String > e : mandatoryIfSiblingPresentElseForbidden.entrySet() ) { if( ! presentDA.containsKey( e.getValue() )) { - console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" ); + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataAttribute " + e.getKey() + " is unknown" ); } } } if( mandatoryIfSiblingPresentElseOptional != null ) { for( Entry< String, String > e : mandatoryIfSiblingPresentElseOptional.entrySet() ) { if( ! presentDA.containsKey( e.getValue() )) { - console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" ); + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataAttribute " + e.getKey() + " is unknown" ); } } } if( optionalIfSiblingPresentElseMandatory != null ) { for( Entry< String, String > e : optionalIfSiblingPresentElseMandatory.entrySet() ) { if( ! presentDA.containsKey( e.getValue() )) { - console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" ); + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataAttribute " + e.getKey() + " is unknown" ); } } } if( forbiddenIfSiblingPresentElseMandatory != null ) { for( Entry< String, String > e : forbiddenIfSiblingPresentElseMandatory.entrySet() ) { if( ! presentDA.containsKey( e.getValue() )) { - console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" ); + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataAttribute " + e.getKey() + " is unknown" ); } } } if( oneOrMoreIfSiblingPresentElseForbidden != null ) { for( Entry< String, String > e : oneOrMoreIfSiblingPresentElseForbidden.entrySet() ) { if( ! presentDA.containsKey( e.getValue() )) { - console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" ); + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataAttribute " + e.getKey() + " is unknown" ); } } } if( optionalIfSiblingPresentElseForbidden != null ) { for( Entry< String, String > e : optionalIfSiblingPresentElseForbidden.entrySet() ) { if( ! presentDA.containsKey( e.getValue() )) { - console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" ); + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataAttribute " + e.getKey() + " is unknown" ); } } } diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/EnumerationValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/EnumerationValidator.java index b4b7205ecf458b8cfff2bb76f8773f4cdfcfc79b..4e309c582a1d1a98f44056f9bb87973826622a99 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/EnumerationValidator.java +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/EnumerationValidator.java @@ -26,7 +26,7 @@ import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.DiagnosticChain; import fr.centralesupelec.edf.riseclipse.iec61850.nsd.Enumeration; -import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.AbstractDataAttribute; import fr.centralesupelec.edf.riseclipse.iec61850.scl.EnumType; import fr.centralesupelec.edf.riseclipse.iec61850.scl.EnumVal; import fr.centralesupelec.edf.riseclipse.iec61850.scl.Val; @@ -56,8 +56,8 @@ public class EnumerationValidator extends TypeValidator { } @Override - public boolean validateDA( DA da, DiagnosticChain diagnostics ) { - AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] EnumerationValidator.validateDA( " + da.getName() + " ) at line " + da.getLineNumber() ); + public boolean validateAbstractDataAttribute( AbstractDataAttribute ada, DiagnosticChain diagnostics ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] EnumerationValidator.validateAbstractDataAttribute( " + ada.getName() + " ) at line " + ada.getLineNumber() ); if(( inheritedFromName != null ) && ( inheritedFrom == null )) { TypeValidator inheritedValidator = TypeValidator.get( inheritedFromName ); @@ -70,59 +70,56 @@ public class EnumerationValidator extends TypeValidator { RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, "[NSD validation] validator for inherited enumeration " + inheritedFromName + " not found", - new Object[] { da } )); + new Object[] { ada } )); // Avoid checking again inheritedFromName = null; } } boolean res = true; - if( ! "Enum".equals( da.getBType() )) { + if( ! "Enum".equals( ada.getBType() )) { diagnostics.add( new BasicDiagnostic( Diagnostic.ERROR, RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, - "[NSD validation] bType of DA " + da.getName() + " in DOType (id = " + da.getParentDOType().getId() - + ", line = " + da.getParentDOType().getLineNumber() + ") is not Enum", - new Object[] { da } )); + "[NSD validation] bType of DA/BDA " + ada.getName() + " line = " + ada.getLineNumber() + ") is not Enum", + new Object[] { ada } )); res = false; } - if( ! getName().equals( da.getType() )) { + if( ! getName().equals( ada.getType() )) { diagnostics.add( new BasicDiagnostic( Diagnostic.ERROR, RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, - "[NSD validation] type of DA " + da.getName() + " in DOType (id = " + da.getParentDOType().getId() - + ", line = " + da.getParentDOType().getLineNumber() + ") is not " + getName(), - new Object[] { da } )); + "[NSD validation] type of DA/BDA " + ada.getName() + " line = " + ada.getLineNumber() + ") is not " + getName(), + new Object[] { ada } )); res = false; } - for( Val val : da.getVal() ) { - res = validateValue( da, val.getValue(), diagnostics ) && res; + for( Val val : ada.getVal() ) { + res = validateValue( ada, val.getValue(), diagnostics ) && res; } - if( da.getRefersToEnumType() != null ) { - res = validateEnumType( da.getRefersToEnumType(), diagnostics ) && res; + if( ada.getRefersToEnumType() != null ) { + res = validateEnumType( ada.getRefersToEnumType(), diagnostics ) && res; } return res; } - protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) { + protected boolean validateValue( AbstractDataAttribute ada, String value, DiagnosticChain diagnostics ) { boolean res = true; if( ! literals.containsKey( value )) { if( inheritedFrom != null ) { - res = inheritedFrom.validateValue( da, value, diagnostics ) && res; + res = inheritedFrom.validateValue( ada, value, diagnostics ) && res; } else { diagnostics.add( new BasicDiagnostic( Diagnostic.ERROR, RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, - "[NSD validation] value of DA " + da.getName() + " in DOType (id = " + da.getParentDOType().getId() - + ", line = " + da.getParentDOType().getLineNumber() + ") is not valid", - new Object[] { da } )); + "[NSD validation] value of DA/BDA " + ada.getName() + " line = " + ada.getLineNumber() + ") is not valid", + new Object[] { ada } )); res = false; } } @@ -150,21 +147,36 @@ public class EnumerationValidator extends TypeValidator { RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, "[NSD validation] EnumVal " + enumVal.getValue() + " in EnumType (id = " + enumType.getId() - + " at line " + enumVal.getLineNumber() + " is unknown", + + ") at line " + enumVal.getLineNumber() + " is unknown", new Object[] { enumVal } )); res = false; } } - else if( literals.get( enumVal.getValue() ).equals( enumVal.getOrd() )) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] EnumVal " + enumVal.getValue() + " in EnumType (id = " + enumType.getId() - + " at line " + enumVal.getLineNumber() + " has incorrect ord (" + enumVal.getOrd() - + " instead of " + literals.get( enumVal.getValue() ), - new Object[] { enumVal } )); - res = false; + else { + try { + Integer val = new Integer( literals.get( enumVal.getValue() )); + if( ! val.equals( enumVal.getOrd() )) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] EnumVal " + enumVal.getValue() + " in EnumType (id = " + enumType.getId() + + ") at line " + enumVal.getLineNumber() + " has incorrect ord (" + enumVal.getOrd() + + " instead of " + literals.get( enumVal.getValue() ) + ")", + new Object[] { enumVal } )); + res = false; + } + } + catch( NumberFormatException e ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] EnumVal " + enumVal.getValue() + " in EnumType (id = " + enumType.getId() + + ") at line " + enumVal.getLineNumber() + " is not an integer", + new Object[] { enumVal } )); + res = false; + } } } diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataAttributePresenceConditionValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataAttributePresenceConditionValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..37f5d83f0f522e9b0de47516835635ad96a7c25e --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataAttributePresenceConditionValidator.java @@ -0,0 +1,1377 @@ +/** + * Copyright (c) 2019 CentraleSupélec & EDF. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * This file is part of the RiseClipse tool + * + * Contributors: + * Computer Science Department, CentraleSupélec + * EDF R&D + * Contacts: + * dominique.marcadet@centralesupelec.fr + * aurelie.dehouck-neveu@edf.fr + * Web site: + * http://wdi.supelec.fr/software/RiseClipse/ + */ +package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map.Entry; + +import org.apache.commons.lang3.tuple.Pair; +import org.eclipse.emf.common.util.BasicDiagnostic; +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.common.util.DiagnosticChain; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.ConstructedAttribute; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.BDA; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DAType; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL; +import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole; +import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole; + +public class SubDataAttributePresenceConditionValidator { + + private static HashMap< String, SubDataAttributePresenceConditionValidator > validators = new HashMap<>(); + + public static SubDataAttributePresenceConditionValidator get( ConstructedAttribute constructedAttribute ) { + if( ! validators.containsKey( constructedAttribute.getName() )) { + validators.put( constructedAttribute.getName(), new SubDataAttributePresenceConditionValidator( constructedAttribute )); + } + return validators.get( constructedAttribute.getName() ); + } + + private ConstructedAttribute constructedAttribute; + + // Name of the SubDataAttribute/BDA, BDA + private HashMap< String, BDA > presentBDA = new HashMap<>(); + + private HashSet< String > mandatory; + private HashSet< String > optional; + private HashSet< String > forbidden; + private HashSet< String > notApplicable; + private HashSet< String > mandatoryMulti; + private HashSet< String > optionalMulti; + private HashMap< Integer, HashSet< String > > atLeastOne; + private HashSet< String > atMostOne; + private HashMap< Integer, HashSet< String > > allOrNonePerGroup; + private HashMap< Integer, HashSet< String > > allOnlyOneGroup; + private HashMap< Integer, HashSet< String > > allAtLeastOneGroup; + private HashMap< String, String > mandatoryIfSiblingPresentElseForbidden; + private HashMap< String, String > mandatoryIfSiblingPresentElseOptional; + private HashMap< String, String > optionalIfSiblingPresentElseMandatory; + private HashMap< String, String > forbiddenIfSiblingPresentElseMandatory; + private HashMap< String, String > mandatoryIfTextConditionElseOptional; + private HashMap< String, String > mandatoryIfTextConditionElseForbidden; + private HashMap< String, String > optionalIfTextConditionElseForbidden; + private HashMap< String, Pair< Integer, Integer > > mandatoryMultiRange; + private HashMap< String, Pair< Integer, Integer > > optionalMultiRange; + private HashSet< String > mandatoryIfSubstitutionElseForbidden; + private HashSet< String > mandatoryInLLN0ElseOptional; + private HashSet< String > mandatoryInLLN0ElseForbidden; + private HashSet< String > mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional; + private HashSet< String > mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional; + private HashSet< String > mandatoryIfAnalogValueIncludesIElseForbidden; + private HashSet< String > mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden; + private HashSet< String > mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden; + private HashSet< String > mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional; + private HashSet< String > mandatoryInRootLogicalDeviceElseOptional; + private HashSet< String > mandatoryIfControlSupportsTimeElseOptional; + private HashMap< String, String > oneOrMoreIfSiblingPresentElseForbidden; + private HashSet< String > mandatoryIfControlSupportsSecurity1ElseOptional; + private HashSet< String > mandatoryIfControlSupportsSecurity2ElseOptional; + private HashMap< String, String > optionalIfSiblingPresentElseForbidden; + private HashSet< String > mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2; + private HashSet< String > mandatoryIfMeasuredValueExposesRange; + private HashSet< String > optionalIfPhsRefIsSynchrophasorElseMandatory; + + private final IRiseClipseConsole console = AbstractRiseClipseConsole.getConsole(); + + public SubDataAttributePresenceConditionValidator( ConstructedAttribute constructedAttribute ) { + this.constructedAttribute = constructedAttribute; + + constructedAttribute + .getSubDataAttribute() + .stream() + .forEach( sda -> addSpecification( sda.getName(), sda.getPresCond(), sda.getPresCondArgs() ) ); + + checkSpecification(); + } + + public void reset() { + for( String bda : presentBDA.keySet() ) { + presentBDA.put( bda, null ); + } + } + + private void addSpecification( String name, String presCond, String presCondArgs ) { + if( presentBDA.containsKey( name )) { + console.warning( "[NSD setup] " + name + " has already been added to SubDataAttributePresenceConditionValidator" ); + return; + } + presentBDA.put( name, null ); + + switch( presCond ) { + case "M" : + // Element is mandatory + if( mandatory == null ) mandatory = new HashSet<>(); + mandatory.add( name ); + break; + case "O" : + // Element is optional + if( optional == null ) optional = new HashSet<>(); + optional.add( name ); + break; + case "F" : + // Element is forbidden + if( forbidden == null ) forbidden = new HashSet<>(); + forbidden.add( name ); + break; + case "na" : + // Element is not applicable + // -> TODO: what does it mean ? what do we have to check ? + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"na\" in PresenceCondition" ); + if( notApplicable == null ) notApplicable = new HashSet<>(); + notApplicable.add( name ); + break; + case "Mmulti" : + // At least one element shall be present; all instances have an instance number > 0 + // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"Mmulti\" in PresenceCondition" ); + if( mandatoryMulti == null ) mandatoryMulti = new HashSet<>(); + mandatoryMulti.add( name ); + break; + case "Omulti" : + // Zero or more elements may be present; all instances have an instance number > 0 + // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"Omulti\" in PresenceCondition" ); + if( optionalMulti == null ) optionalMulti = new HashSet<>(); + optionalMulti.add( name ); + break; + case "AtLeastOne" : + // Parameter n: group number (> 0). + // At least one of marked elements of a group n shall be present + if( atLeastOne == null ) atLeastOne = new HashMap<>(); + try { + Integer arg = Integer.valueOf( presCondArgs ); + if( arg <= 0 ) { + console.warning( "[NSD setup] argument of PresenceCondition \"AtLeastOne\" is not a positive integer" ); + break; + } + if( ! atLeastOne.containsKey( arg )) { + atLeastOne.put( arg, new HashSet<>() ); + } + atLeastOne.get( arg ).add( name ); + break; + } + catch( NumberFormatException e ) { + console.warning( "[NSD setup] argument of PresenceCondition \"AtLeastOne\" is not an integer" ); + break; + } + case "AtMostOne" : + // At most one of marked elements shall be present + if( atMostOne == null ) atMostOne = new HashSet<>(); + atMostOne.add( name ); + break; + case "AllOrNonePerGroup" : + // Parameter n: group number (> 0). + // All or none of the elements of a group n shall be present + if( allOrNonePerGroup == null ) allOrNonePerGroup = new HashMap<>(); + try { + Integer arg = Integer.valueOf( presCondArgs ); + if( arg <= 0 ) { + console.warning( "[NSD setup] argument of PresenceCondition \"AllOrNonePerGroup\" is not a positive integer" ); + break; + } + if( ! allOrNonePerGroup.containsKey( arg )) { + allOrNonePerGroup.put( arg, new HashSet<>() ); + } + allOrNonePerGroup.get( arg ).add( name ); + break; + } + catch( NumberFormatException e ) { + console.warning( "[NSD setup] argument of PresenceCondition \"AllOrNonePerGroup\" is not an integer" ); + break; + } + case "AllOnlyOneGroup" : + // Parameter n: group number (> 0). + // All elements of only one group n shall be present + if( allOnlyOneGroup == null ) allOnlyOneGroup = new HashMap<>(); + try { + Integer arg = Integer.valueOf( presCondArgs ); + if( arg <= 0 ) { + console.warning( "[NSD setup] argument of PresenceCondition \"AllOnlyOneGroup\" is not a positive integer" ); + break; + } + if( ! allOnlyOneGroup.containsKey( arg )) { + allOnlyOneGroup.put( arg, new HashSet<>() ); + } + allOnlyOneGroup.get( arg ).add( name ); + break; + } + catch( NumberFormatException e ) { + console.warning( "[NSD setup] argument of PresenceCondition \"AllOnlyOneGroup\" is not an integer" ); + break; + } + case "AllAtLeastOneGroup" : + // Parameter n: group number (> 0). + // All elements of at least one group n shall be present + if( allAtLeastOneGroup == null ) allAtLeastOneGroup = new HashMap<>(); + try { + Integer arg = Integer.valueOf( presCondArgs ); + if( arg <= 0 ) { + console.warning( "[NSD setup] argument of PresenceCondition \"AllAtLeastOneGroup\" is not a positive integer" ); + break; + } + if( ! allAtLeastOneGroup.containsKey( arg )) { + allAtLeastOneGroup.put( arg, new HashSet<>() ); + } + allAtLeastOneGroup.get( arg ).add( name ); + break; + } + catch( NumberFormatException e ) { + console.warning( "[NSD setup] argument of PresenceCondition \"AllAtLeastOneGroup\" is not an integer" ); + break; + } + case "MF" : + // Parameter sibling: sibling element name. + // Mandatory if sibling element is present, otherwise forbidden + if( mandatoryIfSiblingPresentElseForbidden == null ) mandatoryIfSiblingPresentElseForbidden = new HashMap<>(); + mandatoryIfSiblingPresentElseForbidden.put( name, presCondArgs ); + break; + case "MO" : + // Parameter sibling: sibling element name. + // Mandatory if sibling element is present, otherwise optional + if( mandatoryIfSiblingPresentElseOptional == null ) mandatoryIfSiblingPresentElseOptional = new HashMap<>(); + mandatoryIfSiblingPresentElseOptional.put( name, presCondArgs ); + break; + case "OM" : + // Parameter sibling: sibling element name. + // Optional if sibling element is present, otherwise mandatory + if( optionalIfSiblingPresentElseMandatory == null ) optionalIfSiblingPresentElseMandatory = new HashMap<>(); + optionalIfSiblingPresentElseMandatory.put( name, presCondArgs ); + break; + case "FM" : + // Parameter sibling: sibling element name. + // Forbidden if sibling element is present, otherwise mandatory + if( forbiddenIfSiblingPresentElseMandatory == null ) forbiddenIfSiblingPresentElseMandatory = new HashMap<>(); + forbiddenIfSiblingPresentElseMandatory.put( name, presCondArgs ); + break; + case "MOcond" : + // Parameter condID: condition number (> 0). + // Textual presence condition (non-machine processable) with reference condID to context specific text. + // If satisfied, the element is mandatory, otherwise optional + if( mandatoryIfTextConditionElseOptional == null ) mandatoryIfTextConditionElseOptional = new HashMap<>(); + try { + Integer arg = Integer.valueOf( presCondArgs ); + if( arg <= 0 ) { + console.warning( "[NSD setup] argument of PresenceCondition \"MOcond\" is not a positive integer" ); + break; + } + mandatoryIfTextConditionElseOptional.put( name, presCondArgs ); + break; + } + catch( NumberFormatException e ) { + console.warning( "[NSD setup] argument of PresenceCondition \"MOcond\" is not an integer" ); + break; + } + case "MFcond" : + // Parameter condID: condition number (> 0). + // Textual presence condition (non-machine processable) with reference condID to context specific text. + // If satisfied, the element is mandatory, otherwise forbidden + if( mandatoryIfTextConditionElseForbidden == null ) mandatoryIfTextConditionElseForbidden = new HashMap<>(); + try { + Integer arg = Integer.valueOf( presCondArgs ); + if( arg <= 0 ) { + console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not a positive integer" ); + break; + } + mandatoryIfTextConditionElseForbidden.put( name, presCondArgs ); + break; + } + catch( NumberFormatException e ) { + console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not an integer" ); + break; + } + case "OFcond" : + // Parameter condID: condition number (> 0). + // Textual presence condition (non-machine processable) with reference condID to context specific text. + // If satisfied, the element is optional, otherwise forbidden + if( optionalIfTextConditionElseForbidden == null ) optionalIfTextConditionElseForbidden = new HashMap<>(); + try { + Integer arg = Integer.valueOf( presCondArgs ); + if( arg <= 0 ) { + console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not a positive integer" ); + break; + } + optionalIfTextConditionElseForbidden.put( name, presCondArgs ); + break; + } + catch( NumberFormatException e ) { + console.warning( "[NSD setup] argument of PresenceCondition \"MFcond\" is not an integer" ); + break; + } + case "MmultiRange" : + // Parameters min, max: limits for instance number (> 0). + // One or more elements shall be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1) + // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MmultiRange\" in PresenceCondition" ); + if( mandatoryMultiRange == null ) mandatoryMultiRange = new HashMap<>(); + String[] limits1 = presCondArgs.split( "[ ,]+" ); + if( limits1.length != 2 ) { + console.warning( "[NSD setup] argument of PresenceCondition \"MmultiRange\" is not two integers" ); + break; + } + Integer min1 = Integer.valueOf( limits1[0] ); + if( min1 <= 0 ) { + console.warning( "[NSD setup] first argument of PresenceCondition \"MmultiRange\" is not a positive integer" ); + break; + } + Integer max1 = Integer.valueOf( limits1[1] ); + if( max1 <= 0 ) { + console.warning( "[NSD setup] second argument of PresenceCondition \"MmultiRange\" is not a positive integer" ); + break; + } + mandatoryMultiRange.put( name, Pair.of( min1, max1 )); + break; + case "OmultiRange" : + // Parameters min, max: limits for instance number (> 0). + // Zero or more elements may be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1) + // -> TODO: not sure what is the instance number, it is assumed to be the suffix of DO name + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"OmultiRange\" in PresenceCondition" ); + if( optionalMultiRange == null ) optionalMultiRange = new HashMap<>(); + String[] limits2 = presCondArgs.split( "[ ,]+" ); + if( limits2.length != 2 ) { + console.warning( "[NSD setup] argument of PresenceCondition \"OmultiRange\" is not two integers" ); + break; + } + Integer min2 = Integer.valueOf( limits2[0] ); + if( min2 <= 0 ) { + console.warning( "[NSD setup] first argument of PresenceCondition \"OmultiRange\" is not a positive integer" ); + break; + } + Integer max2 = Integer.valueOf( limits2[1] ); + if( max2 <= 0 ) { + console.warning( "[NSD setup] second argument of PresenceCondition \"OmultiRange\" is not a positive integer" ); + break; + } + optionalMultiRange.put( name, Pair.of( min2, max2 )); + break; + case "MFsubst" : + // Element is mandatory if substitution is supported (for substitution, see IEC 61850-7-3), otherwise forbidden + // TODO: how do we know if substitution is supported ? + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MFsubst\" in PresenceCondition" ); + if( mandatoryIfSubstitutionElseForbidden == null ) mandatoryIfSubstitutionElseForbidden = new HashSet<>(); + mandatoryIfSubstitutionElseForbidden.add( name ); + break; + case "MOln0" : + // Element is mandatory in the context of LLN0; otherwise optional + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOln0\" in PresenceCondition" ); + if( mandatoryInLLN0ElseOptional == null ) mandatoryInLLN0ElseOptional = new HashSet<>(); + mandatoryInLLN0ElseOptional.add( name ); + break; + case "MFln0" : + // Element is mandatory in the context of LLN0; otherwise forbidden + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MFln0\" in PresenceCondition" ); + if( mandatoryInLLN0ElseForbidden == null ) mandatoryInLLN0ElseForbidden = new HashSet<>(); + mandatoryInLLN0ElseForbidden.add( name ); + break; + case "MOlnNs" : + // Element is mandatory if the name space of its logical node deviates from the name space of the containing + // logical device, otherwise optional. See IEC 61850-7-1 for use of name space + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOlnNs\" in PresenceCondition" ); + if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional == null ) mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional = new HashSet<>(); + mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional.add( name ); + break; + case "MOdataNs" : + // Element is mandatory if the name space of its data object deviates from the name space of its logical node, + // otherwise optional. See IEC 61850-7-1 for use of name space + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOdataNs\" in PresenceCondition" ); + if( mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional == null ) mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional = new HashSet<>(); + mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional.add( name ); + break; + case "MFscaledAV" : + // Element is mandatory* if any sibling elements of type AnalogueValue include 'i' as a child, otherwise forbidden. + // *Even though devices without floating point capability cannot exchange floating point values through ACSI services, + // the description of scaling remains mandatory for their (SCL) configuration + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MFscaledAV\" in PresenceCondition" ); + if( mandatoryIfAnalogValueIncludesIElseForbidden == null ) mandatoryIfAnalogValueIncludesIElseForbidden = new HashSet<>(); + mandatoryIfAnalogValueIncludesIElseForbidden.add( name ); + break; + case "MFscaledMagV" : + // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'mag' attribute, otherwise forbidden. + // *See MFscaledAV + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MFscaledMagV\" in PresenceCondition" ); + if( mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden == null ) mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden = new HashSet<>(); + mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden.add( name ); + break; + case "MFscaledAngV" : + // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'ang' attribute, otherwise forbidden. + // *See MFscaledAV + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MFscaledAngV\" in PresenceCondition" ); + if( mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden == null ) mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden = new HashSet<>(); + mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden.add( name ); + break; + case "MOrms" : + // Element is mandatory if the harmonic values in the context are calculated as a ratio to RMS value + // (value of data attribute 'hvRef' is 'rms'), optional otherwise + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOrms\" in PresenceCondition" ); + if( mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional == null ) mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional = new HashSet<>(); + mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional.add( name ); + break; + case "MOrootLD" : + // Element is mandatory in the context of a root logical device; otherwise it is optional + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOrootLD\" in PresenceCondition" ); + if( mandatoryInRootLogicalDeviceElseOptional == null ) mandatoryInRootLogicalDeviceElseOptional = new HashSet<>(); + mandatoryInRootLogicalDeviceElseOptional.add( name ); + break; + case "MOoperTm" : + // Element is mandatory if at least one controlled object on the IED supports time activation service; otherwise it is optional + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOoperTm\" in PresenceCondition" ); + if( mandatoryIfControlSupportsTimeElseOptional == null ) mandatoryIfControlSupportsTimeElseOptional = new HashSet<>(); + mandatoryIfControlSupportsTimeElseOptional.add( name ); + break; + case "MmultiF" : + // Parameter sibling: sibling element name. + // One or more elements must be present if sibling element is present, otherwise forbidden + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MmultiF\" in PresenceCondition" ); + if( oneOrMoreIfSiblingPresentElseForbidden == null ) oneOrMoreIfSiblingPresentElseForbidden = new HashMap<>(); + oneOrMoreIfSiblingPresentElseForbidden.put( name, presCondArgs ); + break; + case "MOsbo" : + // Element is mandatory if declared control model supports 'sbo-with-normal-security' or 'sbo-with-enhanced-security', + // otherwise optional and value is of no impact + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOsbo\" in PresenceCondition" ); + if( mandatoryIfControlSupportsSecurity1ElseOptional == null ) mandatoryIfControlSupportsSecurity1ElseOptional = new HashSet<>(); + mandatoryIfControlSupportsSecurity1ElseOptional.add( name ); + break; + case "MOenhanced" : + // Element is mandatory if declared control model supports 'direct-with-enhanced-security' or 'sbo-with-enhanced-security', + // otherwise optional and value is of no impact + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MOenhanced\" in PresenceCondition" ); + if( mandatoryIfControlSupportsSecurity2ElseOptional == null ) mandatoryIfControlSupportsSecurity2ElseOptional = new HashSet<>(); + mandatoryIfControlSupportsSecurity2ElseOptional.add( name ); + break; + case "MONamPlt" : + // Element is mandatory if the name space of its logical node deviates from the name space of the containing + // logical device, otherwise optional. See IEC 61850-7-1 for use of name space + // TODO: same as "MOlnNs" ? + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MONamPlt\" in PresenceCondition" ); + if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 == null ) mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 = new HashSet<>(); + mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2.add( name ); + break; + case "OF" : + // Parameter sibling: sibling element name. + // Optional if sibling element is present, otherwise forbidden + if( optionalIfSiblingPresentElseForbidden == null ) optionalIfSiblingPresentElseForbidden = new HashMap<>(); + optionalIfSiblingPresentElseForbidden.put( name, presCondArgs ); + break; + case "MORange" : + // Element is mandatory if the measured value associated (amplitude respectively angle) exposes the range eventing + // (with the attribute range respectively rangeAng) + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"MORange\" in PresenceCondition" ); + if( mandatoryIfMeasuredValueExposesRange == null ) mandatoryIfMeasuredValueExposesRange = new HashSet<>(); + mandatoryIfMeasuredValueExposesRange.add( name ); + break; + case "OMSynPh" : + // This attribute is optional if value of 'phsRef'' is Synchrophasor otherwise Mandatory]]></Doc> + console.warning( "[NSD setup] NOT IMPLEMENTED: SubDataAttribute " + name + " declared as \"OMSynPh\" in PresenceCondition" ); + if( optionalIfPhsRefIsSynchrophasorElseMandatory == null ) optionalIfPhsRefIsSynchrophasorElseMandatory = new HashSet<>(); + optionalIfPhsRefIsSynchrophasorElseMandatory.add( name ); + break; + default: + console.warning( "[NSD setup] the PresenceCondition " + presCond + " of AnyLNClass " + name + " is unknown" ); + break; + } + + } + + private void checkSpecification() { + // TODO: do we have to check the presence of the sibling in inherited AbstractLNClass ? + if( mandatoryIfSiblingPresentElseForbidden != null ) { + for( Entry< String, String > e : mandatoryIfSiblingPresentElseForbidden.entrySet() ) { + if( ! presentBDA.containsKey( e.getValue() )) { + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of SubDataAttribute " + e.getKey() + " is unknown" ); + } + } + } + if( mandatoryIfSiblingPresentElseOptional != null ) { + for( Entry< String, String > e : mandatoryIfSiblingPresentElseOptional.entrySet() ) { + if( ! presentBDA.containsKey( e.getValue() )) { + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of SubDataAttribute " + e.getKey() + " is unknown" ); + } + } + } + if( optionalIfSiblingPresentElseMandatory != null ) { + for( Entry< String, String > e : optionalIfSiblingPresentElseMandatory.entrySet() ) { + if( ! presentBDA.containsKey( e.getValue() )) { + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of SubDataAttribute " + e.getKey() + " is unknown" ); + } + } + } + if( forbiddenIfSiblingPresentElseMandatory != null ) { + for( Entry< String, String > e : forbiddenIfSiblingPresentElseMandatory.entrySet() ) { + if( ! presentBDA.containsKey( e.getValue() )) { + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of SubDataAttribute " + e.getKey() + " is unknown" ); + } + } + } + if( oneOrMoreIfSiblingPresentElseForbidden != null ) { + for( Entry< String, String > e : oneOrMoreIfSiblingPresentElseForbidden.entrySet() ) { + if( ! presentBDA.containsKey( e.getValue() )) { + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of SubDataAttribute " + e.getKey() + " is unknown" ); + } + } + } + if( optionalIfSiblingPresentElseForbidden != null ) { + for( Entry< String, String > e : optionalIfSiblingPresentElseForbidden.entrySet() ) { + if( ! presentBDA.containsKey( e.getValue() )) { + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of SubDataAttribute " + e.getKey() + " is unknown" ); + } + } + } + } + + public boolean addBDA( BDA bda, DiagnosticChain diagnostics ) { + if( ! presentBDA.containsKey( bda.getName() )) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + bda.getName() + " (line " + bda.getLineNumber() + ") not found in ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { bda } )); + return false; + } + + if( presentBDA.get( bda.getName() ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + bda.getName() + " (line " + bda.getLineNumber() + ") already present in ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { bda } )); + return false; + } + presentBDA.put( bda.getName(), bda ); + return true; + } + + public boolean validate( DAType daType, DiagnosticChain diagnostics ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] DataAttributePresenceConditionValidator.validate(id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + + boolean res = true; + + // presCond: "M" + // Element is mandatory + // Usage in standard NSD files (version 2007B): DataObject and DataAttribute and SubDataAttribute + if( mandatory != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"M\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + for( String name : this.mandatory ) { + if( presentBDA.get( name ) == null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + name + " is mandatory in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + res = false; + } + } + } + + // presCond: "O" + // Element is optional + // Usage in standard NSD files (version 2007B): DataObject and DataAttribute and SubDataAttribute + if( optional != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"O\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + for( String name : this.optional ) { + if( presentBDA.get( name ) == null ) { + // Nothing + } + } + } + + // presCond: "F" + // Element is forbidden + // Usage in standard NSD files (version 2007B): DataObject + if( forbidden != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"F\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + for( String name : this.forbidden ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + name + " is forbidden in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + res = false; + } + } + } + + // presCond: "na" + // Element is not applicable + // Usage in standard NSD files (version 2007B): only for dsPresCond + // -> TODO: what does it mean ? what do we have to check ? + if( notApplicable != null ) { + for( String name : notApplicable ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"na\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "Mmulti" + // At least one element shall be present; all instances have an instance number > 0 + // Usage in standard NSD files (version 2007B): DataObject + if( mandatoryMulti != null ) { + for( String name : mandatoryMulti ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"Mmulti\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "Omulti" + // Zero or more elements may be present; all instances have an instance number > 0 + // Usage in standard NSD files (version 2007B): DataObject + if( optionalMulti != null ) { + for( String name : optionalMulti ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"Omulti\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "AtLeastOne" + // Parameter n: group number (> 0). + // At least one of marked elements of a group n shall be present + // Usage in standard NSD files (version 2007B): DataObject and SubDataObject and DataAttribute and SubDataAttribute + if( atLeastOne != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AtLeastOne\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + for( Entry< Integer, HashSet< String > > e1 : atLeastOne.entrySet() ) { + boolean groupOK = false; + for( String member : e1.getValue() ) { + if( presentBDA.get( member ) != null ) { + groupOK = true; + break; + } + } + if( ! groupOK ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] group " + e1.getKey() + " has no elements in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + res = false; + } + } + } + + // presCond: "AtMostOne" : + // At most one of marked elements shall be present + // Usage in standard NSD files (version 2007B): DataObject + if( atMostOne != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AtMostOne\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + int count = 0; + for( String s : atMostOne ) { + if( presentBDA.get( s ) != null ) { + ++count; + } + } + if( count > 1 ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] LNodeType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName() + " has more than one element marked AtMostOne", + new Object[] { daType } )); + res = false; + } + } + + // presCond: "AllOrNonePerGroup" : + // Parameter n: group number (> 0). + // All or none of the elements of a group n shall be present + // Usage in standard NSD files (version 2007B): DataAttribute + if( allOrNonePerGroup != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllOrNonePerGroup\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + for( Entry< Integer, HashSet< String > > e1 : allOrNonePerGroup.entrySet() ) { + int groupCount = 0; + for( String member : e1.getValue() ) { + if( presentBDA.get( member ) != null ) { + ++groupCount; + } + } + if(( groupCount > 0 ) && (groupCount < e1.getValue().size() )) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] group " + e1.getKey() + " has neither none nor all elements in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + res = false; + } + } + } + + // presCond: "AllOnlyOneGroup" : + // Parameter n: group number (> 0). + // All elements of only one group n shall be present + // Usage in standard NSD files (version 2007B): DataObject and SubDataAttribute + if( allOnlyOneGroup != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllOnlyOneGroup\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + int groupNumber = 0; + for( Entry< Integer, HashSet< String > > e1 : allOnlyOneGroup.entrySet() ) { + int groupCount = 0; + for( String member : e1.getValue() ) { + if( presentBDA.get( member ) != null ) { + ++groupCount; + } + } + if(( groupCount > 0 ) && (groupCount < e1.getValue().size() )) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] group " + e1.getKey() + " has neither none nor all elements in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + res = false; + } + else if( groupCount > 0 ) { + if( groupNumber == 0 ) { + groupNumber = e1.getKey(); + } + else { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] LNodeType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName() + " has several groups with all elements", + new Object[] { daType } )); + res = false; + } + } + } + if( groupNumber == 0 ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] no group in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName() + " has all elements", + new Object[] { daType } )); + res = false; + } + } + + // presCond: "AllAtLeastOneGroup" : + // Parameter n: group number (> 0). + // All elements of at least one group n shall be present + // Usage in standard NSD files (version 2007B): DataAttribute + if( allAtLeastOneGroup != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllAtLeastOneGroup\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + int groupNumber = 0; + for( Entry< Integer, HashSet< String > > e1 : allAtLeastOneGroup.entrySet() ) { + int groupCount = 0; + for( String member : e1.getValue() ) { + if( presentBDA.get( member ) != null ) { + ++groupCount; + } + } + if( groupCount == e1.getValue().size() ) { + groupNumber = e1.getKey(); + } + } + if( groupNumber == 0 ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] no group in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName() + " has all elements", + new Object[] { daType } )); + res = false; + } + } + + // presCond: "MF" : + // Parameter sibling: sibling element name. + // Mandatory if sibling element is present, otherwise forbidden + // Usage in standard NSD files (version 2007B): DataObject + if( mandatoryIfSiblingPresentElseForbidden != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MF\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + for( Entry< String, String > entry : mandatoryIfSiblingPresentElseForbidden.entrySet() ) { + if( presentBDA.get( entry.getValue() ) != null ) { + if( presentBDA.get( entry.getKey() ) == null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + entry.getKey() + " is mandatory in DAType (line " + daType.getLineNumber() + ") with LNClass " + + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is present", + new Object[] { daType } )); + res = false; + } + } + else { + if( presentBDA.get( entry.getKey() ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + entry.getKey() + " is forbidden in DAType (line " + daType.getLineNumber() + ") with LNClass " + + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is not present", + new Object[] { daType } )); + res = false; + } + } + } + } + + // presCond: "MO" : + // Parameter sibling: sibling element name. + // Mandatory if sibling element is present, otherwise optional + // Usage in standard NSD files (version 2007B): DataAttribute + if( mandatoryIfSiblingPresentElseOptional != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MO\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + for( Entry< String, String > entry : mandatoryIfSiblingPresentElseOptional.entrySet() ) { + if( presentBDA.get( entry.getValue() ) != null ) { + if( presentBDA.get( entry.getKey() ) == null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + entry.getKey() + " is mandatory in DAType (line " + daType.getLineNumber() + ") with LNClass " + + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is present", + new Object[] { daType } )); + res = false; + } + } + } + } + + // presCond: "OM" : + // Parameter sibling: sibling element name. + // Optional if sibling element is present, otherwise mandatory + // Usage in standard NSD files (version 2007B): None + if( optionalIfSiblingPresentElseMandatory != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OM\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + for( Entry< String, String > entry : optionalIfSiblingPresentElseMandatory.entrySet() ) { + if( presentBDA.get( entry.getValue() ) == null ) { + if( presentBDA.get( entry.getKey() ) == null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + entry.getKey() + " is mandatory in DAType (line " + daType.getLineNumber() + ") with LNClass " + + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is not present", + new Object[] { daType } )); + res = false; + } + } + } + } + + // presCond: "FM" : + // Parameter sibling: sibling element name. + // Forbidden if sibling element is present, otherwise mandatory + // Usage in standard NSD files (version 2007B): None + if( forbiddenIfSiblingPresentElseMandatory != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"FM\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + for( Entry< String, String > entry : forbiddenIfSiblingPresentElseMandatory.entrySet() ) { + if( presentBDA.get( entry.getValue() ) != null ) { + if( presentBDA.get( entry.getKey() ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + entry.getKey() + " is forbidden in DAType (line " + daType.getLineNumber() + ") with LNClass " + + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is present", + new Object[] { daType } )); + res = false; + } + } + else { + if( presentBDA.get( entry.getKey() ) == null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + entry.getKey() + " is mandatory in DAType (line " + daType.getLineNumber() + ") with LNClass " + + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is not present", + new Object[] { daType } )); + res = false; + } + } + } + } + + // presCond: "MOcond" : + // Parameter condID: condition number (> 0). + // Textual presence condition (non-machine processable) with reference condID to context specific text. + // If satisfied, the element is mandatory, otherwise optional + // Usage in standard NSD files (version 2007B): DataObject + if( mandatoryIfTextConditionElseOptional != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MOcond\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + for( Entry< String, String > entry : mandatoryIfTextConditionElseOptional.entrySet() ) { + String doc = constructedAttribute + .getSubDataAttribute() + .stream() + .filter( d -> d.getName().equals( entry.getKey() )) + .findFirst() + .map( x -> x.getRefersToPresCondArgsDoc() ) + .map( p -> p.getMixed() ) + .map( p -> p.get( 0 ) ) + .map( p -> p.getValue() ) + .map( p -> p.toString() ) + .orElse( null ); + + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + entry.getKey() + " is mandatory in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + + constructedAttribute.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else optional. It is " + + ( presentBDA.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ), + new Object[] { daType } )); + } + } + + // presCond: "MFcond" : + // Parameter condID: condition number (> 0). + // Textual presence condition (non-machine processable) with reference condID to context specific text. + // If satisfied, the element is mandatory, otherwise forbidden + // Usage in standard NSD files (version 2007B): DataObject + if( mandatoryIfTextConditionElseForbidden != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MFcond\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + for( Entry< String, String > entry : mandatoryIfTextConditionElseForbidden.entrySet() ) { + String doc = constructedAttribute + .getSubDataAttribute() + .stream() + .filter( d -> d.getName().equals( entry.getKey() )) + .findFirst() + .map( x -> x.getRefersToPresCondArgsDoc() ) + .map( p -> p.getMixed() ) + .map( p -> p.get( 0 ) ) + .map( p -> p.getValue() ) + .map( p -> p.toString() ) + .orElse( null ); + + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + entry.getKey() + " is mandatory in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + + constructedAttribute.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " + + ( presentBDA.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ), + new Object[] { daType } )); + } + } + + // presCond: "OFcond" : + // Parameter condID: condition number (> 0). + // Textual presence condition (non-machine processable) with reference condID to context specific text. + // If satisfied, the element is optional, otherwise forbidden + // Usage in standard NSD files (version 2007B): DataObject + if( optionalIfTextConditionElseForbidden != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OFcond\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + for( Entry< String, String > entry : optionalIfTextConditionElseForbidden.entrySet() ) { + String doc = constructedAttribute + .getSubDataAttribute() + .stream() + .filter( d -> d.getName().equals( entry.getKey() )) + .findFirst() + .map( x -> x.getRefersToPresCondArgsDoc() ) + .map( p -> p.getMixed() ) + .map( p -> p.get( 0 ) ) + .map( p -> p.getValue() ) + .map( p -> p.toString() ) + .orElse( null ); + + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + entry.getKey() + " is optional in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + + constructedAttribute.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " + + ( presentBDA.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ), + new Object[] { daType } )); + } + } + + // presCond: "MmultiRange" : + // Parameters min, max: limits for instance number (> 0). + // One or more elements shall be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1) + // Usage in standard NSD files (version 2007B): None + if( mandatoryMultiRange != null ) { + for( String name : mandatoryMultiRange.keySet() ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MmultiRange\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "OmultiRange" : + // Parameters min, max: limits for instance number (> 0). + // Zero or more elements may be present; all instances have an instance number within range [min, max] (see IEC 61850-7-1) + // Usage in standard NSD files (version 2007B): DataObject + if( optionalMultiRange != null ) { + for( String name : optionalMultiRange.keySet() ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"OmultiRange\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MFsubst" : + // Element is mandatory if substitution is supported (for substitution, see IEC 61850-7-3), otherwise forbidden + // Usage in standard NSD files (version 2007B): DataAttribute + // TODO + if( mandatoryIfSubstitutionElseForbidden != null ) { + for( String name : mandatoryIfSubstitutionElseForbidden ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MFsubst\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MOln0" : + // Element is mandatory in the context of LLN0; otherwise optional + // Usage in standard NSD files (version 2007B): DataAttribute + if( mandatoryInLLN0ElseOptional != null ) { + for( String name : mandatoryInLLN0ElseOptional ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOln0\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MFln0" : + // Element is mandatory in the context of LLN0; otherwise forbidden + // Usage in standard NSD files (version 2007B): DataAttribute + if( mandatoryInLLN0ElseForbidden != null ) { + for( String name : mandatoryInLLN0ElseForbidden ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MFln0\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MOlnNs" : + // Element is mandatory if the name space of its logical node deviates from the name space of the containing + // logical device, otherwise optional. See IEC 61850-7-1 for use of name space + // Usage in standard NSD files (version 2007B): DataAttribute + // TODO: The meaning is not clear. + if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional != null ) { + for( String name : mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOlnNs\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MOdataNs" : + // Element is mandatory if the name space of its data object deviates from the name space of its logical node, + // otherwise optional. See IEC 61850-7-1 for use of name space + // Usage in standard NSD files (version 2007B): DataAttribute + // TODO: The meaning is not clear. + if( mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional != null ) { + for( String name : mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOdataNs\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MFscaledAV" : + // Element is mandatory* if any sibling elements of type AnalogueValue include 'i' as a child, otherwise forbidden. + // *Even though devices without floating point capability cannot exchange floating point values through ACSI services, + // the description of scaling remains mandatory for their (SCL) configuration + // Usage in standard NSD files (version 2007B): DataAttribute + // TODO + if( mandatoryIfAnalogValueIncludesIElseForbidden != null ) { + for( String name : mandatoryIfAnalogValueIncludesIElseForbidden ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MFscaledAV\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MFscaledMagV" : + // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'mag' attribute, otherwise forbidden. + // *See MFscaledAV + // Usage in standard NSD files (version 2007B): DataAttribute + // TODO + if( mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden != null ) { + for( String name : mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MFscaledMagV\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MFscaledAngV" : + // Element is mandatory* if any sibling elements of type Vector include 'i' as a child of their 'ang' attribute, otherwise forbidden. + // *See MFscaledAV + // Usage in standard NSD files (version 2007B): DataAttribute + // TODO + if( mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden != null ) { + for( String name : mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MFscaledAngV\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MOrms" : + // Element is mandatory if the harmonic values in the context are calculated as a ratio to RMS value + // (value of data attribute 'hvRef' is 'rms'), optional otherwise + // Usage in standard NSD files (version 2007B): DataAttribute + // TODO + if( mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional != null ) { + for( String name : mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOrms\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MOrootLD" : + // Element is mandatory in the context of a root logical device; otherwise it is optional + // Usage in standard NSD files (version 2007B): DataObject + if( mandatoryInRootLogicalDeviceElseOptional != null ) { + for( String name : mandatoryInRootLogicalDeviceElseOptional ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOrootLD\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MOoperTm" : + // Element is mandatory if at least one controlled object on the IED supports time activation service; otherwise it is optional + // Usage in standard NSD files (version 2007B): DataAttribute + // TODO + if( mandatoryIfControlSupportsTimeElseOptional != null ) { + for( String name : mandatoryIfControlSupportsTimeElseOptional ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOoperTm\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MmultiF" : + // Parameter sibling: sibling element name. + // One or more elements must be present if sibling element is present, otherwise forbidden + // Usage in standard NSD files (version 2007B): DataObject + // TODO: One or more elements ? Is there an instance number ? + if( oneOrMoreIfSiblingPresentElseForbidden != null ) { + for( String name : oneOrMoreIfSiblingPresentElseForbidden.keySet() ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MmultiF\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MOsbo" : + // Element is mandatory if declared control model supports 'sbo-with-normal-security' or 'sbo-with-enhanced-security', + // otherwise optional and value is of no impact + // Usage in standard NSD files (version 2007B): DataAttribute + // TODO + if( mandatoryIfControlSupportsSecurity1ElseOptional != null ) { + for( String name : mandatoryIfControlSupportsSecurity1ElseOptional ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOsbo\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MOenhanced" : + // Element is mandatory if declared control model supports 'direct-with-enhanced-security' or 'sbo-with-enhanced-security', + // otherwise optional and value is of no impact + // Usage in standard NSD files (version 2007B): DataAttribute + // TODO + if( mandatoryIfControlSupportsSecurity2ElseOptional != null ) { + for( String name : mandatoryIfControlSupportsSecurity2ElseOptional ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOenhanced\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "MONamPlt" : + // Element is mandatory if the name space of its logical node deviates from the name space of the containing + // logical device, otherwise optional. See IEC 61850-7-1 for use of name space + // Usage in standard NSD files (version 2007B): DataObject + // TODO: same as "MOlnNs" ? + if( mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 != null ) { + for( String name : mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2 ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MONamPlt\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "OF" : + // Parameter sibling: sibling element name. + // Optional if sibling element is present, otherwise forbidden + // Usage in standard NSD files (version 2007B): DataObject and DataAttribute + if( optionalIfSiblingPresentElseForbidden != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OF\" on DAType (id=" + daType.getId() + ") at line " + daType.getLineNumber() ); + for( Entry< String, String > entry : optionalIfSiblingPresentElseForbidden.entrySet() ) { + if( presentBDA.get( entry.getValue() ) == null ) { + if( presentBDA.get( entry.getKey() ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] BDA" + entry.getKey() + " is forbidden in DAType (line " + daType.getLineNumber() + ") with LNClass " + + constructedAttribute.getName() + " because sibling " + entry.getValue() + " is not present", + new Object[] { daType } )); + res = false; + } + } + } + } + + // presCond: "MORange" : + // Element is mandatory if the measured value associated (amplitude respectively angle) exposes the range eventing + // (with the attribute range respectively rangeAng) + // Usage in standard NSD files (version 2007B): SubDataAttribute + // TODO + if( mandatoryIfMeasuredValueExposesRange != null ) { + for( String name : mandatoryIfMeasuredValueExposesRange ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MORange\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + // presCond: "OMSynPh" : + // This attribute is optional if value of 'phsRef'' is Synchrophasor otherwise Mandatory]]></Doc> + // Usage in standard NSD files (version 2007B): SubDataObject + // TODO + if( optionalIfPhsRefIsSynchrophasorElseMandatory != null ) { + for( String name : optionalIfPhsRefIsSynchrophasorElseMandatory ) { + if( presentBDA.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"OMSynPh\" for DA " + name + " is not implemented in DAType (line " + daType.getLineNumber() + ") with ConstructedAttribute " + constructedAttribute.getName(), + new Object[] { daType } )); + } + } + } + + return res; + } + +} diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/TypeValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/TypeValidator.java index a74944fd5b28d132f45b1ff253a45a8dbf3f4282..4f22c62cafab0937d9a7e84a10881d23b4cc7dc0 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/TypeValidator.java +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/TypeValidator.java @@ -26,7 +26,7 @@ import org.eclipse.emf.common.util.DiagnosticChain; import fr.centralesupelec.edf.riseclipse.iec61850.nsd.BasicType; import fr.centralesupelec.edf.riseclipse.iec61850.nsd.ConstructedAttribute; import fr.centralesupelec.edf.riseclipse.iec61850.nsd.Enumeration; -import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.AbstractDataAttribute; public abstract class TypeValidator { @@ -39,9 +39,13 @@ public abstract class TypeValidator { public static void buildValidators( Stream< BasicType > basicTypeStream, Stream< Enumeration > enumerationStream, Stream< ConstructedAttribute > constructedAttributeStream ) { basicTypeStream .forEach( basicType -> validators.put( basicType.getName(), BasicTypeValidator.get( basicType ))); + enumerationStream .forEach( enumeration -> validators.put( enumeration.getName(), new EnumerationValidator( enumeration ))); + + constructedAttributeStream + .forEach( contructedAttribute -> validators.put( contructedAttribute.getName(), new ConstructedAttributeValidator( contructedAttribute ))); } - public abstract boolean validateDA( DA da, DiagnosticChain diagnostics ); + public abstract boolean validateAbstractDataAttribute( AbstractDataAttribute ada, DiagnosticChain diagnostics ); }