From b5d3e34eae6cc62761a16eba337d47144d428aad Mon Sep 17 00:00:00 2001 From: Dominique Marcadet <Dominique Marcadet@centralesupelec.fr> Date: Fri, 3 May 2019 19:21:01 +0800 Subject: [PATCH] WIP Initial design for checking presence conditions --- .../META-INF/MANIFEST.MF | 3 +- .../scl/validator/nsd/LNodeTypeValidator.java | 141 +-- .../validator/nsd/NsdEObjectValidator.java | 2 +- .../nsd/PresenceConditionValidator.java | 849 ++++++++++++++++++ 4 files changed, 859 insertions(+), 136 deletions(-) create mode 100644 fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/PresenceConditionValidator.java diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/META-INF/MANIFEST.MF b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/META-INF/MANIFEST.MF index e5d5f00..90a5427 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/META-INF/MANIFEST.MF +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/META-INF/MANIFEST.MF @@ -22,4 +22,5 @@ Require-Bundle: org.eclipse.core.runtime, fr.centralesupelec.edf.riseclipse.iec61850.nsd, fr.centralesupelec.edf.riseclipse.iec61850.nsd.edit, fr.centralesupelec.edf.riseclipse.iec61850.nsd.utilities, - org.eclipse.ocl.xtext.oclinecore + org.eclipse.ocl.xtext.oclinecore, + org.apache.commons.lang3 diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNodeTypeValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNodeTypeValidator.java index f9c0e31..a585eec 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNodeTypeValidator.java +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNodeTypeValidator.java @@ -18,156 +18,29 @@ */ package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd; -import java.util.HashMap; -import java.util.HashSet; - -import org.eclipse.emf.common.util.BasicDiagnostic; -import org.eclipse.emf.common.util.Diagnostic; import org.eclipse.emf.common.util.DiagnosticChain; -import fr.centralesupelec.edf.riseclipse.iec61850.nsd.AbstractLNClass; -import fr.centralesupelec.edf.riseclipse.iec61850.nsd.DataObject; -import fr.centralesupelec.edf.riseclipse.iec61850.nsd.LNClass; import fr.centralesupelec.edf.riseclipse.iec61850.nsd.AnyLNClass; import fr.centralesupelec.edf.riseclipse.iec61850.scl.DO; import fr.centralesupelec.edf.riseclipse.iec61850.scl.LNodeType; -import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL; import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole; public class LNodeTypeValidator { - private String lnClassName; - private HashMap< String, DataObject > dataObjectMap; - private HashMap< String, DOValidator > doValidatorMap; - - public LNodeTypeValidator( LNClass lnClass ) { - this.lnClassName = lnClass.getName(); - this.dataObjectMap = new HashMap<>(); // link between DOI (name) and its respective DataObject - this.doValidatorMap = new HashMap<>(); // link between CDC (name) and its respective DOIValidator - - generateValidators( lnClass ); - - // LNClass hierarchy taken into account - AbstractLNClass parent = lnClass.getRefersToAbstractLNClass(); - while( parent != null ) { - generateValidators( parent ); - parent = parent.getRefersToAbstractLNClass(); - } - - } + private PresenceConditionValidator presenceConditionValidator; - private void generateValidators( AnyLNClass lnClass ) { - for( DataObject dObj : lnClass.getDataObject() ) { - dataObjectMap.put( dObj.getName(), dObj ); - if( dObj.getRefersToCDC() != null ) { - if( ! doValidatorMap.containsKey( dObj.getRefersToCDC().getName() )) { - doValidatorMap.put( dObj.getRefersToCDC().getName(), new DOValidator( dObj.getRefersToCDC() )); - } - } - } + public LNodeTypeValidator( AnyLNClass lnClass ) { + presenceConditionValidator = PresenceConditionValidator.get( lnClass ); } public boolean validateLNodeType( LNodeType lNodeType, DiagnosticChain diagnostics ) { AbstractRiseClipseConsole.getConsole().verbose( "[NSD] validateLNodeType( " + lNodeType.getId() + " )" ); - boolean res = true; - - HashSet< String > checkedDO = new HashSet<>(); - + presenceConditionValidator.reset(); for( DO do_ : lNodeType.getDO() ) { - AbstractRiseClipseConsole.getConsole().verbose( "[NSD] validateDO( " + do_.getName() + " )" ); - - // Test if DOI is a possible DOI in this LN - if( ! dataObjectMap.containsKey( do_.getName() ) ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD] DO " + do_.getName() + " in LN at line " + lNodeType.getLineNumber() + " not found in LNClass " + lNodeType.getLnClass(), - new Object[] { lNodeType } )); - continue; - } - - // Control of DOI presence in LN - updateCompulsory( do_, checkedDO, diagnostics ); - - // Validation of DOI content - if( ! validateDO( do_, diagnostics ) ) { - res = false; - } - - } - - // Verify all necessary DOI were present - if( ! dataObjectMap.values().stream() - .map( x -> checkCompulsory( lNodeType, x, checkedDO, diagnostics )) - .reduce( ( a, b ) -> a && b ).get() ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD] LNodeType at line " + lNodeType.getLineNumber() + " does not contain all mandatory DO from class " + lNodeType.getLnClass(), - new Object[] { lNodeType } )); - res = false; - } - return res; - } - - private boolean checkCompulsory( LNodeType lNodeType, DataObject dataObject, HashSet< String > checkedDO, DiagnosticChain diagnostics ) { - switch( dataObject.getPresCond() ) { - case "M": - if( ! checkedDO.contains( dataObject.getName() ) ) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD] DO " + dataObject.getName() + " is missing in LN at line " + lNodeType.getLineNumber(), - new Object[] { lNodeType } )); - return false; - } - break; - default: - AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: AnyLNValidator.checkCompulsory( " + dataObject.getPresCond() + " )" ); - break; + presenceConditionValidator.addDO( do_, diagnostics ); } - return true; - } - - private boolean updateCompulsory( DO do_, HashSet< String > checkedDO, DiagnosticChain diagnostics ) { - switch( dataObjectMap.get( do_.getName() ).getPresCond() ) { - case "M": - case "O": - if( checkedDO.contains( do_.getName() )) { - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD] DO " + do_ + " cannot appear more than once in LN at line " + do_.getParentLNodeType().getLineNumber(), - new Object[] { do_ } )); - return false; - } - checkedDO.add( do_.getName() ); - break; - case "F": - diagnostics.add( new BasicDiagnostic( - Diagnostic.ERROR, - RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, - 0, - "[NSD] DO " + do_ + " is forbidden in LN at line " + do_.getParentLNodeType().getLineNumber(), - new Object[] { do_ } )); - return false; - default: - AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: AnyLNValidator.updateCompulsory( " + dataObjectMap.get( do_.getName() ).getPresCond() + " )" ); - break; - } - return true; - } - - private boolean validateDO( DO do_, DiagnosticChain diagnostics ) { - AbstractRiseClipseConsole.getConsole().verbose( "[NSD] found DO " + do_.getName() + " in LNClass " + lnClassName ); - - // DOIValidator validates DOI content - String cdc = dataObjectMap.get( do_.getName() ).getRefersToCDC().getName(); - return doValidatorMap.get( cdc ).validateDO( do_, diagnostics ); + + return presenceConditionValidator.validate( lNodeType, diagnostics ); } } diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/NsdEObjectValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/NsdEObjectValidator.java index b428306..8820de5 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/NsdEObjectValidator.java +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/NsdEObjectValidator.java @@ -90,7 +90,7 @@ public class NsdEObjectValidator implements EValidator { @Override public Boolean caseAnyLN( AnyLN anyLN ) { - return validateAnyLN( anyLN, diagnostics ); + return true;//validateAnyLN( anyLN, diagnostics ); } @Override diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/PresenceConditionValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/PresenceConditionValidator.java new file mode 100644 index 0000000..796051b --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/PresenceConditionValidator.java @@ -0,0 +1,849 @@ +package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map.Entry; + +import org.apache.commons.lang3.tuple.Pair; +import org.eclipse.emf.common.util.BasicDiagnostic; +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.common.util.DiagnosticChain; + +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.AnyLNClass; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.DataObject; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DO; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.LNodeType; +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 PresenceConditionValidator { + + private static HashMap< String, PresenceConditionValidator > validators = new HashMap<>(); + + public static PresenceConditionValidator get( AnyLNClass anyLNClass ) { + if( ! validators.containsKey( anyLNClass.getName() )) { + validators.put( anyLNClass.getName(), new PresenceConditionValidator( anyLNClass )); + } + return validators.get( anyLNClass.getName() ); + } + + private AnyLNClass anyLNClass; + private PresenceConditionValidator base; + + // Name of the DataObject/DO, DO + private HashMap< String, DO > presentDO = 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 HashMap< Integer, 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(); + + private PresenceConditionValidator( AnyLNClass anyLNClass ) { + this.anyLNClass = anyLNClass; + + for( DataObject dObj : anyLNClass.getDataObject() ) { + addSpecification( dObj.getName(), dObj.getPresCond(), dObj.getPresCondArgs() ); + } + checkSpecification(); + + AnyLNClass parent = anyLNClass.getRefersToAbstractLNClass(); + if( parent != null ) { + base = get( parent ); + } + } + + public void reset() { + presentDO = new HashMap<>(); + + if( base != null ) base.reset(); + } + + private void addSpecification( String name, String presCond, String presCondArgs ) { + if( presentDO.containsKey( name )) { + console.warning( "[NSD] " + name + " has already been added to PresenceConditionValidator" ); + return; + } + presentDO.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] NOT IMPLEMENTED" + 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 and no example found + console.warning( "[NSD] NOT IMPLEMENTED" + 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 and no example found + console.warning( "[NSD] NOT IMPLEMENTED" + 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: 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: 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 HashMap<>(); + try { + Integer arg = Integer.valueOf( presCondArgs ); + if( arg <= 0 ) { + console.warning( "NSD: argument of PresenceCondition \"AtMostOne\" is not a positive integer" ); + break; + } + if( ! atMostOne.containsKey( arg )) { + atMostOne.put( arg, new HashSet<>() ); + } + atMostOne.get( arg ).add( name ); + break; + } + catch( NumberFormatException e ) { + console.warning( "NSD: argument of PresenceCondition \"AtMostOne\" is not an integer" ); + 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: 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: 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: 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: 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: 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: 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: argument of PresenceCondition \"MOcond\" is not a positive integer" ); + break; + } + mandatoryIfTextConditionElseOptional.put( name, presCondArgs ); + break; + } + catch( NumberFormatException e ) { + console.warning( "NSD: 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: argument of PresenceCondition \"MFcond\" is not a positive integer" ); + break; + } + mandatoryIfTextConditionElseForbidden.put( name, presCondArgs ); + break; + } + catch( NumberFormatException e ) { + console.warning( "NSD: 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: argument of PresenceCondition \"MFcond\" is not a positive integer" ); + break; + } + optionalIfTextConditionElseForbidden.put( name, presCondArgs ); + break; + } + catch( NumberFormatException e ) { + console.warning( "NSD: 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 and no example found + if( mandatoryMultiRange == null ) mandatoryMultiRange = new HashMap<>(); + String[] limits1 = presCondArgs.split( "\\d[ ,]+\\d" ); + if( limits1.length != 2 ) { + console.warning( "NSD: argument of PresenceCondition \"MmultiRange\" is not two integers" ); + break; + } + Integer min1 = Integer.valueOf( limits1[0] ); + if( min1 <= 0 ) { + console.warning( "NSD: first argument of PresenceCondition \"MmultiRange\" is not a positive integer" ); + break; + } + Integer max1 = Integer.valueOf( limits1[1] ); + if( max1 <= 0 ) { + console.warning( "NSD: 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 and no example found + if( optionalMultiRange == null ) optionalMultiRange = new HashMap<>(); + String[] limits2 = presCondArgs.split( "\\d[ ,]+\\d" ); + if( limits2.length != 2 ) { + console.warning( "NSD: argument of PresenceCondition \"OmultiRange\" is not two integers" ); + break; + } + Integer min2 = Integer.valueOf( limits2[0] ); + if( min2 <= 0 ) { + console.warning( "NSD: first argument of PresenceCondition \"OmultiRange\" is not a positive integer" ); + break; + } + Integer max2 = Integer.valueOf( limits2[1] ); + if( max2 <= 0 ) { + console.warning( "NSD: 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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 + 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" ? + 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) + 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> + if( optionalIfPhsRefIsSynchrophasorElseMandatory == null ) optionalIfPhsRefIsSynchrophasorElseMandatory = new HashSet<>(); + optionalIfPhsRefIsSynchrophasorElseMandatory.add( name ); + break; + default: + console.warning( "[NSD] the PresenceCondition " + presCond + " of AnyLNClass " + name + " is unknown" ); + break; + } + + } + + private void checkSpecification() { + if( mandatoryIfSiblingPresentElseForbidden != null ) { + for( Entry< String, String > e : mandatoryIfSiblingPresentElseForbidden.entrySet() ) { + if( ! presentDO.containsKey( e.getValue() )) { + console.warning( "[NSD] the sibling of " + e.getKey() + " in PresenceCondition od DataObject " + e.getKey() + " is unknown" ); + } + } + } + if( mandatoryIfSiblingPresentElseOptional != null ) { + for( Entry< String, String > e : mandatoryIfSiblingPresentElseOptional.entrySet() ) { + if( ! presentDO.containsKey( e.getValue() )) { + console.warning( "[NSD] the sibling of " + e.getKey() + " in PresenceCondition od DataObject " + e.getKey() + " is unknown" ); + } + } + } + if( optionalIfSiblingPresentElseMandatory != null ) { + for( Entry< String, String > e : optionalIfSiblingPresentElseMandatory.entrySet() ) { + if( ! presentDO.containsKey( e.getValue() )) { + console.warning( "[NSD] the sibling of " + e.getKey() + " in PresenceCondition od DataObject " + e.getKey() + " is unknown" ); + } + } + } + if( forbiddenIfSiblingPresentElseMandatory != null ) { + for( Entry< String, String > e : forbiddenIfSiblingPresentElseMandatory.entrySet() ) { + if( ! presentDO.containsKey( e.getValue() )) { + console.warning( "[NSD] the sibling of " + e.getKey() + " in PresenceCondition od DataObject " + e.getKey() + " is unknown" ); + } + } + } + if( oneOrMoreIfSiblingPresentElseForbidden != null ) { + for( Entry< String, String > e : oneOrMoreIfSiblingPresentElseForbidden.entrySet() ) { + if( ! presentDO.containsKey( e.getValue() )) { + console.warning( "[NSD] the sibling of " + e.getKey() + " in PresenceCondition od DataObject " + e.getKey() + " is unknown" ); + } + } + } + if( optionalIfSiblingPresentElseForbidden != null ) { + for( Entry< String, String > e : optionalIfSiblingPresentElseForbidden.entrySet() ) { + if( ! presentDO.containsKey( e.getValue() )) { + console.warning( "[NSD] the sibling of " + e.getKey() + " in PresenceCondition od DataObject " + e.getKey() + " is unknown" ); + } + } + } + } + + public boolean addDO( DO do_, DiagnosticChain diagnostics ) { + if( ! presentDO.containsKey( do_.getName() )) { + if( base != null ) { + return base.addDO( do_, diagnostics ); + } + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD] DO " + do_.getName() + " in LNodeType (line " + do_.getParentLNodeType().getLineNumber() + ") not found in LNClass " + anyLNClass.getName(), + new Object[] { do_ } )); + return false; + } + + if( presentDO.get( do_.getName() ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD] DO " + do_.getName() + " in LNodeType (line " + do_.getParentLNodeType().getLineNumber() + ") already present in LNClass " + anyLNClass.getName(), + new Object[] { do_ } )); + return false; + } + presentDO.put( do_.getName(), do_ ); + return true; + } + + public boolean validate( LNodeType lNodeType, DiagnosticChain diagnostics ) { + boolean res = true; + + // presCond: "M" + // Element is mandatory + if( mandatory != null ) { + for( String name : this.mandatory ) { + if( presentDO.get( name ) == null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD] DO " + name + " is mandatory in LNodeType (line " + lNodeType.getLineNumber() + ") with LNClass " + anyLNClass.getName(), + new Object[] { lNodeType } )); + res = false; + } + } + } + + // presCond: "O" + // Element is optional + // Nothing to do + + // presCond: "F" + // Element is forbidden + if( forbidden != null ) { + for( String name : this.forbidden ) { + if( presentDO.get( name ) != null ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD] DO " + name + " is forbidden in LNodeType (line " + lNodeType.getLineNumber() + ") with LNClass " + anyLNClass.getName(), + new Object[] { lNodeType } )); + res = false; + } + } + } + + // presCond: "na" + // Element is not applicable + // -> TODO: what does it mean ? what do we have to check ? + + // presCond: "Mmulti" + // At least one element shall be present; all instances have an instance number > 0 + // -> TODO: not sure what is the instance number and no example found + + // presCond: "Omulti" + // Zero or more elements may be present; all instances have an instance number > 0 + // -> TODO: not sure what is the instance number and no example found + + // presCond: "AtLeastOne" + // Parameter n: group number (> 0). + // At least one of marked elements of a group n shall be present + if( atLeastOne != null ) { + for( Entry< Integer, HashSet< String > > e1 : atLeastOne.entrySet() ) { + boolean groupOK = false; + for( String member : e1.getValue() ) { + if( presentDO.get( member ) != null ) { + groupOK = true; + break; + } + } + if( ! groupOK ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD] group " + e1.getKey() + " has no elements in LNodeType (line " + lNodeType.getLineNumber() + ") with LNClass " + anyLNClass.getName(), + new Object[] { lNodeType } )); + res = false; + } + } + } + // presCond: "AtMostOne" : + // At most one of marked elements shall be present + if( atMostOne != null ) { + for( Entry< Integer, HashSet< String > > e1 : atMostOne.entrySet() ) { + int groupCount = 0; + for( String member : e1.getValue() ) { + if( presentDO.get( member ) != null ) { + ++groupCount; + } + } + if( groupCount > 1 ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD] group " + e1.getKey() + " has more than one element in LNodeType (line " + lNodeType.getLineNumber() + ") with LNClass " + anyLNClass.getName(), + new Object[] { lNodeType } )); + res = false; + } + } + } + // presCond: "AllOrNonePerGroup" : + // Parameter n: group number (> 0). + // All or none of the elements of a group n shall be present + if( allOrNonePerGroup != null ) { + for( Entry< Integer, HashSet< String > > e1 : allOrNonePerGroup.entrySet() ) { + int groupCount = 0; + for( String member : e1.getValue() ) { + if( presentDO.get( member ) != null ) { + ++groupCount; + } + } + if(( groupCount > 0 ) && (groupCount < e1.getValue().size() )) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD] group " + e1.getKey() + " has neither none nor all elements in LNodeType (line " + lNodeType.getLineNumber() + ") with LNClass " + anyLNClass.getName(), + new Object[] { lNodeType } )); + res = false; + } + } + } + // presCond: "AllOnlyOneGroup" : + // Parameter n: group number (> 0). + // All elements of only one group n shall be present + if( allOnlyOneGroup != null ) { + int groupNumber = 0; + for( Entry< Integer, HashSet< String > > e1 : allOnlyOneGroup.entrySet() ) { + int groupCount = 0; + for( String member : e1.getValue() ) { + if( presentDO.get( member ) != null ) { + ++groupCount; + } + } + if(( groupCount > 0 ) && (groupCount < e1.getValue().size() )) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD] group " + e1.getKey() + " has neither none nor all elements in LNodeType (line " + lNodeType.getLineNumber() + ") with LNClass " + anyLNClass.getName(), + new Object[] { lNodeType } )); + res = false; + } + else if( groupCount > 0 ) { + if( groupNumber == 0 ) { + groupNumber = e1.getKey(); + } + else { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD] LNodeType (line " + lNodeType.getLineNumber() + ") with LNClass " + anyLNClass.getName() + " has several groups with all elements", + new Object[] { lNodeType } )); + res = false; + } + } + } + if( groupNumber == 0 ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "[NSD] no group in LNodeType (line " + lNodeType.getLineNumber() + ") with LNClass " + anyLNClass.getName() + " has all elements", + new Object[] { lNodeType } )); + res = false; + } + } + // presCond: "AllAtLeastOneGroup" : + // Parameter n: group number (> 0). + // All elements of at least one group n shall be present + if( allAtLeastOneGroup != null ) { + int groupNumber = 0; + for( Entry< Integer, HashSet< String > > e1 : allAtLeastOneGroup.entrySet() ) { + int groupCount = 0; + for( String member : e1.getValue() ) { + if( presentDO.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] no group in LNodeType (line " + lNodeType.getLineNumber() + ") with LNClass " + anyLNClass.getName() + " has all elements", + new Object[] { lNodeType } )); + res = false; + } + } + /* + // presCond: "MF" : + // Parameter sibling: sibling element name. + // Mandatory if sibling element is present, otherwise forbidden + mandatoryIfSiblingPresentElseForbidden.put( name, Pair.of( mandatoryIfSiblingPresentElseForbidden.get( name ).getKey(), true )); + // presCond: "MO" : + // Parameter sibling: sibling element name. + // Mandatory if sibling element is present, otherwise optional + mandatoryIfSiblingPresentElseOptional.put( name, Pair.of( mandatoryIfSiblingPresentElseOptional.get( name ).getKey(), true )); + // presCond: "OM" : + // Parameter sibling: sibling element name. + // Optional if sibling element is present, otherwise mandatory + optionalIfSiblingPresentElseMandatory.put( name, Pair.of( optionalIfSiblingPresentElseMandatory.get( name ).getKey(), true )); + // presCond: "FM" : + // Parameter sibling: sibling element name. + // Forbidden if sibling element is present, otherwise mandatory + forbiddenIfSiblingPresentElseMandatory.put( name, Pair.of( forbiddenIfSiblingPresentElseMandatory.get( name ).getKey(), true )); + // 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 + mandatoryIfTextConditionElseOptional.put( name, Pair.of( mandatoryIfTextConditionElseOptional.get( name ).getKey(), false )); + // 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 + mandatoryIfTextConditionElseForbidden.put( name, Pair.of( mandatoryIfTextConditionElseForbidden.get( name ).getKey(), false )); + // 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 + optionalIfTextConditionElseForbidden.put( name, Pair.of( optionalIfTextConditionElseForbidden.get( name ).getKey(), false )); + // 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) + // -> TODO: not sure what is the instance number and no example found + mandatoryMultiRange.put( name, Pair.of( Pair.of( min1, max1 ), new HashSet<>() )); + // 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) + // -> TODO: not sure what is the instance number and no example found + optionalMultiRange.put( name, Pair.of( Pair.of( min2, max2 ), new HashSet<>() )); + // presCond: "MFsubst" : + // Element is mandatory if substitution is supported (for substitution, see IEC 61850-7-3), otherwise forbidden + mandatoryIfSubstitutionElseForbidden.put( name, false ); + // presCond: "MOln0" : + // Element is mandatory in the context of LLN0; otherwise optional + mandatoryInLLN0ElseOptional.put( name, false ); + // presCond: "MFln0" : + // Element is mandatory in the context of LLN0; otherwise forbidden + mandatoryInLLN0ElseForbidden.put( name, false ); + // 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 + mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional.put( name, false ); + // 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 + mandatoryIfNameSpaceOfDataObjectDeviatesElseOptional.put( name, false ); + // 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 + mandatoryIfAnalogValueIncludesIElseForbidden.put( name, false ); + // 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 + mandatoryIfVectorSiblingIncludesIAsChildMagElseForbidden.put( name, false ); + // 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 + mandatoryIfVectorSiblingIncludesIAsChildAngElseForbidden.put( name, false ); + // 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 + mandatoryIfHarmonicValuesCalculatedAsRatioElseOptional.put( name, false ); + // presCond: "MOrootLD" : + // Element is mandatory in the context of a root logical device; otherwise it is optional + mandatoryInRootLogicalDeviceElseOptional.put( name, false ); + // presCond: "MOoperTm" : + // Element is mandatory if at least one controlled object on the IED supports time activation service; otherwise it is optional + mandatoryIfControlSupportsTimeElseOptional.put( name, false ); + // presCond: "MmultiF" : + // Parameter sibling: sibling element name. + // One or more elements must be present if sibling element is present, otherwise forbidden + oneOrMoreIfSiblingPresentElseForbidden.put( name, Pair.of( presCondArgs, false )); + // 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 + mandatoryIfControlSupportsSecurity1ElseOptional.put( name, false ); + // 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 + mandatoryIfControlSupportsSecurity2ElseOptional.put( name, false ); + // 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 + // TODO: same as "MOlnNs" ? + mandatoryIfNameSpaceOfLogicalNodeDeviatesElseOptional2.put( name, false ); + // presCond: "OF" : + // Parameter sibling: sibling element name. + // Optional if sibling element is present, otherwise forbidden + optionalIfSiblingPresentElseForbidden.put( name, Pair.of( presCondArgs, false )); + // presCond: "MORange" : + // Element is mandatory if the measured value associated (amplitude respectively angle) exposes the range eventing + // (with the attribute range respectively rangeAng) + mandatoryIfMeasuredValueExposesRange.put( name, false ); + // presCond: "OMSynPh" : + // This attribute is optional if value of 'phsRef'' is Synchrophasor otherwise Mandatory]]></Doc> + optionalIfPhsRefIsSynchrophasorElseMandatory.put( name, false ); +*/ + return res; + } + +} -- GitLab