diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/AnyLNValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/AnyLNValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..b20d1093e4b8ffa4efbb5d3b9001d6b3be3bca14 --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/AnyLNValidator.java @@ -0,0 +1,159 @@ +package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.emf.common.util.DiagnosticChain; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EValidator; +import org.eclipse.emf.ecore.resource.Resource; + +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.DocumentRoot; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.FunctionalConstraint; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.AbstractLNClass; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.BasicType; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.CDC; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.DataAttribute; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.DataObject; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.LNClass; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.NS; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.util.NsdResourceSetImpl; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.AnyLN; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DAI; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DOI; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DOType; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.LNode; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.LNodeType; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.Val; +import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole; + +public class AnyLNValidator { + + private String lnClass; + private HashMap<String, DataObject> doMap; + private HashMap<String, DOIValidator> cdcMap; + + + public AnyLNValidator(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(); + } + + } + + public void generateValidators(HashMap<String, DataObject> doMap, HashMap<String, DOIValidator> cdcMap, AbstractLNClass lnClass) { + for(DataObject dObj : lnClass.getDataObject()) { + this.doMap.put(dObj.getName(), dObj); + if (dObj.getRefersToCDC() != null) { + if(!cdcMap.containsKey(dObj.getRefersToCDC().getName())) { + this.cdcMap.put(dObj.getRefersToCDC().getName(), new DOIValidator(dObj.getRefersToCDC())); + } + } + } + } + + public void generateValidators(HashMap<String, DataObject> doMap, HashMap<String, DOIValidator> cdcMap, LNClass lnClass) { + for(DataObject dObj : lnClass.getDataObject()) { + this.doMap.put(dObj.getName(), dObj); + if (dObj.getRefersToCDC() != null) { + if(!cdcMap.containsKey(dObj.getRefersToCDC().getName())) { + this.cdcMap.put(dObj.getRefersToCDC().getName(), new DOIValidator(dObj.getRefersToCDC())); + } + } + } + } + + + public boolean validateLN(AnyLN ln) { + HashSet<String> checkedDO = new HashSet<>(); + + for( DOI doi : ln.getDOI() ) { + AbstractRiseClipseConsole.getConsole().info( "validateDOI( " + doi.getName()+ " )" ); + + // Test if DOI is a possible DOI in this LN + if(!this.doMap.containsKey(doi.getName())) { + AbstractRiseClipseConsole.getConsole().error( "DO " + doi.getName() + " not found in LNClass " + ln.getLnClass()); + return false; + } + + // Control of DOI presence in LN + String presCond = this.doMap.get(doi.getName()).getPresCond(); + this.updateCompulsory(doi.getName(), presCond, checkedDO); + + // Validation of DOI content + if( ! validateDOI(doi) ) { + return false; + } + + } + + // Verify all necessary DOI were present + if(!this.doMap.entrySet().stream().map(x -> checkCompulsory(x.getKey(), x.getValue().getPresCond(), checkedDO)).reduce((a, b) -> a && b).get()) { + AbstractRiseClipseConsole.getConsole().error( "LN does not contain all mandatory DO from class " + ln.getLnClass()); + return false; + } + return true; + } + + public boolean checkCompulsory(String name, String presCond, HashSet<String> checked) { + switch(presCond) { + case "M": + if(!checked.contains(name)) { + AbstractRiseClipseConsole.getConsole().error( "DO "+ name + " is missing"); + return false; + } + } + return true; + } + + public boolean updateCompulsory(String name, String presCond, HashSet<String> checked) { + switch(presCond) { + case "M": + case "O": + if(checked.contains(name)) { + AbstractRiseClipseConsole.getConsole().error("DO " + name + " cannot appear more than once"); + return false; + } else { + checked.add(name); + break; + } + case "F": + AbstractRiseClipseConsole.getConsole().error("DO " + name + " is forbidden"); + return false; + } + return true; + } + + + public boolean validateDOI(DOI doi) { + + AbstractRiseClipseConsole.getConsole().info( "found DO " + doi.getName() + " in LNClass " + this.lnClass); + + // DOIValidator validates DOI content + String cdc = this.doMap.get(doi.getName()).getRefersToCDC().getName(); + return cdcMap.get(cdc).validateDOI(doi); + } + + + public void log(String message) { + AbstractRiseClipseConsole.getConsole().info(message); + } + +} diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/DOIValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/DOIValidator.java new file mode 100644 index 0000000000000000000000000000000000000000..883eeb53031fad815528025a4bc1cce2a431756e --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/DOIValidator.java @@ -0,0 +1,182 @@ +package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import org.eclipse.emf.common.util.DiagnosticChain; +import org.eclipse.emf.common.util.EList; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EValidator; +import org.eclipse.emf.ecore.resource.Resource; + +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.DocumentRoot; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.FunctionalConstraint; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.BasicType; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.CDC; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.DataAttribute; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.DataObject; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.LNClass; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.NS; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.util.NsdResourceSetImpl; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.AnyLN; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DAI; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DOI; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DOType; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.LNode; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.LNodeType; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.Val; +import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole; + +public class DOIValidator { + + private String cdc; + private HashMap<String, DataAttribute> daMap; + + public DOIValidator(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 validateDOI(DOI doi) { + HashSet<String> checkedDA = new HashSet<>(); + + for( DAI dai : doi.getDAI() ) { + AbstractRiseClipseConsole.getConsole().info( "validateDAI( " + dai.getName()+ " )" ); + + // Test if DAI is a possible DAI in this DOI + if(!this.daMap.containsKey(dai.getName())) { + AbstractRiseClipseConsole.getConsole().error( "DA " + dai.getName() + " not found in CDC " + this.cdc); + return false; + } + + // Control of DAI presence in DOI + String presCond = this.daMap.get(dai.getName()).getPresCond(); + this.updateCompulsory(dai.getName(), presCond, checkedDA); + + // Validation of DAI content + if( ! validateDAI(dai) ){ + return false; + } + + } + + // Verify all necessary DAI were present + if(!this.daMap.entrySet().stream().map(x -> checkCompulsory(x.getKey(), x.getValue().getPresCond(), checkedDA)).reduce((a, b) -> a && b).get()) { + AbstractRiseClipseConsole.getConsole().error( "DO does not contain all mandatory DA from CDC " + this.cdc); + return false; + } + return true; + } + + public boolean checkCompulsory(String name, String presCond, HashSet<String> checked) { + switch(presCond) { + case "M": + if(!checked.contains(name)) { + AbstractRiseClipseConsole.getConsole().error( "DA "+ name + " is missing"); + return false; + } + } + return true; + } + + public boolean updateCompulsory(String name, String presCond, HashSet<String> checked) { + switch(presCond) { + case "M": + case "O": + if(checked.contains(name)) { + AbstractRiseClipseConsole.getConsole().error("DA " + name + " cannot appear more than once"); + return false; + } else { + checked.add(name); + break; + } + case "F": + AbstractRiseClipseConsole.getConsole().error("DA " + name + " is forbidden"); + return false; + } + return true; + } + + + public boolean validateDAI(DAI dai) { + + AbstractRiseClipseConsole.getConsole().info( "found DA " + dai.getName() + " in CDC " + this.cdc); + + // DataAttributes that are BASIC have a BasicType which describes allowed Val of DA + DataAttribute da = this.daMap.get(dai.getName()); + if(da.getTypeKind().getName().equals("BASIC")) { + for(Val val : dai.getVal()) { + if( ! validateVal(val.getValue(), da.getType()) ) { + AbstractRiseClipseConsole.getConsole().error( "Val " + val.getValue() + " of DA " + dai.getName() + + " is not of type " + da.getType());; + return false; + } + AbstractRiseClipseConsole.getConsole().info( "Val " + val.getValue() + " of DA " + dai.getName() + + " is of type " + da.getType()); + } + } + + return true; + } + + public boolean validateVal(String val, String type) { + int v; + long l; + float f; + switch(type) { + case "BOOLEAN": + return (val.equals("0") || val.equals("1") || val.equals("false") || val.equals("true")); + case "INT8": + v = Integer.parseInt(val); + return v >= -128 && v <= 127; + case "INT16": + v = Integer.parseInt(val); + return v >= -32768 && v <= 32767; + case "INT32": + v = Integer.parseInt(val); + return v >= Integer.MIN_VALUE && v <= Integer.MAX_VALUE; + case "INT64": + l = Long.parseLong(val); + return l >= Long.MIN_VALUE && l <= Long.MAX_VALUE; + case "INT8U": + v = Integer.parseInt(val); + return v >= 0 && v <= 255; + case "INT16U": + v = Integer.parseInt(val); + return v >= 0 && v <= 65535; + case "INT32U": + l = Long.parseLong(val); + String max = "4294967295"; + return l >= 0 && l <= Long.parseLong(max); + case "FLOAT32": + f = Float.parseFloat(val); + return f >= Float.MIN_VALUE && f <= Float.MAX_VALUE; + case "Octet64": + byte[] bytes = val.getBytes(); + return bytes.length <= 64; + case "VisString64": + return val.length() <= 255; + case "VisString129": + return val.length() <= 129; + case "Unicode255": + case "VisString255": + return val.length() <= 255; + default: + return false; + } + } + + +} diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NsdEObjectValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NsdEObjectValidator.java index d3861e74013a3458c980a444e8181addbd58ea61..06161bcc67e4a5940120b3be15838b5ee2286750 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NsdEObjectValidator.java +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NsdEObjectValidator.java @@ -56,29 +56,24 @@ import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole; public class NsdEObjectValidator implements EValidator { private NsdResourceSetImpl nsdResourceSet; - private HashMap<String, HashMap<String, String>> lnMap; + private HashMap<String, AnyLNValidator> lnMap; - public NsdEObjectValidator( NsdResourceSetImpl nsdResourceSet ) { this.nsdResourceSet = nsdResourceSet; } - + public void initializeValidationData() { this.lnMap= this.nsdResourceSet.getLNClassStream() - .map(lnClass -> generatePresenceMap(lnClass)) + .map(lnClass -> generateValidators(lnClass)) .reduce((a, b) -> {a.putAll(b); return a;}).get(); - log(this.lnMap.toString()); } - - public HashMap<String, HashMap<String, String>> generatePresenceMap (LNClass lnClass) { - HashMap<String, HashMap<String, String>> lnDOMap = new HashMap<>(); - HashMap<String, String> doMap = new HashMap<>(); - for(DataObject dObj : lnClass.getDataObject()) { - doMap.put(dObj.getName(), dObj.getPresCond()); - } - lnDOMap.put(lnClass.getName(), doMap); - return lnDOMap; + + public HashMap<String, AnyLNValidator> generateValidators(LNClass lnClass) { + HashMap<String, AnyLNValidator> lnMap = new HashMap<>(); + lnMap.put(lnClass.getName(), new AnyLNValidator(lnClass)); + return lnMap; } + @Override public boolean validate( EObject eObject, DiagnosticChain diagnostics, Map< Object, Object > context ) { @@ -88,6 +83,11 @@ public class NsdEObjectValidator implements EValidator { @Override public boolean validate( EClass eClass, EObject eObject, DiagnosticChain diagnostics, Map< Object, Object > context ) { + + if(this.lnMap == null) { + this.initializeValidationData(); + } + switch(eClass.getName()) { case "LN0": case "LN": @@ -102,7 +102,7 @@ public class NsdEObjectValidator implements EValidator { public boolean validate( EDataType eDataType, Object value, DiagnosticChain diagnostics, Map< Object, Object > context ) { //AbstractRiseClipseConsole.getConsole().info( "NSDEObjectValidator.validate( EDataType ): " + eDataType.getName() ); - + // TODO: use nsdResource to validate value @@ -110,6 +110,22 @@ public class NsdEObjectValidator implements EValidator { } + public boolean validateLN(AnyLN ln) { + AbstractRiseClipseConsole.getConsole().info(""); + AbstractRiseClipseConsole.getConsole().info( "NSDEObjectValidator.validateLN( " + ln.getLnClass() + " )" ); + + //LN has valid LNClass + if( ! this.lnMap.containsKey(ln.getLnClass()) ) { + AbstractRiseClipseConsole.getConsole().error( "LNClass " + ln.getLnClass() + " not found in NSD files" ); + return false; + } + AbstractRiseClipseConsole.getConsole().info( "found LNClass " + ln.getLnClass() + " in NSD files" ); + + //AnyLNValidator validates LN content + return lnMap.get(ln.getLnClass()).validateLN(ln); + } + + /* public boolean validateLN(AnyLN ln) { AbstractRiseClipseConsole.getConsole().info(""); AbstractRiseClipseConsole.getConsole().info(""); @@ -130,7 +146,7 @@ public class NsdEObjectValidator implements EValidator { return false; } AbstractRiseClipseConsole.getConsole().info( "found LNClass " + ln.getLnClass() + " in NSD files" ); - */ + // lnClassFound contains DataObject which describes allowed DOI in LN for( DOI doi : ln.getDOI() ) { @@ -167,7 +183,9 @@ public class NsdEObjectValidator implements EValidator { } return true; } + */ + /* public boolean checkCompulsory(String dObj, String presCond, HashSet<String> checked) { switch(presCond) { case "M": @@ -178,14 +196,16 @@ public class NsdEObjectValidator implements EValidator { } return true; } + */ - + /* public boolean validateDO(DOI doi) { return true; } - + */ + /* - public boolean validateDO(EList<DOI> lnDOI, LNClass lnClassFound) { + public boolean validateDO(EList<DOI> lnDOI, LNClass lnClassFound) { for( DOI doi : lnDOI ) { Optional< DataObject > dataObjectFound = lnClassFound.getDataObject().stream().filter( dataObject -> dataObject.getName().equals( doi.getName()) ).findAny(); AbstractRiseClipseConsole.getConsole().info(" "); @@ -353,6 +373,7 @@ public class NsdEObjectValidator implements EValidator { } */ + /* public boolean validateVal(String val, String type) { int v; long l; @@ -399,7 +420,7 @@ public class NsdEObjectValidator implements EValidator { return false; } } - + */ public void log(String message) { AbstractRiseClipseConsole.getConsole().info(message); diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NsdValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NsdValidator.java index 5d105c4b8df1d85dffcc44331c33968c97553021..6a8a2751b30cd24a674198cd5766e307562d11d8 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NsdValidator.java +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NsdValidator.java @@ -79,7 +79,7 @@ public class NsdValidator { } }; context.put(EValidator.SubstitutionLabelProvider.class, substitutionLabelProvider ); - + for( int n = 0; n < resource.getContents().size(); ++n ) { Diagnostic diagnostic = Diagnostician.INSTANCE.validate( resource.getContents().get( n ), context ); diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/RiseClipseValidatorSCL.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/RiseClipseValidatorSCL.java index 13135860f36e80bdb185490e19416c1d7cbcc968..c4ff345007f995dc9868dbc9d001af9b80cdbe5e 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/RiseClipseValidatorSCL.java +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/RiseClipseValidatorSCL.java @@ -142,16 +142,17 @@ public class RiseClipseValidatorSCL { nsdValidator.addNsdDocument( nsdFiles.get( i ), console ); } //nsdAdapter = new NsdItemProviderAdapterFactory(); - for(EValidator v: validator.getChildren()) { - if(v.getClass() == NsdEObjectValidator.class) { - NsdEObjectValidator nsdValidator = (NsdEObjectValidator) v; - nsdValidator.initializeValidationData(); - } - } } sclLoader = new SCLModelLoader( console ); sclAdapter = new SclItemProviderAdapterFactory(); + + /*for(EValidator v: validator.getChildren()) { + if(v.getClass() == NsdEObjectValidator.class) { + NsdEObjectValidator nsdValidator = (NsdEObjectValidator) v; + nsdValidator.initializeValidationData(); + } + }*/ } public static void run( IRiseClipseConsole console, boolean make_explicit_links, String sclFile ) {