From c56fb3afeded935341bbfd713ec76caa3192eff5 Mon Sep 17 00:00:00 2001 From: Dominique Marcadet <Dominique.Marcadet@centralesupelec.fr> Date: Tue, 28 May 2019 17:03:25 +0200 Subject: [PATCH] create superclass GenericPresenceCondiitonValidator to avoid much of duplicated code. Not yet done for DataObjectPresenceCondiitonValidator. --- .../scl/validator/nsd/BasicTypeValidator.java | 1 - .../scl/validator/nsd/CDCValidator.java | 11 +- .../nsd/ConstructedAttributeValidator.java | 9 +- ...taAttributePresenceConditionValidator.java | 1435 ++-------------- .../validator/nsd/EnumerationValidator.java | 7 +- .../GenericPresenceConditionValidator.java | 1334 +++++++++++++++ .../scl/validator/nsd/LNClassValidator.java | 7 +- ...taAttributePresenceConditionValidator.java | 1351 +-------------- ...bDataObjectPresenceConditionValidator.java | 1448 +---------------- 9 files changed, 1588 insertions(+), 4015 deletions(-) create mode 100644 fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/GenericPresenceConditionValidator.java 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 a128e72..4530e67 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 @@ -18,7 +18,6 @@ */ package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd; -import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; 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 f57a6dc..58a5a15 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 @@ -45,11 +45,12 @@ public class CDCValidator { .forEach( cdc -> validators.put( cdc.getName(), new CDCValidator( cdc ))); } + private static HashSet< String > validatedDOType = new HashSet<>(); + private DataAttributePresenceConditionValidator dataAttributePresenceConditionValidator; private SubDataObjectPresenceConditionValidator subDataObjectPresenceConditionValidator; private HashMap< String, TypeValidator > dataAttributeValidatorMap = new HashMap<>(); private HashMap< String, CDCValidator > subDataObjectValidatorMap = new HashMap<>(); - private HashSet< DOType > validatedDOType = new HashSet<>(); private CDCValidator( CDC cdc ) { dataAttributePresenceConditionValidator = DataAttributePresenceConditionValidator.get( cdc ); @@ -78,15 +79,15 @@ public class CDCValidator { } public boolean validateDOType( DOType doType, DiagnosticChain diagnostics ) { - if( validatedDOType.contains( doType )) return true; + if( validatedDOType.contains( doType.getId() )) return true; AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] CDCValidator.validateDOType( " + doType.getId() + " ) at line " + doType.getLineNumber() ); - validatedDOType.add( doType ); + validatedDOType.add( doType.getId() ); dataAttributePresenceConditionValidator.reset(); doType .getDA() .stream() - .forEach( d -> dataAttributePresenceConditionValidator.addDA( d, diagnostics )); + .forEach( d -> dataAttributePresenceConditionValidator.addModelData( d, d.getName(), diagnostics )); boolean res = dataAttributePresenceConditionValidator.validate( doType, diagnostics ); @@ -94,7 +95,7 @@ public class CDCValidator { doType .getSDO() .stream() - .forEach( d -> subDataObjectPresenceConditionValidator.addSDO( d, diagnostics )); + .forEach( d -> subDataObjectPresenceConditionValidator.addModelData( d, d.getName(), diagnostics )); res = subDataObjectPresenceConditionValidator.validate( doType, diagnostics ) && res; 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 index 1cdbe9d..90958ea 100644 --- 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 @@ -32,9 +32,10 @@ import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole; public class ConstructedAttributeValidator extends TypeValidator { + private static HashSet< String > validatedDAType = new HashSet<>(); + private SubDataAttributePresenceConditionValidator subDataAttributePresenceConditionValidator; private HashMap< String, TypeValidator > subDataAttributeValidatorMap = new HashMap<>(); - private HashSet< DAType > validatedDAType = new HashSet<>(); public ConstructedAttributeValidator( ConstructedAttribute contructedAttribute ) { subDataAttributePresenceConditionValidator = SubDataAttributePresenceConditionValidator.get( contructedAttribute ); @@ -62,15 +63,15 @@ public class ConstructedAttributeValidator extends TypeValidator { } private boolean validateDAType( DAType daType, DiagnosticChain diagnostics ) { - if( validatedDAType.contains( daType )) return true; + if( validatedDAType.contains( daType.getId() )) return true; AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] ConstructedAttributeValidator.validateDAType( " + daType.getId() + " ) at line " + daType.getLineNumber() ); - validatedDAType.add( daType ); + validatedDAType.add( daType.getId() ); subDataAttributePresenceConditionValidator.reset(); daType .getBDA() .stream() - .forEach( bda -> subDataAttributePresenceConditionValidator.addBDA( bda, diagnostics )); + .forEach( bda -> subDataAttributePresenceConditionValidator.addModelData( bda, bda.getName(), diagnostics )); boolean res = subDataAttributePresenceConditionValidator.validate( daType, diagnostics ); 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 1e18a8d..3df5165 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 @@ -19,14 +19,12 @@ 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 org.eclipse.emf.common.util.EList; +import org.eclipse.jdt.annotation.Nullable; import fr.centralesupelec.edf.riseclipse.iec61850.nsd.CDC; import fr.centralesupelec.edf.riseclipse.iec61850.scl.AbstractDataObject; @@ -34,11 +32,9 @@ import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA; import fr.centralesupelec.edf.riseclipse.iec61850.scl.DO; import fr.centralesupelec.edf.riseclipse.iec61850.scl.DOType; 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 DataAttributePresenceConditionValidator { - +public class DataAttributePresenceConditionValidator extends GenericPresenceConditionValidator< CDC, DOType, @Nullable DA >{ + private static HashMap< String, DataAttributePresenceConditionValidator > validators = new HashMap<>(); public static DataAttributePresenceConditionValidator get( CDC cdc ) { @@ -49,1373 +45,136 @@ public class DataAttributePresenceConditionValidator { } private CDC cdc; - - // Name of the DataAttribute/DA, DA - private HashMap< String, DA > presentDA = 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 DataAttributePresenceConditionValidator( CDC cdc ) { - this.cdc = cdc; + super( cdc ); + this.cdc = cdc; + } + + @Override + protected void createSpecifications( CDC cdc ) { cdc .getDataAttribute() .stream() - .forEach( da -> addSpecification( da.getName(), da.getPresCond(), da.getPresCondArgs() ) ); + .forEach( da -> addSpecification( da.getName(), da.getPresCond(), da.getPresCondArgs(), da.getRefersToPresCondArgsDoc() )); + } - checkSpecification(); + @Override + protected String getPresenceConditionValidatorName() { + return "DataAttributePresenceConditionValidator"; } - - public void reset() { - for( String da : presentDA.keySet() ) { - presentDA.put( da, null ); - } + + @Override + protected String getNsdModelName() { + return cdc.getName(); } - - private void addSpecification( String name, String presCond, String presCondArgs ) { - if( presentDA.containsKey( name )) { - console.warning( "[NSD setup] " + name + " has already been added to DataAttributePresenceConditionValidator" ); - return; - } - presentDA.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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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 - if( mandatoryInLLN0ElseOptional == null ) mandatoryInLLN0ElseOptional = new HashSet<>(); - mandatoryInLLN0ElseOptional.add( name ); - break; - case "MFln0" : - // Element is mandatory in the context of LLN0; otherwise forbidden - 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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: DataAttribute " + 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; - } - + @Override + protected String getNsdModelClassName() { + return "CDC"; } - - 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( ! presentDA.containsKey( e.getValue() )) { - 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 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 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 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 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 DataAttribute " + e.getKey() + " is unknown" ); - } - } - } + + @Override + protected String getNsdComponentClassName() { + return "DataAttribute"; } - public boolean addDA( DA da, DiagnosticChain diagnostics ) { - if( ! presentDA.containsKey( da.getName() )) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + da.getName() + " in DOType (line " + da.getParentDOType().getLineNumber() + ") not found in CDC " + cdc.getName(), - new Object[] { da } )); - return false; - } + @Override + protected String getSclModelClassName() { + return "DOType"; + } - if( presentDA.get( da.getName() ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + da.getName() + " in DOType (line " + da.getParentDOType().getLineNumber() + ") already present in CDC " + cdc.getName(), - new Object[] { da } )); - return false; - } - presentDA.put( da.getName(), da ); - return true; + @Override + protected String getSclComponentClassName() { + return "DA"; } - - public boolean validate( DOType doType, DiagnosticChain diagnostics ) { - AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] DataAttributePresenceConditionValidator.validate(id=" + doType.getId() + ") at line " + doType.getLineNumber() ); + @Override + protected boolean validateMFln0( DOType sclModel, DiagnosticChain diagnostics ) { 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( String name : this.mandatory ) { - if( presentDA.get( name ) == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + name + " is mandatory in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( String name : this.optional ) { - if( presentDA.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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( String name : this.forbidden ) { - if( presentDA.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + name + " is forbidden in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< Integer, HashSet< String > > e1 : atLeastOne.entrySet() ) { - boolean groupOK = false; - for( String member : e1.getValue() ) { - if( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - int count = 0; - for( String s : atMostOne ) { - if( presentDA.get( s ) != null ) { - ++count; - } - } - if( count > 1 ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] LNodeType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has more than one element marked AtMostOne", - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< Integer, HashSet< String > > e1 : allOrNonePerGroup.entrySet() ) { - int groupCount = 0; - for( String member : e1.getValue() ) { - if( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - int groupNumber = 0; - for( Entry< Integer, HashSet< String > > e1 : allOnlyOneGroup.entrySet() ) { - int groupCount = 0; - for( String member : e1.getValue() ) { - if( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - 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 " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has several groups with all elements", - new Object[] { doType } )); - res = false; - } - } - } - if( groupNumber == 0 ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] no group in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has all elements", - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - int groupNumber = 0; - for( Entry< Integer, HashSet< String > > e1 : allAtLeastOneGroup.entrySet() ) { - int groupCount = 0; - for( String member : e1.getValue() ) { - if( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has all elements", - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : mandatoryIfSiblingPresentElseForbidden.entrySet() ) { - if( presentDA.get( entry.getValue() ) != null ) { - if( presentDA.get( entry.getKey() ) == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is present", - new Object[] { doType } )); - res = false; - } - } - else { - if( presentDA.get( entry.getKey() ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + entry.getKey() + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is not present", - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : mandatoryIfSiblingPresentElseOptional.entrySet() ) { - if( presentDA.get( entry.getValue() ) != null ) { - if( presentDA.get( entry.getKey() ) == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is present", - new Object[] { doType } )); - res = false; + EList< AbstractDataObject > adoList = sclModel.getReferredByAbstractDataObject(); + for( AbstractDataObject ado : adoList ) { + if( ado instanceof DO ) { + DO do_ = ( DO ) ado; + if( "LLN0".equals( do_.getParentLNodeType().getLnClass() )) { + for( String attribute : mandatoryInLLN0ElseOptional ) { + DA da = presentSclComponent.get( attribute ); + if( da == null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + attribute + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass LLN0", + new Object[] { sclModel } )); + 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : optionalIfSiblingPresentElseMandatory.entrySet() ) { - if( presentDA.get( entry.getValue() ) == null ) { - if( presentDA.get( entry.getKey() ) == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is not present", - new Object[] { doType } )); - res = false; - } - } + else { + // ado instanceof SDO } } - - // 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : forbiddenIfSiblingPresentElseMandatory.entrySet() ) { - if( presentDA.get( entry.getValue() ) != null ) { - if( presentDA.get( entry.getKey() ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + entry.getKey() + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is present", - new Object[] { doType } )); - res = false; + return res; + } + + @Override + protected boolean validateMOln0( DOType sclModel, DiagnosticChain diagnostics ) { + boolean res = true; + EList< AbstractDataObject > adoList = sclModel.getReferredByAbstractDataObject(); + for( AbstractDataObject ado : adoList ) { + if( ado instanceof DO ) { + DO do_ = ( DO ) ado; + if( "LLN0".equals( do_.getParentLNodeType().getLnClass() )) { + for( String attribute : mandatoryInLLN0ElseForbidden ) { + DA da = presentSclComponent.get( attribute ); + if( da == null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + attribute + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass LLN0", + new Object[] { sclModel } )); + res = false; + } } } else { - if( presentDA.get( entry.getKey() ) == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is not present", - new Object[] { doType } )); - res = false; + for( String attribute : mandatoryInLLN0ElseForbidden ) { + DA da = presentSclComponent.get( attribute ); + if( da != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + attribute + " is forbidden in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass " + do_.getParentLNodeType().getLnClass(), + new Object[] { sclModel } )); + 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : mandatoryIfTextConditionElseOptional.entrySet() ) { - String doc = cdc - .getDataAttribute() - .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] DA " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with CDC " - + cdc.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else optional. It is " - + ( presentDA.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ), - new Object[] { doType } )); + else { + // ado instanceof SDO } } - - // 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : mandatoryIfTextConditionElseForbidden.entrySet() ) { - String doc = cdc - .getDataAttribute() - .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] DA " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with CDC " - + cdc.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " - + ( presentDA.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ), - new Object[] { doType } )); - } - } - - // 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : optionalIfTextConditionElseForbidden.entrySet() ) { - String doc = cdc - .getDataAttribute() - .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 ); + return res; + } + @Override + protected boolean validateOMSynPh( DOType sclModel, DiagnosticChain diagnostics ) { + for( String name : optionalIfPhsRefIsSynchrophasorElseMandatory ) { + if( presentSclComponent.get( name ) != null ) { diagnostics.add( new BasicDiagnostic( Diagnostic.WARNING, RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, - "[NSD validation] DA " + entry.getKey() + " is optional in DOType (line " + doType.getLineNumber() + ") with CDC " - + cdc.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " - + ( presentDA.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ), - new Object[] { doType } )); - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } + "[NSD validation] verification of PresenceCondition \"OMSynPh\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); } } - - // presCond: "MOln0" : - // Element is mandatory in the context of LLN0; otherwise optional - // Usage in standard NSD files (version 2007B): DataAttribute - if( mandatoryInLLN0ElseOptional != null ) { - AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MOln0\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - EList< AbstractDataObject > adoList = doType.getReferredByAbstractDataObject(); - for( AbstractDataObject ado : adoList ) { - if( ado instanceof DO ) { - DO do_ = ( DO ) ado; - if( "LLN0".equals( do_.getParentLNodeType().getLnClass() )) { - for( String attribute : mandatoryInLLN0ElseOptional ) { - DA da = presentDA.get( attribute ); - if( da == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + attribute + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass LLN0", - new Object[] { doType } )); - res = false; - } - } - } - } - else { - // ado instanceof SDO - } - } - } - - // presCond: "MFln0" : - // Element is mandatory in the context of LLN0; otherwise forbidden - // Usage in standard NSD files (version 2007B): DataAttribute - if( mandatoryInLLN0ElseForbidden != null ) { - AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MFln0\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - EList< AbstractDataObject > adoList = doType.getReferredByAbstractDataObject(); - for( AbstractDataObject ado : adoList ) { - if( ado instanceof DO ) { - DO do_ = ( DO ) ado; - if( "LLN0".equals( do_.getParentLNodeType().getLnClass() )) { - for( String attribute : mandatoryInLLN0ElseForbidden ) { - DA da = presentDA.get( attribute ); - if( da == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + attribute + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass LLN0", - new Object[] { doType } )); - res = false; - } - } - } - else { - for( String attribute : mandatoryInLLN0ElseForbidden ) { - DA da = presentDA.get( attribute ); - if( da != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + attribute + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass " + do_.getParentLNodeType().getLnClass(), - new Object[] { doType } )); - res = false; - } - } - } - } - else { - // ado instanceof SDO - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : optionalIfSiblingPresentElseForbidden.entrySet() ) { - if( presentDA.get( entry.getValue() ) == null ) { - if( presentDA.get( entry.getKey() ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] DA " + entry.getKey() + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is not present", - new Object[] { doType } )); - 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentDA.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - return res; + return true; } } 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 81a178d..803af2f 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 @@ -37,11 +37,12 @@ import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole; public class EnumerationValidator extends TypeValidator { + private static HashSet< String > validatedEnumType = new HashSet<>(); + private HashMap< String, Integer > literals = new HashMap<>(); private String name; private String inheritedFromName; private EnumerationValidator inheritedFrom; - private HashSet< EnumType > validatedEnumType = new HashSet<>(); public EnumerationValidator( Enumeration enumeration ) { this.name = enumeration.getName(); @@ -139,9 +140,9 @@ public class EnumerationValidator extends TypeValidator { } public boolean validateEnumType( EnumType enumType, DiagnosticChain diagnostics ) { - if( validatedEnumType.contains( enumType )) return true; + if( validatedEnumType.contains( enumType.getId() )) return true; AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] EnumerationValidator.validateEnumType( " + enumType.getId() + " ) at line " + enumType.getLineNumber() ); - validatedEnumType.add( enumType ); + validatedEnumType.add( enumType.getId() ); boolean res = true; diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/GenericPresenceConditionValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/GenericPresenceConditionValidator.java new file mode 100644 index 0000000..ac41ef8 --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/GenericPresenceConditionValidator.java @@ -0,0 +1,1334 @@ +/** + * 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 org.eclipse.jdt.annotation.NonNull; +import org.eclipse.jdt.annotation.Nullable; + +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.Doc; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.NsdObject; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.SclObject; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL; +import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole; +import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole; + +public abstract class GenericPresenceConditionValidator< NsdModel extends NsdObject, SclModel extends SclObject, @Nullable SclComponent extends SclObject > { + + // Name of the NsdComponent/SclComponent, SclComponent + protected HashMap< String, SclComponent > presentSclComponent = new HashMap<>(); + + protected HashSet< String > mandatory; + protected HashSet< String > optional; + protected HashSet< String > forbidden; + protected HashSet< String > notApplicable; + protected HashSet< String > mandatoryMulti; + protected HashSet< String > optionalMulti; + protected HashMap< Integer, HashSet< String > > atLeastOne; + protected HashSet< String > atMostOne; + protected HashMap< Integer, HashSet< String > > allOrNonePerGroup; + protected HashMap< Integer, HashSet< String > > allOnlyOneGroup; + protected HashMap< Integer, HashSet< String > > allAtLeastOneGroup; + protected HashMap< String, String > mandatoryIfSiblingPresentElseForbidden; + protected HashMap< String, String > mandatoryIfSiblingPresentElseOptional; + protected HashMap< String, String > optionalIfSiblingPresentElseMandatory; + protected HashMap< String, String > forbiddenIfSiblingPresentElseMandatory; + protected HashMap< String, String > mandatoryIfTextConditionElseOptional; + protected HashMap< String, String > mandatoryIfTextConditionElseOptionalDoc; + protected HashMap< String, String > mandatoryIfTextConditionElseForbidden; + protected HashMap< String, String > mandatoryIfTextConditionElseForbiddenDoc; + protected HashMap< String, String > optionalIfTextConditionElseForbidden; + protected HashMap< String, String > optionalIfTextConditionElseForbiddenDoc; + protected HashMap< String, Pair< Integer, Integer > > mandatoryMultiRange; + protected HashMap< String, Pair< Integer, Integer > > optionalMultiRange; + protected HashSet< String > mandatoryIfSubstitutionElseForbidden; + protected HashSet< String > mandatoryInLLN0ElseOptional; + protected HashSet< String > mandatoryInLLN0ElseForbidden; + protected HashSet< String > mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional; + protected HashSet< String > mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional; + protected HashSet< String > mandatoryIfAnalogValueIncludesIElseForbidden; + protected HashSet< String > mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden; + protected HashSet< String > mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden; + protected HashSet< String > mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional; + protected HashSet< String > mandatoryInRootLogicalDeviceElseOptional; + protected HashSet< String > mandatoryIfControlSupportsTimeElseOptional; + protected HashMap< String, String > oneOrMoreIfSiblingPresentElseForbidden; + protected HashSet< String > mandatoryIfControlSupportsSecurity1ElseOptional; + protected HashSet< String > mandatoryIfControlSupportsSecurity2ElseOptional; + protected HashMap< String, String > optionalIfSiblingPresentElseForbidden; + protected HashSet< String > mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2; + protected HashSet< String > mandatoryIfMeasuredValueExposesRange; + protected HashSet< String > optionalIfPhsRefIsSynchrophasorElseMandatory; + + protected final IRiseClipseConsole console = AbstractRiseClipseConsole.getConsole(); + + public GenericPresenceConditionValidator( NsdModel nsdModel ) { + createSpecifications( nsdModel ); + checkSpecification(); + } + + protected abstract void createSpecifications( NsdModel nsdModel ); + + protected abstract String getPresenceConditionValidatorName(); + + protected abstract String getNsdModelName(); + protected abstract String getNsdModelClassName(); + protected abstract String getNsdComponentClassName(); + + protected abstract String getSclModelClassName(); + protected abstract String getSclComponentClassName(); + + public void reset() { + for( String sclComponent : presentSclComponent.keySet() ) { + presentSclComponent.put( sclComponent, null ); + } + } + + protected void addSpecification( String name, String presCond, String presCondArgs, Doc doc ) { + if( presentSclComponent.containsKey( name )) { + console.warning( "[NSD setup] " + name + " has already been added to " + getPresenceConditionValidatorName() ); + return; + } + presentSclComponent.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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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<>(); + if( mandatoryIfTextConditionElseOptionalDoc == null ) mandatoryIfTextConditionElseOptionalDoc = 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 ); + mandatoryIfTextConditionElseOptionalDoc.put( name, doc.getMixed().get( 0 ).getValue().toString() ); + + 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<>(); + if( mandatoryIfTextConditionElseForbiddenDoc == null ) mandatoryIfTextConditionElseForbiddenDoc = 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 ); + mandatoryIfTextConditionElseForbiddenDoc.put( name, doc.getMixed().get( 0 ).getValue().toString() ); + 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<>(); + if( optionalIfTextConditionElseForbiddenDoc == null ) optionalIfTextConditionElseForbiddenDoc = 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 ); + optionalIfTextConditionElseForbiddenDoc.put( name, doc.getMixed().get( 0 ).getValue().toString() ); + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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 + if( mandatoryInLLN0ElseOptional == null ) mandatoryInLLN0ElseOptional = new HashSet<>(); + mandatoryInLLN0ElseOptional.add( name ); + break; + case "MFln0" : + // Element is mandatory in the context of LLN0; otherwise forbidden + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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: " + getNsdComponentClassName() + " " + 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; + } + + } + + protected 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( ! presentSclComponent.containsKey( e.getValue() )) { + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of " + getNsdComponentClassName() + " " + e.getKey() + " is unknown" ); + } + } + } + if( mandatoryIfSiblingPresentElseOptional != null ) { + for( Entry< String, String > e : mandatoryIfSiblingPresentElseOptional.entrySet() ) { + if( ! presentSclComponent.containsKey( e.getValue() )) { + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of " + getNsdComponentClassName() + " " + e.getKey() + " is unknown" ); + } + } + } + if( optionalIfSiblingPresentElseMandatory != null ) { + for( Entry< String, String > e : optionalIfSiblingPresentElseMandatory.entrySet() ) { + if( ! presentSclComponent.containsKey( e.getValue() )) { + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of " + getNsdComponentClassName() + " " + e.getKey() + " is unknown" ); + } + } + } + if( forbiddenIfSiblingPresentElseMandatory != null ) { + for( Entry< String, String > e : forbiddenIfSiblingPresentElseMandatory.entrySet() ) { + if( ! presentSclComponent.containsKey( e.getValue() )) { + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of " + getNsdComponentClassName() + " " + e.getKey() + " is unknown" ); + } + } + } + if( oneOrMoreIfSiblingPresentElseForbidden != null ) { + for( Entry< String, String > e : oneOrMoreIfSiblingPresentElseForbidden.entrySet() ) { + if( ! presentSclComponent.containsKey( e.getValue() )) { + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of " + getNsdComponentClassName() + " " + e.getKey() + " is unknown" ); + } + } + } + if( optionalIfSiblingPresentElseForbidden != null ) { + for( Entry< String, String > e : optionalIfSiblingPresentElseForbidden.entrySet() ) { + if( ! presentSclComponent.containsKey( e.getValue() )) { + console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of " + getNsdComponentClassName() + " " + e.getKey() + " is unknown" ); + } + } + } + } + + public boolean addModelData( @NonNull SclComponent sclComponent, String sclComponentName, DiagnosticChain diagnostics ) { + if( ! presentSclComponent.containsKey( sclComponentName )) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + sclComponentName + " (line " + sclComponent.getLineNumber() + ") not found in " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclComponent } )); + return false; + } + + if( presentSclComponent.get( sclComponentName ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + sclComponentName + " (line " + sclComponent.getLineNumber() + ") already present in " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclComponent } )); + return false; + } + presentSclComponent.put( sclComponentName, sclComponent ); + return true; + } + + public boolean validate( SclModel sclModel, DiagnosticChain diagnostics ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] OldDataAttributePresenceConditionValidator.validate() at line " + sclModel.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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + for( String name : this.mandatory ) { + if( presentSclComponent.get( name ) == null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + name + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + for( String name : this.optional ) { + if( presentSclComponent.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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + for( String name : this.forbidden ) { + if( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + name + " is forbidden in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"na\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"Mmulti\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"Omulti\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + for( Entry< Integer, HashSet< String > > e1 : atLeastOne.entrySet() ) { + boolean groupOK = false; + for( String member : e1.getValue() ) { + if( presentSclComponent.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 " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + int count = 0; + for( String s : atMostOne ) { + if( presentSclComponent.get( s ) != null ) { + ++count; + } + } + if( count > 1 ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] LNodeType (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName() + " has more than one element marked AtMostOne", + new Object[] { sclModel } )); + 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + for( Entry< Integer, HashSet< String > > e1 : allOrNonePerGroup.entrySet() ) { + int groupCount = 0; + for( String member : e1.getValue() ) { + if( presentSclComponent.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 " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + int groupNumber = 0; + for( Entry< Integer, HashSet< String > > e1 : allOnlyOneGroup.entrySet() ) { + int groupCount = 0; + for( String member : e1.getValue() ) { + if( presentSclComponent.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 " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + 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 " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName() + " has several groups with all elements", + new Object[] { sclModel } )); + res = false; + } + } + } + if( groupNumber == 0 ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] no group in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName() + " has all elements", + new Object[] { sclModel } )); + 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + int groupNumber = 0; + for( Entry< Integer, HashSet< String > > e1 : allAtLeastOneGroup.entrySet() ) { + int groupCount = 0; + for( String member : e1.getValue() ) { + if( presentSclComponent.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 " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName() + " has all elements", + new Object[] { sclModel } )); + 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + for( Entry< String, String > entry : mandatoryIfSiblingPresentElseForbidden.entrySet() ) { + if( presentSclComponent.get( entry.getValue() ) != null ) { + if( presentSclComponent.get( entry.getKey() ) == null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass " + + getNsdModelName() + " because sibling " + entry.getValue() + " is present", + new Object[] { sclModel } )); + res = false; + } + } + else { + if( presentSclComponent.get( entry.getKey() ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is forbidden in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass " + + getNsdModelName() + " because sibling " + entry.getValue() + " is not present", + new Object[] { sclModel } )); + 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + for( Entry< String, String > entry : mandatoryIfSiblingPresentElseOptional.entrySet() ) { + if( presentSclComponent.get( entry.getValue() ) != null ) { + if( presentSclComponent.get( entry.getKey() ) == null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass " + + getNsdModelName() + " because sibling " + entry.getValue() + " is present", + new Object[] { sclModel } )); + 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + for( Entry< String, String > entry : optionalIfSiblingPresentElseMandatory.entrySet() ) { + if( presentSclComponent.get( entry.getValue() ) == null ) { + if( presentSclComponent.get( entry.getKey() ) == null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass " + + getNsdModelName() + " because sibling " + entry.getValue() + " is not present", + new Object[] { sclModel } )); + 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + for( Entry< String, String > entry : forbiddenIfSiblingPresentElseMandatory.entrySet() ) { + if( presentSclComponent.get( entry.getValue() ) != null ) { + if( presentSclComponent.get( entry.getKey() ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is forbidden in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass " + + getNsdModelName() + " because sibling " + entry.getValue() + " is present", + new Object[] { sclModel } )); + res = false; + } + } + else { + if( presentSclComponent.get( entry.getKey() ) == null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass " + + getNsdModelName() + " because sibling " + entry.getValue() + " is not present", + new Object[] { sclModel } )); + 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + for( Entry< String, String > entry : mandatoryIfTextConditionElseOptional.entrySet() ) { + String doc = mandatoryIfTextConditionElseOptionalDoc.get( entry.getKey() ); + + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + + getNsdModelClassName() + " " + getNsdModelName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else optional. It is " + + ( presentSclComponent.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ), + new Object[] { sclModel } )); + } + } + + // 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + for( Entry< String, String > entry : mandatoryIfTextConditionElseForbidden.entrySet() ) { + String doc = mandatoryIfTextConditionElseForbiddenDoc.get( entry.getKey() ); + + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is mandatory in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + + getNsdModelClassName() + " " + getNsdModelName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " + + ( presentSclComponent.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ), + new Object[] { sclModel } )); + } + } + + // 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + for( Entry< String, String > entry : optionalIfTextConditionElseForbidden.entrySet() ) { + String doc = optionalIfTextConditionElseForbiddenDoc.get( entry.getKey() ); + + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is optional in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + + getNsdModelClassName() + " " + getNsdModelName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " + + ( presentSclComponent.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ), + new Object[] { sclModel } )); + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MmultiRange\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"OmultiRange\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MFsubst\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // presCond: "MOln0" : + // Element is mandatory in the context of LLN0; otherwise optional + // Usage in standard NSD files (version 2007B): DataAttribute + if( mandatoryInLLN0ElseOptional != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MOln0\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + res = validateMOln0( sclModel, diagnostics ) && res; + } + + // presCond: "MFln0" : + // Element is mandatory in the context of LLN0; otherwise forbidden + // Usage in standard NSD files (version 2007B): DataAttribute + if( mandatoryInLLN0ElseForbidden != null ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MFln0\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + res = validateMFln0( sclModel, diagnostics ) && res; + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOlnNs\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOdataNs\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MFscaledAV\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MFscaledMagV\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MFscaledAngV\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOrms\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOrootLD\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOoperTm\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MmultiF\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOsbo\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MOenhanced\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MONamPlt\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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 " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + for( Entry< String, String > entry : optionalIfSiblingPresentElseForbidden.entrySet() ) { + if( presentSclComponent.get( entry.getValue() ) == null ) { + if( presentSclComponent.get( entry.getKey() ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] " + getSclComponentClassName() + " " + entry.getKey() + " is forbidden in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with LNClass " + + getNsdModelName() + " because sibling " + entry.getValue() + " is not present", + new Object[] { sclModel } )); + 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( presentSclComponent.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"MORange\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); + } + } + } + + // 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 ) { + AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"OMSynPh\" on " + getSclModelClassName() + " at line " + sclModel.getLineNumber() ); + res = validateOMSynPh( sclModel, diagnostics ) && res; + } + + return res; + } + + protected abstract boolean validateMFln0( SclModel sclModel, DiagnosticChain diagnostics ); + + protected abstract boolean validateMOln0( SclModel sclModel, DiagnosticChain diagnostics ); + + protected abstract boolean validateOMSynPh( SclModel sclModel, DiagnosticChain diagnostics ); + +} diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNClassValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNClassValidator.java index a6e2fd4..228059f 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNClassValidator.java +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNClassValidator.java @@ -45,9 +45,10 @@ public class LNClassValidator { .forEach( lnClass -> validators.put( lnClass.getName(), new LNClassValidator( lnClass ))); } + private static HashSet< String > validatedLNodeType = new HashSet<>(); + private DataObjectPresenceConditionValidator dataObjectPresenceConditionValidator; private HashMap< String, CDCValidator > dataObjectValidatorMap = new HashMap<>(); - private HashSet< LNodeType > validatedLNodeType = new HashSet<>(); private LNClassValidator( AnyLNClass anyLNClass ) { dataObjectPresenceConditionValidator = DataObjectPresenceConditionValidator.get( anyLNClass ); @@ -69,9 +70,9 @@ public class LNClassValidator { } public boolean validateLNodeType( LNodeType lNodeType, DiagnosticChain diagnostics ) { - if( validatedLNodeType.contains( lNodeType )) return true; + if( validatedLNodeType.contains( lNodeType.getId() )) return true; AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] LNClassValidator.validateLNodeType( " + lNodeType.getId() + " ) at line " + lNodeType.getLineNumber() ); - validatedLNodeType.add( lNodeType ); + validatedLNodeType.add( lNodeType.getId() ); boolean res = true; 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 index 37f5d83..67af54a 100644 --- 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 @@ -19,21 +19,17 @@ 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 org.eclipse.jdt.annotation.Nullable; + 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 { +public class SubDataAttributePresenceConditionValidator extends GenericPresenceConditionValidator< ConstructedAttribute, DAType, @Nullable BDA >{ private static HashMap< String, SubDataAttributePresenceConditionValidator > validators = new HashMap<>(); @@ -46,1332 +42,93 @@ public class SubDataAttributePresenceConditionValidator { 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 ) { + super( constructedAttribute ); + this.constructedAttribute = constructedAttribute; - + } + + @Override + protected void createSpecifications( ConstructedAttribute constructedAttribute ) { constructedAttribute .getSubDataAttribute() .stream() - .forEach( sda -> addSpecification( sda.getName(), sda.getPresCond(), sda.getPresCondArgs() ) ); - - checkSpecification(); + .forEach( sda -> addSpecification( sda.getName(), sda.getPresCond(), sda.getPresCondArgs(), sda.getRefersToPresCondArgsDoc() ) ); } - public void reset() { - for( String bda : presentBDA.keySet() ) { - presentBDA.put( bda, null ); - } + @Override + protected String getPresenceConditionValidatorName() { + return "SubDataAttributePresenceConditionValidator"; } - - 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; - } - + @Override + protected String getNsdModelName() { + return constructedAttribute.getName(); } - - 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; + @Override + protected String getNsdModelClassName() { + return "ConstructedAttribute"; } - - 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; - } - } - } + @Override + protected String getNsdComponentClassName() { + return "SubDataAttribute"; + } - // 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 } )); - } - } - } + @Override + protected String getSclModelClassName() { + return "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 ); + @Override + protected String getSclComponentClassName() { + return "BDA"; + } + @Override + protected boolean validateMFln0( DAType sclModel, DiagnosticChain diagnostics ) { + for( String name : mandatoryInLLN0ElseForbidden ) { + if( presentSclComponent.get( name ) != 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 } )); + "[NSD validation] verification of PresenceCondition \"MFln0\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); } } - - // 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 ); + return true; + } + @Override + protected boolean validateMOln0( DAType sclModel, DiagnosticChain diagnostics ) { + for( String name : mandatoryInLLN0ElseOptional ) { + if( presentSclComponent.get( name ) != 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 } )); + "[NSD validation] verification of PresenceCondition \"MOln0\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); } } - - // 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 ); + return true; + } + @Override + protected boolean validateOMSynPh( DAType sclModel, DiagnosticChain diagnostics ) { + for( String name : optionalIfPhsRefIsSynchrophasorElseMandatory ) { + if( presentSclComponent.get( name ) != 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 } )); - } + "[NSD validation] verification of PresenceCondition \"OMSynPh\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); } } - - // 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; + return true; } } diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataObjectPresenceConditionValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataObjectPresenceConditionValidator.java index 7ce4319..64d95c9 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataObjectPresenceConditionValidator.java +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/SubDataObjectPresenceConditionValidator.java @@ -19,29 +19,23 @@ package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd; import java.util.HashMap; -import java.util.HashSet; -import java.util.Map.Entry; import java.util.Optional; -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 org.eclipse.emf.common.util.EList; +import org.eclipse.jdt.annotation.Nullable; import fr.centralesupelec.edf.riseclipse.iec61850.nsd.CDC; -import fr.centralesupelec.edf.riseclipse.iec61850.scl.AbstractDataObject; import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA; -import fr.centralesupelec.edf.riseclipse.iec61850.scl.DO; import fr.centralesupelec.edf.riseclipse.iec61850.scl.DOType; import fr.centralesupelec.edf.riseclipse.iec61850.scl.SDO; import fr.centralesupelec.edf.riseclipse.iec61850.scl.Val; 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 SubDataObjectPresenceConditionValidator { - +public class SubDataObjectPresenceConditionValidator extends GenericPresenceConditionValidator< CDC, DOType, @Nullable SDO >{ + private static HashMap< String, SubDataObjectPresenceConditionValidator > validators = new HashMap<>(); public static SubDataObjectPresenceConditionValidator get( CDC cdc ) { @@ -52,1411 +46,137 @@ public class SubDataObjectPresenceConditionValidator { } private CDC cdc; - - // Name of the SubDataObject/SDO, SDO - private HashMap< String, SDO > presentSDO = 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 SubDataObjectPresenceConditionValidator( CDC cdc ) { - this.cdc = cdc; + super( cdc ); + this.cdc = cdc; + } + + @Override + protected void createSpecifications( CDC cdc ) { cdc .getSubDataObject() .stream() - .forEach( sdo -> addSpecification( sdo.getName(), sdo.getPresCond(), sdo.getPresCondArgs() ) ); - - checkSpecification(); + .forEach( sda -> addSpecification( sda.getName(), sda.getPresCond(), sda.getPresCondArgs(), sda.getRefersToPresCondArgsDoc() )); } - - public void reset() { - for( String sdo : presentSDO.keySet() ) { - presentSDO.put( sdo, null ); - } - } - - private void addSpecification( String name, String presCond, String presCondArgs ) { - if( presentSDO.containsKey( name )) { - console.warning( "[NSD setup] " + name + " has already been added to SubDataObjectPresenceConditionValidator" ); - return; - } - presentSDO.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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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 - if( mandatoryInLLN0ElseOptional == null ) mandatoryInLLN0ElseOptional = new HashSet<>(); - mandatoryInLLN0ElseOptional.add( name ); - break; - case "MFln0" : - // Element is mandatory in the context of LLN0; otherwise forbidden - 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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: SubDataObject " + 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 - 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( ! presentSDO.containsKey( e.getValue() )) { - console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" ); - } - } - } - if( mandatoryIfSiblingPresentElseOptional != null ) { - for( Entry< String, String > e : mandatoryIfSiblingPresentElseOptional.entrySet() ) { - if( ! presentSDO.containsKey( e.getValue() )) { - console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" ); - } - } - } - if( optionalIfSiblingPresentElseMandatory != null ) { - for( Entry< String, String > e : optionalIfSiblingPresentElseMandatory.entrySet() ) { - if( ! presentSDO.containsKey( e.getValue() )) { - console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" ); - } - } - } - if( forbiddenIfSiblingPresentElseMandatory != null ) { - for( Entry< String, String > e : forbiddenIfSiblingPresentElseMandatory.entrySet() ) { - if( ! presentSDO.containsKey( e.getValue() )) { - console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" ); - } - } - } - if( oneOrMoreIfSiblingPresentElseForbidden != null ) { - for( Entry< String, String > e : oneOrMoreIfSiblingPresentElseForbidden.entrySet() ) { - if( ! presentSDO.containsKey( e.getValue() )) { - console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" ); - } - } - } - if( optionalIfSiblingPresentElseForbidden != null ) { - for( Entry< String, String > e : optionalIfSiblingPresentElseForbidden.entrySet() ) { - if( ! presentSDO.containsKey( e.getValue() )) { - console.warning( "[NSD setup] the sibling of " + e.getKey() + " in PresenceCondition of DataObject " + e.getKey() + " is unknown" ); - } - } - } + @Override + protected String getPresenceConditionValidatorName() { + return "SubDataObjectPresenceConditionValidator"; } - public boolean addSDO( SDO sdo, DiagnosticChain diagnostics ) { - if( ! presentSDO.containsKey( sdo.getName() )) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + sdo.getName() + " in DOType (line " + sdo.getParentDOType().getLineNumber() + ") not found in CDC " + cdc.getName(), - new Object[] { sdo } )); - return false; - } - - if( presentSDO.get( sdo.getName() ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + sdo.getName() + " in DOType (line " + sdo.getParentDOType().getLineNumber() + ") already present in CDC " + cdc.getName(), - new Object[] { sdo } )); - return false; - } - presentSDO.put( sdo.getName(), sdo ); - return true; + @Override + protected String getNsdModelName() { + return cdc.getName(); } - - public boolean validate( DOType doType, DiagnosticChain diagnostics ) { - AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] SubDataObjectPresenceConditionValidator.validate( " + doType.getId() + ") at line " + doType.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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( String name : this.mandatory ) { - if( presentSDO.get( name ) == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + name + " is mandatory in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - res = false; - } - } - } + @Override + protected String getNsdModelClassName() { + return "CDC"; + } - // 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( String name : this.optional ) { - if( presentSDO.get( name ) == null ) { - // Nothing - } - } - } + @Override + protected String getNsdComponentClassName() { + return "SubDataObject"; + } - // 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( String name : this.forbidden ) { - if( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + name + " is forbidden in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - res = false; - } - } - } + @Override + protected String getSclModelClassName() { + return "DOType"; + } - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"na\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"Mmulti\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } + @Override + protected String getSclComponentClassName() { + return "SDO"; + } - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"Omulti\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< Integer, HashSet< String > > e1 : atLeastOne.entrySet() ) { - boolean groupOK = false; - for( String member : e1.getValue() ) { - if( presentSDO.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - int count = 0; - for( String s : atMostOne ) { - if( presentSDO.get( s ) != null ) { - ++count; - } - } - if( count > 1 ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] LNodeType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has more than one element marked AtMostOne", - new Object[] { doType } )); - 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 ) { - for( Entry< Integer, HashSet< String > > e1 : allOrNonePerGroup.entrySet() ) { - AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"AllOrNonePerGroup\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - int groupCount = 0; - for( String member : e1.getValue() ) { - if( presentSDO.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - int groupNumber = 0; - for( Entry< Integer, HashSet< String > > e1 : allOnlyOneGroup.entrySet() ) { - int groupCount = 0; - for( String member : e1.getValue() ) { - if( presentSDO.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 DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - 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 " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has several groups with all elements", - new Object[] { doType } )); - res = false; - } - } - } - if( groupNumber == 0 ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] no group in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has all elements", - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - int groupNumber = 0; - for( Entry< Integer, HashSet< String > > e1 : allAtLeastOneGroup.entrySet() ) { - int groupCount = 0; - for( String member : e1.getValue() ) { - if( presentSDO.get( member ) != null ) { - ++groupCount; - } - } - if( groupCount == e1.getValue().size() ) { - groupNumber = e1.getKey(); - } - } - if( groupNumber == 0 ) { + @Override + protected boolean validateMFln0( DOType sclModel, DiagnosticChain diagnostics ) { + for( String name : mandatoryInLLN0ElseForbidden ) { + if( presentSclComponent.get( name ) != null ) { diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, + Diagnostic.WARNING, RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, - "[NSD validation] no group in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName() + " has all elements", - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : mandatoryIfSiblingPresentElseForbidden.entrySet() ) { - if( presentSDO.get( entry.getValue() ) != null ) { - if( presentSDO.get( entry.getKey() ) == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is present", - new Object[] { doType } )); - res = false; - } - } - else { - if( presentSDO.get( entry.getKey() ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + entry.getKey() + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is not present", - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : mandatoryIfSiblingPresentElseOptional.entrySet() ) { - if( presentSDO.get( entry.getValue() ) != null ) { - if( presentSDO.get( entry.getKey() ) == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is present", - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : optionalIfSiblingPresentElseMandatory.entrySet() ) { - if( presentSDO.get( entry.getValue() ) == null ) { - if( presentSDO.get( entry.getKey() ) == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is not present", - new Object[] { doType } )); - 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : forbiddenIfSiblingPresentElseMandatory.entrySet() ) { - if( presentSDO.get( entry.getValue() ) != null ) { - if( presentSDO.get( entry.getKey() ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + entry.getKey() + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is present", - new Object[] { doType } )); - res = false; - } - } - else { - if( presentSDO.get( entry.getKey() ) == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is not present", - new Object[] { doType } )); - res = false; - } - } + "[NSD validation] verification of PresenceCondition \"MFln0\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); } } - - // 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : mandatoryIfTextConditionElseOptional.entrySet() ) { - String doc = cdc - .getSubDataObject() - .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 ); + return true; + } + @Override + protected boolean validateMOln0( DOType sclModel, DiagnosticChain diagnostics ) { + for( String name : mandatoryInLLN0ElseOptional ) { + if( presentSclComponent.get( name ) != null ) { diagnostics.add( new BasicDiagnostic( Diagnostic.WARNING, RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, - "[NSD validation] SDO " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with CDC " - + cdc.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else optional. It is " - + ( presentSDO.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ), - new Object[] { doType } )); + "[NSD validation] verification of PresenceCondition \"MOln0\" for " + getSclComponentClassName() + " " + name + " is not implemented in " + getSclModelClassName() + " (line " + sclModel.getLineNumber() + ") with " + getNsdModelClassName() + " " + getNsdModelName(), + new Object[] { sclModel } )); } } - - // 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : mandatoryIfTextConditionElseForbidden.entrySet() ) { - String doc = cdc - .getSubDataObject() - .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 ); + return true; + } + @Override + protected boolean validateOMSynPh( DOType doType, DiagnosticChain diagnostics ) { + boolean res = true; + + String sdoName = optionalIfPhsRefIsSynchrophasorElseMandatory.stream().findFirst().get(); + boolean phsRefIsSynchrophasor = false; + Optional< DA > phsRef = doType + .getDA() + .stream() + .filter( da -> "phsRef".equals( da.getName() )) + .findAny(); + if( phsRef.isPresent() ) { + EList< Val > vals = phsRef.get().getVal(); + if( vals.size() == 0 ) { diagnostics.add( new BasicDiagnostic( Diagnostic.WARNING, RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, - "[NSD validation] SDO " + entry.getKey() + " is mandatory in DOType (line " + doType.getLineNumber() + ") with CDC " - + cdc.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " - + ( presentSDO.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ), + "[NSD validation] verification of PresenceCondition \"OMSynPh\" for SDO " + sdoName + " for DOType (line " + doType.getLineNumber() + "): no value for phsRef", new Object[] { doType } )); } - } - - // 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : optionalIfTextConditionElseForbidden.entrySet() ) { - String doc = cdc - .getSubDataObject() - .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 ); - + else if( vals.size() == 1 ) { + phsRefIsSynchrophasor = "Synchrophasor".equals( vals.get( 0 ).getValue() ); + } + else { diagnostics.add( new BasicDiagnostic( Diagnostic.WARNING, RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, - "[NSD validation] SDO " + entry.getKey() + " is optional in DOType (line " + doType.getLineNumber() + ") with CDC " - + cdc.getName() + " if textual condition number " + entry.getValue() + " (not evaluated) is true, else forbidden. It is " - + ( presentSDO.get( entry.getKey() ) == null ? "absent." : "present." ) + ( doc != null ? " Textual condition is: \"" + doc + "\"." : "" ), + "[NSD validation] verification of PresenceCondition \"OMSynPh\" for SDO " + sdoName + " for DOType (line " + doType.getLineNumber() + "): multiple values for phsRef", new Object[] { doType } )); } } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MmultiRange\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"OmultiRange\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MFsubst\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // presCond: "MOln0" : - // Element is mandatory in the context of LLN0; otherwise optional - // Usage in standard NSD files (version 2007B): DataAttribute - if( mandatoryInLLN0ElseOptional != null ) { - AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MOln0\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - EList< AbstractDataObject > adoList = doType.getReferredByAbstractDataObject(); - for( AbstractDataObject ado : adoList ) { - if( ado instanceof DO ) { - DO do_ = ( DO ) ado; - if( "LLN0".equals( do_.getParentLNodeType().getLnClass() )) { - for( String attribute : mandatoryInLLN0ElseOptional ) { - SDO sdo = presentSDO.get( attribute ); - if( sdo == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + attribute + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass LLN0", - new Object[] { doType } )); - res = false; - } - } - } - } - else { - // ado instanceof SDO - } - } - } - - // presCond: "MFln0" : - // Element is mandatory in the context of LLN0; otherwise forbidden - // Usage in standard NSD files (version 2007B): DataAttribute - if( mandatoryInLLN0ElseForbidden != null ) { - AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] validation of presence condition \"MFln0\" on DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - EList< AbstractDataObject > adoList = doType.getReferredByAbstractDataObject(); - for( AbstractDataObject ado : adoList ) { - if( ado instanceof DO ) { - DO do_ = ( DO ) ado; - if( "LLN0".equals( do_.getParentLNodeType().getLnClass() )) { - for( String attribute : mandatoryInLLN0ElseForbidden ) { - SDO sdo = presentSDO.get( attribute ); - if( sdo == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + attribute + " is mandatory in DOType (line " + doType.getLineNumber() + ") with LNClass LLN0", - new Object[] { doType } )); - res = false; - } - } - } - else { - for( String attribute : mandatoryInLLN0ElseForbidden ) { - SDO sdo = presentSDO.get( attribute ); - if( sdo != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + attribute + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass " + do_.getParentLNodeType().getLnClass(), - new Object[] { doType } )); - res = false; - } - } - } - } - else { - // ado instanceof SDO - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MOlnNs\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MOdataNs\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MFscaledAV\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MFscaledMagV\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MFscaledAngV\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MOrms\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MOrootLD\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MOoperTm\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MmultiF\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MOsbo\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MOenhanced\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MONamPlt\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } - } - - // 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 DOType (id=" + doType.getId() + ") at line " + doType.getLineNumber() ); - for( Entry< String, String > entry : optionalIfSiblingPresentElseForbidden.entrySet() ) { - if( presentSDO.get( entry.getValue() ) == null ) { - if( presentSDO.get( entry.getKey() ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + entry.getKey() + " is forbidden in DOType (line " + doType.getLineNumber() + ") with LNClass " - + cdc.getName() + " because sibling " + entry.getValue() + " is not present", - new Object[] { doType } )); - 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( presentSDO.get( name ) != null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"MORange\" for SDO " + name + " is not implemented in DOType (line " + doType.getLineNumber() + ") with CDC " + cdc.getName(), - new Object[] { doType } )); - } - } + else { + diagnostics.add( new BasicDiagnostic( + Diagnostic.WARNING, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD validation] verification of PresenceCondition \"OMSynPh\" for SDO " + sdoName + " for DOType (line " + doType.getLineNumber() + "): DA phsRef not found", + new Object[] { doType } )); } - - // 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 ) { - String sdoName = optionalIfPhsRefIsSynchrophasorElseMandatory.stream().findFirst().get(); - boolean phsRefIsSynchrophasor = false; - Optional< DA > phsRef = doType - .getDA() - .stream() - .filter( da -> "phsRef".equals( da.getName() )) - .findAny(); - if( phsRef.isPresent() ) { - EList< Val > vals = phsRef.get().getVal(); - if( vals.size() == 0 ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"OMSynPh\" for SDO " + sdoName + " for DOType (line " + doType.getLineNumber() + "): no value for phsRef", - new Object[] { doType } )); - } - else if( vals.size() == 1 ) { - phsRefIsSynchrophasor = "Synchrophasor".equals( vals.get( 0 ).getValue() ); - } - else { + if( ! phsRefIsSynchrophasor ) { + for( String name : optionalIfPhsRefIsSynchrophasorElseMandatory ) { + if( presentSclComponent.get( name ) == null ) { diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, + Diagnostic.ERROR, RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, 0, - "[NSD validation] verification of PresenceCondition \"OMSynPh\" for SDO " + sdoName + " for DOType (line " + doType.getLineNumber() + "): multiple values for phsRef", + "[NSD validation] SDO " + name + " is mandatory in DOType (line " + doType.getLineNumber() + ") because phsRef is not Synchrophasor", new Object[] { doType } )); - } - } - else { - diagnostics.add( new BasicDiagnostic( - Diagnostic.WARNING, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] verification of PresenceCondition \"OMSynPh\" for SDO " + sdoName + " for DOType (line " + doType.getLineNumber() + "): DA phsRef not found", - new Object[] { doType } )); - } - if( ! phsRefIsSynchrophasor ) { - for( String name : optionalIfPhsRefIsSynchrophasorElseMandatory ) { - if( presentSDO.get( name ) == null ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD validation] SDO " + name + " is mandatory in DOType (line " + doType.getLineNumber() + ") because phsRef is not Synchrophasor", - new Object[] { doType } )); - } + res = false; } } } - return res; } + } -- GitLab