From 2dca1b4f95fe62eef595cde5509e850973838707 Mon Sep 17 00:00:00 2001
From: Dominique Marcadet <Dominique.Marcadet@centralesupelec.fr>
Date: Wed, 22 May 2019 14:52:24 +0200
Subject: [PATCH] add BasicType (partial) and Enumeration validation

---
 .../scl/validator/nsd/BasicTypeValidator.java | 441 ++++++++++++++++++
 .../scl/validator/nsd/CDCValidator.java       |  23 +
 .../validator/nsd/EnumerationValidator.java   | 176 +++++++
 .../validator/nsd/NsdEObjectValidator.java    |   1 +
 .../scl/validator/nsd/TypeValidator.java      |  47 ++
 5 files changed, 688 insertions(+)
 create mode 100644 fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/BasicTypeValidator.java
 create mode 100644 fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/EnumerationValidator.java
 create mode 100644 fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/TypeValidator.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
new file mode 100644
index 0000000..db302e2
--- /dev/null
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/BasicTypeValidator.java
@@ -0,0 +1,441 @@
+/**
+ *  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.Arrays;
+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.BasicType;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.Val;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL;
+import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole;
+
+public abstract class BasicTypeValidator extends TypeValidator {
+
+    private static HashMap< String, BasicTypeValidator > validators = new HashMap<>();
+
+    public static BasicTypeValidator get( BasicType basicType ) {
+        return validators.get( basicType.getName() );
+    }
+    
+    static {
+        validators.put( "BOOLEAN", new BasicTypeValidator( "BOOLEAN" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                switch( value ) {
+                case "0" :
+                case "1" :
+                case "false" :
+                case "true" :
+                    return true;
+                default :
+                    return addDiagnosticErrorIfTrue( true, value, da, diagnostics );
+                }
+            }
+            
+        });
+        
+        validators.put( "INT8", new BasicTypeValidator( "INT8" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                try {
+                    new Byte( value );
+                }
+                catch( NumberFormatException e ) {
+                    return addDiagnosticErrorIfTrue( true, value, da, diagnostics );
+                }
+                return true;
+            }
+            
+        });
+        
+        validators.put( "INT16", new BasicTypeValidator( "INT16" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                try {
+                    new Short( value );
+                }
+                catch( NumberFormatException e ) {
+                    return addDiagnosticErrorIfTrue( true, value, da, diagnostics );
+                }
+                return true;
+            }
+            
+        });
+        
+        validators.put( "INT32", new BasicTypeValidator( "INT32" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                try {
+                    new Integer( value );
+                }
+                catch( NumberFormatException e ) {
+                    return addDiagnosticErrorIfTrue( true, value, da, diagnostics );
+                }
+                return true;
+            }
+            
+        });
+        
+        validators.put( "INT64", new BasicTypeValidator( "INT64" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                try {
+                    new Long( value );
+                }
+                catch( NumberFormatException e ) {
+                    return addDiagnosticErrorIfTrue( true, value, da, diagnostics );
+                }
+                return true;
+            }
+            
+        });
+        
+        validators.put( "INT8U", new BasicTypeValidator( "INT8U" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                Long v;
+                try {
+                    v = new Long( value );
+                }
+                catch( NumberFormatException e ) {
+                    return addDiagnosticErrorIfTrue( true, value, da, diagnostics );
+                }
+                return addDiagnosticErrorIfTrue(( v < 0 ) || ( v > 255 ), value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "INT16U", new BasicTypeValidator( "INT16U" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                Long v;
+                try {
+                    v = new Long( value );
+                }
+                catch( NumberFormatException e ) {
+                    return addDiagnosticErrorIfTrue( true, value, da, diagnostics );
+                }
+                return addDiagnosticErrorIfTrue(( v < 0 ) || ( v > 65535 ), value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "INT32U", new BasicTypeValidator( "INT32U" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                Long v;
+                try {
+                    v = new Long( value );
+                }
+                catch( NumberFormatException e ) {
+                    return addDiagnosticErrorIfTrue( true, value, da, diagnostics );
+                }
+                return addDiagnosticErrorIfTrue(( v < 0 ) || ( v > 4294967295L ), value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "FLOAT32", new BasicTypeValidator( "FLOAT32" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                try {
+                    new Float( value );
+                }
+                catch( NumberFormatException e ) {
+                    return addDiagnosticErrorIfTrue( true, value, da, diagnostics );
+                }
+                return true;
+            }
+            
+        });
+        
+        validators.put( "Octet64", new BasicTypeValidator( "Octet64" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                return addDiagnosticErrorIfTrue( value.getBytes().length > 64, value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "VisString64", new BasicTypeValidator( "VisString64" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO: what is a VisString ?
+                return addDiagnosticErrorIfTrue( value.getBytes().length > 64, value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "VisString129", new BasicTypeValidator( "VisString129" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO: what is a VisString ?
+                return addDiagnosticErrorIfTrue( value.getBytes().length > 129, value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "VisString255", new BasicTypeValidator( "VisString255" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO: what is a VisString ?
+                return addDiagnosticErrorIfTrue( value.getBytes().length > 255, value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "Unicode255", new BasicTypeValidator( "Unicode255" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO: how do we handle Unicode ?
+                return addDiagnosticErrorIfTrue( value.getBytes().length > 255, value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "PhyComAddr", new BasicTypeValidator( "PhyComAddr" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO
+                return addDiagnosticWarningNotImplemented( value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "ObjRef", new BasicTypeValidator( "ObjRef" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO
+                return addDiagnosticWarningNotImplemented( value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "EntryID", new BasicTypeValidator( "EntryID" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO
+                return addDiagnosticWarningNotImplemented( value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "Currency", new BasicTypeValidator( "Currency" ) {
+            
+            final HashSet< String > ISO_4217_3_characterCurrencyCode = new HashSet< String >( Arrays.asList( 
+                    "AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD",
+                    "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BOV", "BRL", "BSD", "BTN", "BWP",
+                    "BYN", "BZD", "CAD", "CDF", "CHE", "CHF", "CHW", "CLF", "CLP", "CNY", "COP", "COU",
+                    "CRC", "CUC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", "DZD", "EGP", "ERN", "ETB",
+                    "EUR", "FJD", "FKP", "GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD",
+                    "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "INR", "IQD", "IRR", "ISK", "JMD", "JOD",
+                    "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP",
+                    "LKR", "LRD", "LSL", "LYD", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRU",
+                    "MUR", "MVR", "MWK", "MXN", "MXV", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR",
+                    "NZD", "OMR", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD",
+                    "RUB", "RWF", "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLL", "SOS", "SRD",
+                    "SSP", "STN", "SVC", "SYP", "SZL", "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD",
+                    "TWD", "TZS", "UAH", "UGX", "USD", "USN", "UYI", "UYU", "UYW", "UZS", "VES", "VND",
+                    "VUV", "WST", "XAF", "XAG", "XAU", "XBA", "XBB", "XBC", "XBD", "XCD", "XDR", "XOF",
+                    "XPD", "XPF", "XPT", "XSU", "XTS", "XUA", "XXX", "YER", "ZAR", "ZMW", "ZWL", "XXX"
+            ));
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO: what means "The concrete coding shall be defined by the SCSMs." ?
+                return addDiagnosticErrorIfTrue( ! ISO_4217_3_characterCurrencyCode.contains( value ), value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "Timestamp", new BasicTypeValidator( "Timestamp" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO
+                return addDiagnosticWarningNotImplemented( value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "Quality", new BasicTypeValidator( "Quality" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO
+                return addDiagnosticWarningNotImplemented( value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "EntryTime", new BasicTypeValidator( "EntryTime" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO
+                return addDiagnosticWarningNotImplemented( value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "TrgOps", new BasicTypeValidator( "TrgOps" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO
+                return addDiagnosticWarningNotImplemented( value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "OptFlds", new BasicTypeValidator( "OptFlds" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO
+                return addDiagnosticWarningNotImplemented( value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "SvOptFlds", new BasicTypeValidator( "SvOptFlds" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO
+                return addDiagnosticWarningNotImplemented( value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "Check", new BasicTypeValidator( "Check" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO
+                return addDiagnosticWarningNotImplemented( value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "Tcmd", new BasicTypeValidator( "Tcmd" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO
+                return addDiagnosticWarningNotImplemented( value, da, diagnostics );
+            }
+            
+        });
+        
+        validators.put( "Dbpos", new BasicTypeValidator( "Dbpos" ) {
+
+            @Override
+            protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+                // TODO
+                return addDiagnosticWarningNotImplemented( value, da, diagnostics );
+            }
+            
+        });
+        
+    }
+    
+    private String name;
+    
+    public BasicTypeValidator( String name ) {
+        this.name = name;
+    }
+    
+    public String getName() {
+        return name;
+    }
+    
+    @Override
+    public boolean validateDA( DA da, DiagnosticChain diagnostics ) {
+        AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] BasicTypeValidator.validateDA( " + da.getName() + " ) at line " + da.getLineNumber() );
+        boolean res = true;
+        if( ! getName().equals( da.getBType() )) {
+            diagnostics.add( new BasicDiagnostic(
+                    Diagnostic.ERROR,
+                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                    0,
+                    "[NSD validation] type of DA " + da.getName() + " in DOType (id = " + da.getParentDOType().getId()
+                            + ", line = " + da.getParentDOType().getLineNumber() + ") is not " + getName(),
+                    new Object[] { da } ));
+            res = false;
+        }
+        for( Val val : da.getVal() ) {
+            res = validateValue( da, val.getValue(), diagnostics ) && res;
+        }
+        
+        return res;
+    }
+    
+    protected boolean addDiagnosticErrorIfTrue( boolean condition, String value, DA da, DiagnosticChain diagnostics ) {
+        if( condition ) {
+            diagnostics.add( new BasicDiagnostic(
+                    Diagnostic.ERROR,
+                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                    0,
+                    "[NSD validation] value " + value + " of Val in DA " + da + " in DOType (id = " + da.getParentDOType().getId()
+                            + ", line = " + da.getParentDOType().getLineNumber() + ") is not a valid " + getName() + " value",
+                    new Object[] { da } ));
+            return false;
+            
+        }
+        return true;
+    }
+    
+    protected boolean addDiagnosticWarningNotImplemented( String value, DA da, DiagnosticChain diagnostics ) {
+        diagnostics.add( new BasicDiagnostic(
+                Diagnostic.WARNING,
+                RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                0,
+                "[NSD validation] verification of value " + value + " of Val in DA " + da + " in DOType (id = " + da.getParentDOType().getId()
+                        + ", line = " + da.getParentDOType().getLineNumber() + ") is not implemented for BasicType " + getName(),
+                new Object[] { da } ));
+        return true;
+    }
+
+    protected abstract boolean validateValue( DA da, String value, DiagnosticChain diagnostics );
+
+}
diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/CDCValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/CDCValidator.java
index 377afdd..53d9a37 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
@@ -25,7 +25,9 @@ import java.util.stream.Stream;
 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.nsd.SubDataObject;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.DOType;
 import fr.centralesupelec.edf.riseclipse.iec61850.scl.SDO;
 import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole;
@@ -45,6 +47,7 @@ public class CDCValidator {
 
     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<>(); 
 
@@ -52,6 +55,16 @@ public class CDCValidator {
         dataAttributePresenceConditionValidator = DataAttributePresenceConditionValidator.get( cdc );
         subDataObjectPresenceConditionValidator = SubDataObjectPresenceConditionValidator.get( cdc );
         
+        for( DataAttribute da : cdc.getDataAttribute() ) {
+            TypeValidator validator = TypeValidator.get( da.getType() );
+            if( validator != null ) {
+                dataAttributeValidatorMap.put( da.getName(), validator );
+            }
+            else {
+                AbstractRiseClipseConsole.getConsole().warning( "[NSD setup] Type not found for DataAttribute " + da.getName() );
+            }
+        }
+        
         for( SubDataObject sdo : cdc.getSubDataObject() ) {
             CDCValidator validator = CDCValidator.get( sdo.getType() );
             if( validator != null ) {
@@ -84,6 +97,16 @@ public class CDCValidator {
         .forEach( d -> subDataObjectPresenceConditionValidator.addSDO( d, diagnostics ));
         
         res = subDataObjectPresenceConditionValidator.validate( doType, diagnostics ) && res;
+        
+        for( DA da : doType.getDA() ) {
+            TypeValidator validator = dataAttributeValidatorMap.get( da.getName() );
+            if( validator != null ) {
+                validator.validateDA( da, diagnostics );
+            }
+            else {
+                AbstractRiseClipseConsole.getConsole().warning( "[NSD validation] while validating DOType (line " + doType.getLineNumber() + "): validator for DA " + da.getName() + " not found" );
+            }
+        }
       
         for( SDO sdo : doType.getSDO() ) {
             CDCValidator validator = subDataObjectValidatorMap.get( sdo.getName() );
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
new file mode 100644
index 0000000..b4b7205
--- /dev/null
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/EnumerationValidator.java
@@ -0,0 +1,176 @@
+/**
+ *  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.Enumeration;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.EnumType;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.EnumVal;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.Val;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.validator.RiseClipseValidatorSCL;
+import fr.centralesupelec.edf.riseclipse.util.AbstractRiseClipseConsole;
+
+public class EnumerationValidator extends TypeValidator {
+    
+    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();
+        this.inheritedFromName = enumeration.getInheritedFrom();
+        
+        enumeration
+        .getLiteral()
+        .stream()
+        .forEach( e -> literals.put( e.getName(), e.getLiteralVal() ));
+    }
+    
+    public String getName() {
+        return name;
+    }
+    
+    @Override
+    public boolean validateDA( DA da, DiagnosticChain diagnostics ) {
+        AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] EnumerationValidator.validateDA( " + da.getName() + " ) at line " + da.getLineNumber() );
+        
+        if(( inheritedFromName != null ) && ( inheritedFrom == null )) {
+            TypeValidator inheritedValidator = TypeValidator.get( inheritedFromName );
+            if(( inheritedValidator != null ) && ( inheritedValidator instanceof EnumerationValidator )) {
+                inheritedFrom = ( EnumerationValidator ) inheritedValidator;
+            }
+            else {
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.WARNING,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "[NSD validation] validator for inherited enumeration " + inheritedFromName + " not found",
+                        new Object[] { da } ));
+                // Avoid checking again
+                inheritedFromName = null;
+            }
+        }
+
+        boolean res = true;
+        if( ! "Enum".equals(  da.getBType() )) {
+            diagnostics.add( new BasicDiagnostic(
+                    Diagnostic.ERROR,
+                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                    0,
+                    "[NSD validation] bType of DA " + da.getName() + " in DOType (id = " + da.getParentDOType().getId()
+                            + ", line = " + da.getParentDOType().getLineNumber() + ") is not Enum",
+                    new Object[] { da } ));
+            res = false;
+        }
+        if( ! getName().equals( da.getType() )) {
+            diagnostics.add( new BasicDiagnostic(
+                    Diagnostic.ERROR,
+                    RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                    0,
+                    "[NSD validation] type of DA " + da.getName() + " in DOType (id = " + da.getParentDOType().getId()
+                            + ", line = " + da.getParentDOType().getLineNumber() + ") is not " + getName(),
+                    new Object[] { da } ));
+            res = false;
+        }
+        for( Val val : da.getVal() ) {
+            res = validateValue( da, val.getValue(), diagnostics ) && res;
+        }
+        
+        if( da.getRefersToEnumType() != null ) {
+            res = validateEnumType( da.getRefersToEnumType(), diagnostics ) && res;
+        }
+        
+        return res;
+    }
+    
+    protected boolean validateValue( DA da, String value, DiagnosticChain diagnostics ) {
+        boolean res = true;
+        
+        if( ! literals.containsKey( value )) {
+            if( inheritedFrom != null ) {
+                res = inheritedFrom.validateValue( da, value, diagnostics ) && res;
+            }
+            else {
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.ERROR,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "[NSD validation] value of DA " + da.getName() + " in DOType (id = " + da.getParentDOType().getId()
+                                + ", line = " + da.getParentDOType().getLineNumber() + ") is not valid",
+                        new Object[] { da } ));
+                res = false;
+            }
+        }
+        
+        return res;
+    }
+
+    public boolean validateEnumType( EnumType enumType, DiagnosticChain diagnostics ) {
+        if( validatedEnumType.contains( enumType )) return true;
+        AbstractRiseClipseConsole.getConsole().verbose( "[NSD validation] EnumerationValidator.validateEnumType( " + enumType.getId() + " ) at line " + enumType.getLineNumber() );
+        validatedEnumType.add( enumType );
+        
+        boolean res = true;
+        
+        // enumType.getId().equals( getName() ) already tested because enumType.getId().equals( da.getType() )
+        
+        for( EnumVal enumVal : enumType.getEnumVal() ) {
+            if( ! literals.containsKey( enumVal.getValue() )) {
+                if( inheritedFrom != null ) {
+                    res = inheritedFrom.validateEnumType( enumType, diagnostics ) && res;
+                }
+                else {
+                    diagnostics.add( new BasicDiagnostic(
+                            Diagnostic.ERROR,
+                            RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                            0,
+                            "[NSD validation] EnumVal " + enumVal.getValue() + " in EnumType (id = " + enumType.getId()
+                                    + " at line " + enumVal.getLineNumber() + " is unknown",
+                            new Object[] { enumVal } ));
+                    res = false;
+                }
+            }
+            else if( literals.get( enumVal.getValue() ).equals( enumVal.getOrd() )) {
+                diagnostics.add( new BasicDiagnostic(
+                        Diagnostic.ERROR,
+                        RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE,
+                        0,
+                        "[NSD validation] EnumVal " + enumVal.getValue() + " in EnumType (id = " + enumType.getId()
+                                + " at line " + enumVal.getLineNumber() + " has incorrect ord (" + enumVal.getOrd()
+                                + " instead of " + literals.get( enumVal.getValue() ),
+                        new Object[] { enumVal } ));
+                res = false;
+            }
+        }
+        
+        // TODO: do we have to check that all literals in Enumeration are present as EnumVal ?
+        
+        return res;
+    }
+
+}
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 20d7cca..392bf65 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
@@ -41,6 +41,7 @@ public class NsdEObjectValidator implements EValidator {
 
     public NsdEObjectValidator( NsdResourceSetImpl nsdResourceSet ) {
         // Order is important !
+        TypeValidator.buildValidators( nsdResourceSet.getBasicTypeStream(), nsdResourceSet.getEnumerationStream(), nsdResourceSet.getConstructedAttributeStream() );
         CDCValidator.buildValidators( nsdResourceSet.getCDCStream() );
         LNClassValidator.buildValidators( nsdResourceSet.getLNClassStream() );
     }
diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/TypeValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/TypeValidator.java
new file mode 100644
index 0000000..a74944f
--- /dev/null
+++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/nsd/TypeValidator.java
@@ -0,0 +1,47 @@
+/**
+ *  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.stream.Stream;
+
+import org.eclipse.emf.common.util.DiagnosticChain;
+
+import fr.centralesupelec.edf.riseclipse.iec61850.nsd.BasicType;
+import fr.centralesupelec.edf.riseclipse.iec61850.nsd.ConstructedAttribute;
+import fr.centralesupelec.edf.riseclipse.iec61850.nsd.Enumeration;
+import fr.centralesupelec.edf.riseclipse.iec61850.scl.DA;
+
+public abstract class TypeValidator {
+
+    private static HashMap< String, TypeValidator > validators = new HashMap<>();
+    
+    public static TypeValidator get( String name ) {
+        return validators.get( name );
+    }
+    
+    public static void buildValidators( Stream< BasicType > basicTypeStream, Stream< Enumeration > enumerationStream, Stream< ConstructedAttribute > constructedAttributeStream ) {
+        basicTypeStream
+        .forEach( basicType -> validators.put( basicType.getName(), BasicTypeValidator.get( basicType )));
+        enumerationStream
+        .forEach( enumeration -> validators.put( enumeration.getName(), new EnumerationValidator( enumeration )));
+    }
+
+    public abstract boolean validateDA( DA da, DiagnosticChain diagnostics );
+}
-- 
GitLab