diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DOValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DOValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..9e61f5d7edf2360632fffaa3101993a0fa879192 --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/DOValidator.java @@ -0,0 +1,145 @@ +/** + * Copyright (c) 2019 CentraleSupélec & EDF. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * This file is part of the RiseClipse tool + * + * Contributors: + * Computer Science Department, CentraleSupélec + * EDF R&D + * Contacts: + * dominique.marcadet@centralesupelec.fr + * aurelie.dehouck-neveu@edf.fr + * Web site: + * http://wdi.supelec.fr/software/RiseClipse/ + */ +package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd; + +import java.util.HashMap; +import java.util.HashSet; + +import org.eclipse.emf.common.util.BasicDiagnostic; +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.common.util.DiagnosticChain; + +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.CDC; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.DataAttribute; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DO; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL; +import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole; + +public class DOValidator { + + private String cdc; + private HashMap< String, DataAttribute > daMap; + + public DOValidator( CDC cdc ) { + this.cdc = cdc.getName(); + this.daMap = new HashMap<>(); // link between DAI (name) and its respective DataAttribute + + for( DataAttribute da : cdc.getDataAttribute() ) { + this.daMap.put( da.getName(), da ); + } + } + + public boolean validateDO( DO do_, DiagnosticChain diagnostics ) { + AbstractRiseClipseConsole.getConsole().verbose( "validateDO( " + do_.getName() + " )" ); + boolean res = true; + HashSet< String > checkedDA = new HashSet<>(); + + if( do_.getRefersToDOType() == null ) { + AbstractRiseClipseConsole.getConsole().warning( "validateDO: DO " + do_.getName() + " has no RefersToDOType" ); + } + else { + for( DA da : do_.getRefersToDOType().getDA() ) { + AbstractRiseClipseConsole.getConsole().verbose( "validateDO on DA " + da.getName() + " (line" + da.getLineNumber() + ")" ); + + // Test if DA is a possible DA in this DO + if( ! daMap.containsKey( da.getName() ) ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "DA " + da.getName() + " (line" + da.getLineNumber() + ") not found in CDC", + new Object[] { do_, cdc } )); + res = false; + continue; + } + + // Control of DAI presence in DO + updateCompulsory( da, checkedDA, diagnostics ); + } + } + + // Verify all necessary DA were present + if( ! daMap.values().stream() + .map( x -> checkCompulsory( do_, x, checkedDA, diagnostics ) ) + .reduce( ( a, b ) -> a && b ).get() ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "DO (line " + do_.getLineNumber() + ") does not contain all mandatory DA from CDC ", + new Object[] { do_, cdc } )); + res = false; + } + return res; + } + + public boolean checkCompulsory( DO do_, DataAttribute da, HashSet< String > checked, DiagnosticChain diagnostics ) { + switch( da.getPresCond() ) { + case "M": + if( ! checked.contains( da.getName() )) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "DA " + da.getName() + " not found in DO (line " + do_.getLineNumber() + ")", + new Object[] { da } )); + return false; + } + break; + default: + AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: DOValidator.checkCompulsory( " + da.getPresCond() + " )" ); + break; + } + return true; + } + + public boolean updateCompulsory( DA da, HashSet< String > checked, DiagnosticChain diagnostics ) { + switch( daMap.get( da.getName() ).getPresCond() ) { + case "M": + case "O": + if( checked.contains( da.getName() ) ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "DA " + da.getName() + " (line " + da.getLineNumber() + ") cannot appear more than once", + new Object[] { da } )); + return false; + } + else { + checked.add( da.getName() ); + break; + } + case "F": + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "DA " + da.getName() + " (line " + da.getLineNumber() + ") is forbidden", + new Object[] { da } )); + return false; + default: + AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: DOIValidator.updateCompulsory( " + daMap.get( da.getName() ).getPresCond() + " )" ); + break; + } + return true; + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..b288c585b55777dbde4b8090f86cc5d65eacf049 --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/LNodeTypeValidator.java @@ -0,0 +1,173 @@ +/** + * Copyright (c) 2019 CentraleSupélec & EDF. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * This file is part of the RiseClipse tool + * + * Contributors: + * Computer Science Department, CentraleSupélec + * EDF R&D + * Contacts: + * dominique.marcadet@centralesupelec.fr + * aurelie.dehouck-neveu@edf.fr + * Web site: + * http://wdi.supelec.fr/software/RiseClipse/ + */ +package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.nsd; + +import java.util.HashMap; +import java.util.HashSet; + +import org.eclipse.emf.common.util.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 lnClass; + private HashMap< String, DataObject > doMap; + private HashMap< String, DOValidator > cdcMap; + + public LNodeTypeValidator( LNClass lnClass ) { + this.lnClass = lnClass.getName(); + this.doMap = new HashMap<>(); // link between DOI (name) and its respective DataObject + this.cdcMap = new HashMap<>(); // link between CDC (name) and its respective DOIValidator + + generateValidators( doMap, cdcMap, lnClass ); + + // LNClass hierarchy taken into account + AbstractLNClass parent = lnClass.getRefersToAbstractLNClass(); + while( parent != null ) { + generateValidators( doMap, cdcMap, parent ); + parent = parent.getRefersToAbstractLNClass(); + } + + } + + private void generateValidators( HashMap< String, DataObject > doMap, HashMap< String, DOValidator > cdcMap, AnyLNClass lnClass ) { + for( DataObject dObj : lnClass.getDataObject() ) { + doMap.put( dObj.getName(), dObj ); + if( dObj.getRefersToCDC() != null ) { + if( ! cdcMap.containsKey( dObj.getRefersToCDC().getName() )) { + cdcMap.put( dObj.getRefersToCDC().getName(), new DOValidator( dObj.getRefersToCDC() )); + } + } + } + } + + public boolean validateLNodeType( LNodeType lNodeType, DiagnosticChain diagnostics ) { + boolean res = true; + + HashSet< String > checkedDO = new HashSet<>(); + + for( DO do_ : lNodeType.getDO() ) { + AbstractRiseClipseConsole.getConsole().verbose( "validateDOI( " + do_.getName() + " )" ); + + // Test if DOI is a possible DOI in this LN + if( ! doMap.containsKey( do_.getName() ) ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "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( ! doMap.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, + "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, + "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; + } + return true; + } + + private boolean updateCompulsory( DO do_, HashSet< String > checkedDO, DiagnosticChain diagnostics ) { + switch( doMap.get( do_.getName() ).getPresCond() ) { + case "M": + case "O": + if( checkedDO.contains( do_.getName() )) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "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, + "DO " + do_ + " is forbidden in LN at line " + do_.getParentLNodeType().getLineNumber(), + new Object[] { do_ } )); + return false; + default: + AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: AnyLNValidator.updateCompulsory( " + doMap.get( do_.getName() ).getPresCond() + " )" ); + break; + } + return true; + } + + private boolean validateDO( DO do_, DiagnosticChain diagnostics ) { + + AbstractRiseClipseConsole.getConsole().verbose( "found DO " + do_.getName() + " in LNClass " + lnClass ); + + // DOIValidator validates DOI content + String cdc = doMap.get( do_.getName() ).getRefersToCDC().getName(); + return cdcMap.get( cdc ).validateDO( do_, 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 82f1af1e4d6ba1527dbc30401a17fd8a3dced188..730555c3790a24535bea17ea002965e6cb0dbf11 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 @@ -31,33 +31,49 @@ import org.eclipse.emf.ecore.EValidator; import fr.centralesupelec.edf.riseclipse.iec61850.nsd.LNClass; import fr.centralesupelec.edf.riseclipse.iec61850.nsd.util.NsdResourceSetImpl; import fr.centralesupelec.edf.riseclipse.iec61850.scl.AnyLN; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.LNodeType; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.util.SclSwitch; import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL; import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole; public class NsdEObjectValidator implements EValidator { private NsdResourceSetImpl nsdResourceSet; - private HashMap< String, AnyLNValidator > lnMap; + private HashMap< String, AnyLNValidator > anyLNValidatorMap; + private HashMap<String,LNodeTypeValidator> lNodeTypeValidatorMap; public NsdEObjectValidator( NsdResourceSetImpl nsdResourceSet ) { this.nsdResourceSet = nsdResourceSet; } public void initializeValidationData() { - this.lnMap = this.nsdResourceSet.getLNClassStream() - .map( lnClass -> generateValidators( lnClass ) ) + this.anyLNValidatorMap = this.nsdResourceSet.getLNClassStream() + .map( lnClass -> generateAnyLNValidators( lnClass ) ) + .reduce( ( a, b ) -> { + a.putAll( b ); + return a; + } ).get(); + + this.lNodeTypeValidatorMap = this.nsdResourceSet.getLNClassStream() + .map( lnClass -> generateLNodeTypeValidators( lnClass ) ) .reduce( ( a, b ) -> { a.putAll( b ); return a; } ).get(); } - private HashMap< String, AnyLNValidator > generateValidators( LNClass lnClass ) { + private HashMap< String, AnyLNValidator > generateAnyLNValidators( LNClass lnClass ) { HashMap< String, AnyLNValidator > lnMap = new HashMap<>(); lnMap.put( lnClass.getName(), new AnyLNValidator( lnClass )); return lnMap; } + private HashMap< String, LNodeTypeValidator > generateLNodeTypeValidators( LNClass lnClass ) { + HashMap< String, LNodeTypeValidator > lNodeTypeMap = new HashMap<>(); + lNodeTypeMap.put( lnClass.getName(), new LNodeTypeValidator( lnClass )); + return lNodeTypeMap; + } + @Override public boolean validate( EObject eObject, DiagnosticChain diagnostics, Map< Object, Object > context ) { return validate( eObject.eClass(), eObject, diagnostics, context ); @@ -66,19 +82,31 @@ public class NsdEObjectValidator implements EValidator { @Override public boolean validate( EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map< Object, Object > context ) { - if( this.lnMap == null ) { + if( this.anyLNValidatorMap == null ) { this.initializeValidationData(); } - - switch( eClass.getName() ) { - case "LN0": - case "LN": - AnyLN ln = ( AnyLN ) eObject; - return validateLN( ln, diagnostics ); - default: - AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: NsdEObjectValidator.validate( " + eClass.getName() + " )" ); - return false; - } + + SclSwitch< Boolean > sw = new SclSwitch< Boolean >() { + + @Override + public Boolean caseAnyLN( AnyLN anyLN ) { + return validateAnyLN( anyLN, diagnostics ); + } + + @Override + public Boolean caseLNodeType( LNodeType lNodeType ) { + return validateLNodeType( lNodeType, diagnostics ); + } + + @Override + public Boolean defaultCase( EObject object ) { + AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: NsdEObjectValidator.validate( " + object.eClass().getName() + " )" ); + return true; + } + + }; + + return sw.doSwitch( eObject ); } @Override @@ -90,12 +118,12 @@ public class NsdEObjectValidator implements EValidator { return true; } - private boolean validateLN( AnyLN ln, DiagnosticChain diagnostics ) { + private boolean validateAnyLN( AnyLN ln, DiagnosticChain diagnostics ) { AbstractRiseClipseConsole.getConsole().verbose( "" ); AbstractRiseClipseConsole.getConsole().verbose( "NsdEObjectValidator.validateLN( " + ln.getLnClass() + " )" ); // Check that LN has valid LNClass - if( ! this.lnMap.containsKey( ln.getLnClass() )) { + if( ! this.anyLNValidatorMap.containsKey( ln.getLnClass() )) { diagnostics.add( new BasicDiagnostic( Diagnostic.ERROR, RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, @@ -107,7 +135,27 @@ public class NsdEObjectValidator implements EValidator { AbstractRiseClipseConsole.getConsole().verbose( "found LNClass " + ln.getLnClass() + " in NSD files for LN at line " + ln.getLineNumber() ); // AnyLNValidator validates LN content - return lnMap.get( ln.getLnClass() ).validateLN( ln, diagnostics ); + return anyLNValidatorMap.get( ln.getLnClass() ).validateLN( ln, diagnostics ); + } + + protected Boolean validateLNodeType( LNodeType lNodeType, DiagnosticChain diagnostics ) { + AbstractRiseClipseConsole.getConsole().verbose( "" ); + AbstractRiseClipseConsole.getConsole().verbose( "NsdEObjectValidator.validateLNodeType( " + lNodeType.getLnClass() + " )" ); + + // Check that LN has valid LNClass + if( ! this.anyLNValidatorMap.containsKey( lNodeType.getLnClass() )) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "LNClass " + lNodeType.getLnClass() + " not found in NSD files for LN at line " + lNodeType.getLineNumber(), + new Object[] { lNodeType } )); + return false; + } + AbstractRiseClipseConsole.getConsole().verbose( "found LNClass " + lNodeType.getLnClass() + " in NSD files for LN at line " + lNodeType.getLineNumber() ); + + // AnyLNValidator validates LN content + return lNodeTypeValidatorMap.get( lNodeType.getLnClass() ).validateLNodeType( lNodeType, diagnostics ); } }