diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/.gitignore b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..ae3c1726048cd06b9a143e0376ed46dd9b9a8d53 --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/.gitignore @@ -0,0 +1 @@ +/bin/ 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 2057aad55681263f9de6b7b040d8bd5c6ae01e30..70b6e48c79d2496fd6da9978220082ed9e30a0d1 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 @@ -19,4 +19,5 @@ Require-Bundle: org.eclipse.core.runtime, fr.centralesupelec.edf.riseclipse.iec61850.scl.edit, fr.centralesupelec.edf.riseclipse.validation.ocl, fr.centralesupelec.edf.riseclipse.iec61850.nsd, - fr.centralesupelec.edf.riseclipse.iec61850.nsd.edit + fr.centralesupelec.edf.riseclipse.iec61850.nsd.edit, + org.eclipse.ocl.xtext.oclinecore 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..62b539d8eb1721d28da4d34e23e90a56f56f70dc --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/AnyLNValidator.java @@ -0,0 +1,165 @@ +/** + * 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; + +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.AnyLN; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DOI; +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, 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 DOIValidator( dObj.getRefersToCDC() )); + } + } + } + } + + public boolean validateLN( AnyLN ln, DiagnosticChain diagnostics ) { + boolean res = true; + + HashSet< String > checkedDO = new HashSet<>(); + + for( DOI doi : ln.getDOI() ) { + AbstractRiseClipseConsole.getConsole().verbose( "validateDOI( " + doi.getName() + " )" ); + + // Test if DOI is a possible DOI in this LN + if( ! doMap.containsKey( doi.getName() ) ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "DO " + doi.getName() + " in LN at line " + ln.getLineNumber() + " not found in LNClass " + ln.getLnClass(), + new Object[] { ln } )); + continue; + } + + // Control of DOI presence in LN + updateCompulsory( doi, checkedDO, diagnostics ); + + // Validation of DOI content + if( ! validateDOI( doi, diagnostics ) ) { + res = false; + } + + } + + // Verify all necessary DOI were present + if( ! doMap.values().stream() + .map( x -> checkCompulsory( ln, x, checkedDO, diagnostics )) + .reduce( ( a, b ) -> a && b ).get() ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "LN at line " + ln.getLineNumber() + " does not contain all mandatory DO from class " + ln.getLnClass(), + new Object[] { ln } )); + res = false; + } + return res; + } + + public boolean checkCompulsory( AnyLN ln, 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 " + ln.getLineNumber(), + new Object[] { ln } )); + return false; + } + } + return true; + } + + public boolean updateCompulsory( DOI doi, HashSet< String > checkedDO, DiagnosticChain diagnostics ) { + switch( doMap.get( doi.getName() ).getPresCond() ) { + case "M": + case "O": + if( checkedDO.contains( doi.getName() )) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "DO " + doi + " cannot appear more than once in LN at line " + doi.getAnyLN().getLineNumber(), + new Object[] { doi } )); + return false; + } + checkedDO.add( doi.getName() ); + break; + case "F": + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "DO " + doi + " is forbidden in LN at line " + doi.getAnyLN().getLineNumber(), + new Object[] { doi } )); + return false; + } + return true; + } + + public boolean validateDOI( DOI doi, DiagnosticChain diagnostics ) { + + AbstractRiseClipseConsole.getConsole().verbose( "found DO " + doi.getName() + " in LNClass " + lnClass ); + + // DOIValidator validates DOI content + String cdc = doMap.get( doi.getName() ).getRefersToCDC().getName(); + return cdcMap.get( cdc ).validateDOI( doi, diagnostics ); + } + +} 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..7f0d30695d9afca2f916d4795ce2dede4980eed6 --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/DOIValidator.java @@ -0,0 +1,347 @@ +/** + * 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; + +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.DAI; +import fr.centralesupelec.edf.riseclipse.iec61850.scl.DOI; +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, DiagnosticChain diagnostics ) { + boolean res = true; + HashSet< String > checkedDA = new HashSet<>(); + + for( DAI dai : doi.getDAI() ) { + AbstractRiseClipseConsole.getConsole().verbose( "validateDAI( " + dai.getName() + " ) (line" + dai.getLineNumber() + ")" ); + + // Test if DAI is a possible DAI in this DOI + if( ! daMap.containsKey( dai.getName() ) ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "DAI " + dai.getName() + " (line" + dai.getLineNumber() + ") not found in CDC", + new Object[] { doi, cdc } )); + res = false; + continue; + } + + // Control of DAI presence in DOI + updateCompulsory( dai, checkedDA, diagnostics ); + + // Validation of DAI content + if( ! validateDAI( dai, diagnostics ) ) { + res = false; + } + + } + + // Verify all necessary DAI were present + if( ! daMap.values().stream() + .map( x -> checkCompulsory( doi, x, checkedDA, diagnostics ) ) + .reduce( ( a, b ) -> a && b ).get() ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "DOI (line " + doi.getLineNumber() + ") does not contain all mandatory DA from CDC ", + new Object[] { doi, cdc } )); + res = false; + } + return res; + } + + public boolean checkCompulsory( DOI doi, 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 DOI (line " + doi.getLineNumber() + ")", + new Object[] { da } )); + return false; + } + } + return true; + } + + public boolean updateCompulsory( DAI dai, HashSet< String > checked, DiagnosticChain diagnostics ) { + switch( daMap.get( dai.getName() ).getPresCond() ) { + case "M": + case "O": + if( checked.contains( dai.getName() ) ) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "DAI " + dai.getName() + " (line " + dai.getLineNumber() + ") cannot appear more than once", + new Object[] { dai } )); + return false; + } + else { + checked.add( dai.getName() ); + break; + } + case "F": + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "DAI " + dai.getName() + " (line " + dai.getLineNumber() + ") is forbidden", + new Object[] { dai } )); + return false; + } + return true; + } + + public boolean validateDAI( DAI dai, DiagnosticChain diagnostics ) { + + AbstractRiseClipseConsole.getConsole().verbose( "found DA " + dai.getName() + " in CDC " + cdc ); + + // DataAttributes that are BASIC have a BasicType which describes allowed Val of DA + DataAttribute da = daMap.get( dai.getName() ); + if( da.getTypeKind().getName().equals( "BASIC" ) ) { + for( Val val : dai.getVal() ) { + if( ! validateVal( val.getValue(), da.getType() )) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "Val " + val.getValue() + " (" + dai.getLineNumber() + ") of DA " + dai.getName() + " is not of type " + da.getType(), + new Object[] { dai, val } )); + return false; + } + AbstractRiseClipseConsole.getConsole().verbose( "Val " + val.getValue() + " (" + dai.getLineNumber() + ") 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": + try { + v = Integer.parseInt( val ); + } + catch( Exception e ) { + return false; + } + return v >= -128 && v <= 127; + case "INT16": + try { + v = Integer.parseInt( val ); + } + catch( Exception e ) { + return false; + } + return v >= -32768 && v <= 32767; + case "INT32": + try { + v = Integer.parseInt( val ); + } + catch( Exception e ) { + return false; + } + return v >= Integer.MIN_VALUE && v <= Integer.MAX_VALUE; + case "INT64": + try { + l = Long.parseLong( val ); + } + catch( Exception e ) { + return false; + } + return l >= Long.MIN_VALUE && l <= Long.MAX_VALUE; + case "INT8U": + try { + v = Integer.parseInt( val ); + } + catch( Exception e ) { + return false; + } + return v >= 0 && v <= 255; + case "INT16U": + try { + v = Integer.parseInt( val ); + } + catch( Exception e ) { + return false; + } + return v >= 0 && v <= 65535; + case "INT32U": + try { + l = Long.parseLong( val ); + } + catch( Exception e ) { + return false; + } + String max = "4294967295"; + return l >= 0 && l <= Long.parseLong( max ); + case "FLOAT32": + try { + f = Float.parseFloat( val ); + } + catch( Exception e ) { + return false; + } + return f >= -Float.MAX_VALUE && f <= Float.MAX_VALUE; + case "Octet64": + byte[] bytes = val.getBytes(); + return bytes.length <= 64; + case "VisString64": + return val.length() <= 64; + case "VisString129": + return val.length() <= 129; + case "Unicode255": + case "VisString255": + return val.length() <= 255; + default: + return true; + } + } + + private void testValidateVal() { + log( "\n--\tSTART TEST\t--\n" ); + assertTrue( validateVal( "0", "BOOLEAN" ) ); + assertTrue( validateVal( "1", "BOOLEAN" ) ); + assertTrue( validateVal( "true", "BOOLEAN" ) ); + assertTrue( validateVal( "false", "BOOLEAN" ) ); + assertTrue( !validateVal( "2", "BOOLEAN" ) ); + assertTrue( !validateVal( "-1", "BOOLEAN" ) ); + assertTrue( !validateVal( "string", "BOOLEAN" ) ); + log( "" ); + assertTrue( validateVal( "1", "INT8" ) ); + assertTrue( validateVal( "0", "INT8" ) ); + assertTrue( validateVal( "-1", "INT8" ) ); + assertTrue( validateVal( "127", "INT8" ) ); + assertTrue( validateVal( "-128", "INT8" ) ); + assertTrue( !validateVal( "128", "INT8" ) ); + assertTrue( !validateVal( "-129", "INT8" ) ); + assertTrue( !validateVal( "string", "INT8" ) ); + assertTrue( !validateVal( "22.2", "INT8" ) ); + log( "" ); + assertTrue( validateVal( "32767", "INT16" ) ); + assertTrue( validateVal( "-32768", "INT16" ) ); + assertTrue( !validateVal( "32768", "INT16" ) ); + assertTrue( !validateVal( "-32769", "INT16" ) ); + log( "" ); + assertTrue( validateVal( Integer.toString( Integer.MAX_VALUE ), "INT32" ) ); + assertTrue( validateVal( Integer.toString( Integer.MIN_VALUE ), "INT32" ) ); + assertTrue( !validateVal( "2147483648", "INT32" ) ); + assertTrue( !validateVal( "-2147483649", "INT32" ) ); + log( "" ); + assertTrue( validateVal( Long.toString( Long.MAX_VALUE ), "INT64" ) ); + assertTrue( validateVal( Long.toString( Long.MIN_VALUE ), "INT64" ) ); + assertTrue( !validateVal( "9223372036854775808", "INT64" ) ); + assertTrue( !validateVal( "-9223372036854775809", "INT64" ) ); + log( "" ); + assertTrue( validateVal( "0", "INT8U" ) ); + assertTrue( validateVal( "255", "INT8U" ) ); + assertTrue( !validateVal( "256", "INT8U" ) ); + assertTrue( !validateVal( "-1", "INT8U" ) ); + assertTrue( !validateVal( "-2", "INT8U" ) ); + log( "" ); + assertTrue( validateVal( "0", "INT16U" ) ); + assertTrue( validateVal( "65535", "INT16U" ) ); + assertTrue( !validateVal( "65536", "INT16U" ) ); + assertTrue( !validateVal( "-1", "INT16U" ) ); + assertTrue( !validateVal( "-2", "INT16U" ) ); + log( "" ); + assertTrue( validateVal( "0", "INT32U" ) ); + assertTrue( validateVal( "4294967295", "INT32U" ) ); + assertTrue( !validateVal( "4294967296", "INT32U" ) ); + assertTrue( !validateVal( "-1", "INT32U" ) ); + assertTrue( !validateVal( "-2", "INT32U" ) ); + log( "" ); + assertTrue( validateVal( "0.0", "FLOAT32" ) ); + assertTrue( validateVal( "1.2345", "FLOAT32" ) ); + assertTrue( validateVal( "-1.2345", "FLOAT32" ) ); + assertTrue( validateVal( "100", "FLOAT32" ) ); + assertTrue( validateVal( Float.toString( Float.MAX_VALUE ), "FLOAT32" ) ); + assertTrue( validateVal( Float.toString( -Float.MAX_VALUE ), "FLOAT32" ) ); + assertTrue( !validateVal( "3.4028236E38", "FLOAT32" ) ); + assertTrue( !validateVal( "-3.4028236E38", "FLOAT32" ) ); + assertTrue( !validateVal( "string", "FLOAT32" ) ); + log( "" ); + assertTrue( validateVal( "1234567890123456789012345678901234567890123456789012345678901234", "Octet64" ) ); + assertTrue( !validateVal( "12345678901234567890123456789012345678901234567890123456789012345", "Octet64" ) ); + log( "" ); + assertTrue( validateVal( "1234567890123456789012345678901234567890123456789012345678901234", "VisString64" ) ); + assertTrue( + !validateVal( "12345678901234567890123456789012345678901234567890123456789012345", "VisString64" ) ); + log( "" ); + assertTrue( validateVal( "1234567890123456789012345678901234567890123456789012345678901234" + + "12345678901234567890123456789012345678901234567890123456789012345", "VisString129" ) ); + assertTrue( !validateVal( "1234567890123456789012345678901234567890123456789012345678901234" + + "123456789012345678901234567890123456789012345678901234567890123456", "VisString129" ) ); + log( "" ); + assertTrue( validateVal( "1234567890123456789012345678901234567890123456789012345678901234" + + "1234567890123456789012345678901234567890123456789012345678901234" + + "1234567890123456789012345678901234567890123456789012345678901234" + + "123456789012345678901234567890123456789012345678901234567890123", "VisString255" ) ); + assertTrue( !validateVal( "1234567890123456789012345678901234567890123456789012345678901234" + + "1234567890123456789012345678901234567890123456789012345678901234" + + "1234567890123456789012345678901234567890123456789012345678901234" + + "1234567890123456789012345678901234567890123456789012345678901234", "VisString255" ) ); + } + + private void assertTrue( Boolean b ) { + if( b ) { + log( "Check" ); + } + else { + log( "Error" ); + } + } + + private 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/NSDEObjectValidator.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NSDEObjectValidator.java deleted file mode 100644 index 1839451c7751c89f8804b7352d30c514fc79e728..0000000000000000000000000000000000000000 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NSDEObjectValidator.java +++ /dev/null @@ -1,61 +0,0 @@ -/** - * 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; - -import java.util.Map; - -import org.eclipse.emf.common.util.DiagnosticChain; -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.util.AbstractRiseClipseConsole; - -public class NSDEObjectValidator implements EValidator { - - private Resource nsdResource; - - public NSDEObjectValidator( Resource nsdResource ) { - this.nsdResource = nsdResource; - } - - @Override - public boolean validate( EObject eObject, DiagnosticChain diagnostics, Map< Object, Object > context ) { - return validate( eObject.eClass(), eObject, diagnostics, context ); - } - - @Override - public boolean validate( EClass eClass, EObject eObject, DiagnosticChain diagnostics, - Map< Object, Object > context ) { - AbstractRiseClipseConsole.getConsole().info( "NSDEObjectValidator.validate( EClass ): " + eClass.getName() ); - // TODO: use nsdResource to validate eObject - return true; - } - - @Override - 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 - return true; - } - -} diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NSDModelLoader.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NSDModelLoader.java deleted file mode 100644 index 0839ba203a33a33a7fdb6a889ab0653a135a16a7..0000000000000000000000000000000000000000 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NSDModelLoader.java +++ /dev/null @@ -1,70 +0,0 @@ -/** - * 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; - -import org.eclipse.emf.ecore.EValidator; -import org.eclipse.emf.ecore.resource.Resource; - -import fr.centralesupelec.edf.riseclipse.iec61850.nsd.NsdPackage; -import fr.centralesupelec.edf.riseclipse.iec61850.nsd.util.NsdResourceFactoryImpl; -import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole; -import fr.centralesupelec.edf.riseclipse.util.RiseClipseModelLoader; -import fr.centralesupelec.edf.riseclipse.util.TextRiseClipseConsole; - -public class NSDModelLoader extends RiseClipseModelLoader { - - public NSDModelLoader( IRiseClipseConsole console ) { - super( console ); - } - - @Override - public void reset() { - super.reset(); - - // Register the appropriate resource factory to handle all file - // extensions. - getResourceSet().getResourceFactoryRegistry().getExtensionToFactoryMap() - .put( Resource.Factory.Registry.DEFAULT_EXTENSION, new NsdResourceFactoryImpl() ); - - // Register the package to ensure it is available during loading. - getResourceSet().getPackageRegistry().put( NsdPackage.eNS_URI, NsdPackage.eINSTANCE ); - } - - public Resource loadWithoutValidation( String name ) { - Object eValidator = EValidator.Registry.INSTANCE.remove( NsdPackage.eINSTANCE ); - - Resource resource = load( name ); - - if( eValidator != null ) { - EValidator.Registry.INSTANCE.put( NsdPackage.eINSTANCE, eValidator ); - } - return resource; - } - - public static void main( String[] args ) { - IRiseClipseConsole console = new TextRiseClipseConsole(); - SCLModelLoader loader = new SCLModelLoader( console ); - - for( int i = 0; i < args.length; ++i ) { - @SuppressWarnings( "unused" ) - Resource resource = loader.load( args[i] ); - } - } - -} 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 deleted file mode 100644 index 0bffb4600fcf0e8ea2c41b6037905f24106c834c..0000000000000000000000000000000000000000 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NSDValidator.java +++ /dev/null @@ -1,112 +0,0 @@ -/** - * 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; - -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -import org.eclipse.emf.common.notify.AdapterFactory; -import org.eclipse.emf.common.util.Diagnostic; -import org.eclipse.emf.ecore.EAttribute; -import org.eclipse.emf.ecore.EDataType; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EPackage; -import org.eclipse.emf.ecore.EStructuralFeature; -import org.eclipse.emf.ecore.EValidator; -import org.eclipse.emf.ecore.EValidator.SubstitutionLabelProvider; -import org.eclipse.emf.ecore.resource.Resource; -import org.eclipse.emf.ecore.util.Diagnostician; -import org.eclipse.emf.edit.provider.IItemLabelProvider; -import org.eclipse.jdt.annotation.NonNull; -import org.eclipse.ocl.pivot.validation.ComposedEValidator; - -import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole; - -public class NSDValidator { - - private @NonNull EPackage modelPackage; - private ComposedEValidator validator; - - public NSDValidator( @NonNull EPackage modelPackage ) { - this.modelPackage = modelPackage; - validator = ComposedEValidator.install( modelPackage ); - } - - public boolean addNSDDocument( Resource resource, IRiseClipseConsole console ) { - NSDEObjectValidator nsdObjectValidator = new NSDEObjectValidator( resource ); - validator.addChild( nsdObjectValidator ); - return true; - } - - public void validate( Resource resource, final AdapterFactory adapter, IRiseClipseConsole console ) { - Map<Object, Object> context = new HashMap< Object, Object >(); - SubstitutionLabelProvider substitutionLabelProvider = new EValidator.SubstitutionLabelProvider() { - - @Override - public String getValueLabel( EDataType eDataType, Object value ) { - return Diagnostician.INSTANCE.getValueLabel( eDataType, value ); - } - - @Override - public String getObjectLabel( EObject eObject ) { - IItemLabelProvider labelProvider = ( IItemLabelProvider ) adapter.adapt( eObject, IItemLabelProvider.class ); - return labelProvider.getText( eObject ); - } - - @Override - public String getFeatureLabel( EStructuralFeature eStructuralFeature ) { - return Diagnostician.INSTANCE.getFeatureLabel( eStructuralFeature ); - } - }; - 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 ); - - if( diagnostic.getSeverity() == Diagnostic.ERROR || diagnostic.getSeverity() == Diagnostic.WARNING ) { - //EObject root = ( EObject ) diagnostic.getData().get( 0 ); - //URI uri = root.eResource().getURI(); - //console.error( "in file " + uri.lastSegment() ); - for( Iterator< Diagnostic > i = diagnostic.getChildren().iterator(); i.hasNext(); ) { - Diagnostic childDiagnostic = i.next(); - switch( childDiagnostic.getSeverity() ) { - case Diagnostic.ERROR: - case Diagnostic.WARNING: - List< ? > data = childDiagnostic.getData(); - EObject object = ( EObject ) data.get( 0 ); - if( data.size() == 1 ) { - console.error( "\t" + childDiagnostic.getMessage() ); - } - else if( data.get( 1 ) instanceof EAttribute ) { - EAttribute attribute = ( EAttribute ) data.get( 1 ); - if( attribute == null ) continue; - console.error( "\tAttribute " + attribute.getName() + " of " + substitutionLabelProvider.getObjectLabel( object ) + " : " + childDiagnostic.getChildren().get( 0 ).getMessage() ); - } - else { - console.error( "\t" + childDiagnostic.getMessage() ); - } - } - } - } - } - } - -} 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 new file mode 100644 index 0000000000000000000000000000000000000000..fa2ef5eaec29ce8f402b377bb2dd85a8c65c7fac --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NsdEObjectValidator.java @@ -0,0 +1,112 @@ +/** + * 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; + +import java.util.HashMap; +import java.util.Map; + +import org.eclipse.emf.common.util.BasicDiagnostic; +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.common.util.DiagnosticChain; +import org.eclipse.emf.ecore.EClass; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EObject; +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.util.AbstractRiseClipseConsole; + +public class NsdEObjectValidator implements EValidator { + + private NsdResourceSetImpl nsdResourceSet; + private HashMap< String, AnyLNValidator > lnMap; + + public NsdEObjectValidator( NsdResourceSetImpl nsdResourceSet ) { + this.nsdResourceSet = nsdResourceSet; + } + + public void initializeValidationData() { + this.lnMap = this.nsdResourceSet.getLNClassStream() + .map( lnClass -> generateValidators( lnClass ) ) + .reduce( ( a, b ) -> { + a.putAll( b ); + return a; + } ).get(); + } + + private 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 ) { + return validate( eObject.eClass(), eObject, diagnostics, context ); + } + + @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": + AnyLN ln = ( AnyLN ) eObject; + return validateLN( ln, diagnostics ); + default: + AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: NsdEObjectValidator.validate( " + eClass.getName() + " )" ); + return false; + } + } + + @Override + public boolean validate( EDataType eDataType, Object value, DiagnosticChain diagnostics, Map< Object, Object > context ) { + AbstractRiseClipseConsole.getConsole().info( "NOT IMPLEMENTED: NsdEObjectValidator.validate( " + eDataType.getName() + " )" ); + + // TODO: use nsdResource to validate value + + return true; + } + + public boolean validateLN( 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() )) { + diagnostics.add( new BasicDiagnostic( + Diagnostic.ERROR, + RiseClipseValidatorSCL.DIAGNOSTIC_SOURCE, + 0, + "LNClass " + ln.getLnClass() + " not found in NSD files for LN at line " + ln.getLineNumber(), + new Object[] { ln } )); + return false; + } + 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 ); + } + +} diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NsdModelLoader.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NsdModelLoader.java new file mode 100644 index 0000000000000000000000000000000000000000..3e7058aa5a7cd0a0cd6aad37830b91de80d3aee4 --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NsdModelLoader.java @@ -0,0 +1,129 @@ +/** + * 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; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.EValidator; +import org.eclipse.emf.ecore.EValidator.SubstitutionLabelProvider; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.Diagnostician; +//import org.eclipse.ocl.pivot.delegate.OCLDelegateDomain; +import org.eclipse.emf.edit.provider.IItemLabelProvider; + +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.NsdPackage; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.provider.NsdItemProviderAdapterFactory; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.util.NsdResourceFactoryImpl; +import fr.centralesupelec.edf.riseclipse.iec61850.nsd.util.NsdResourceSetImpl; +import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole; +import fr.centralesupelec.edf.riseclipse.util.RiseClipseModelLoader; +import fr.centralesupelec.edf.riseclipse.util.TextRiseClipseConsole; + +public class NsdModelLoader extends RiseClipseModelLoader { + + public NsdModelLoader( IRiseClipseConsole console ) { + super( console ); + } + + @Override + public void reset() { + super.reset( new NsdResourceSetImpl( true, console ) ); + + // Register the appropriate resource factory to handle all file + // extensions. + getResourceSet().getResourceFactoryRegistry().getExtensionToFactoryMap() + .put( Resource.Factory.Registry.DEFAULT_EXTENSION, new NsdResourceFactoryImpl() ); + + // Register the package to ensure it is available during loading. + getResourceSet().getPackageRegistry().put( NsdPackage.eNS_URI, NsdPackage.eINSTANCE ); + } + + @Override + public NsdResourceSetImpl getResourceSet() { + return ( NsdResourceSetImpl ) super.getResourceSet(); + } + + public Resource loadWithoutValidation( String name ) { + Object eValidator = EValidator.Registry.INSTANCE.remove( NsdPackage.eINSTANCE ); + + Resource resource = load( name ); + + if( eValidator != null ) { + EValidator.Registry.INSTANCE.put( NsdPackage.eINSTANCE, eValidator ); + } + return resource; + } + + public static void main( String[] args ) { + IRiseClipseConsole console = new TextRiseClipseConsole(); + //console.setLevel( IRiseClipseConsole.ERROR_LEVEL ); + NsdModelLoader loader = new NsdModelLoader( console ); + + org.eclipse.ocl.xtext.oclinecore.OCLinEcoreStandaloneSetup.doSetup(); + + Map< Object, Object > context = new HashMap< Object, Object >(); + SubstitutionLabelProvider substitutionLabelProvider = new EValidator.SubstitutionLabelProvider() { + + @Override + public String getValueLabel( EDataType eDataType, Object value ) { + return Diagnostician.INSTANCE.getValueLabel( eDataType, value ); + } + + @Override + public String getObjectLabel( EObject eObject ) { + NsdItemProviderAdapterFactory adapter = new NsdItemProviderAdapterFactory(); + IItemLabelProvider labelProvider = ( IItemLabelProvider ) adapter.adapt( eObject, + IItemLabelProvider.class ); + return labelProvider.getText( eObject ); + } + + @Override + public String getFeatureLabel( EStructuralFeature eStructuralFeature ) { + return Diagnostician.INSTANCE.getFeatureLabel( eStructuralFeature ); + } + }; + context.put( EValidator.SubstitutionLabelProvider.class, substitutionLabelProvider ); + + for( int i = 0; i < args.length; ++i ) { + Resource resource = loader.load( args[i] ); + if( resource == null ) continue; + if( resource.getContents().size() == 0 ) continue; + Diagnostic diagnostic = Diagnostician.INSTANCE.validate( resource.getContents().get( 0 ), context ); + + if( diagnostic.getSeverity() == Diagnostic.ERROR || diagnostic.getSeverity() == Diagnostic.WARNING ) { + for( Iterator< Diagnostic > d = diagnostic.getChildren().iterator(); d.hasNext(); ) { + Diagnostic childDiagnostic = d.next(); + switch( childDiagnostic.getSeverity() ) { + case Diagnostic.ERROR: + case Diagnostic.WARNING: + console.error( "\t" + childDiagnostic.getMessage() ); + } + } + } + } + loader.getResourceSet().finalizeLoad( console ); + } + +} 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 new file mode 100644 index 0000000000000000000000000000000000000000..d7dc86353fef2b31548b770078d91058ebb92436 --- /dev/null +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/NsdValidator.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; + +import org.eclipse.emf.ecore.EPackage; +import org.eclipse.jdt.annotation.NonNull; +import org.eclipse.ocl.pivot.validation.ComposedEValidator; + +import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole; + +public class NsdValidator { + + private NsdModelLoader nsdLoader; + + public NsdValidator( @NonNull EPackage modelPackage, IRiseClipseConsole console ) { + nsdLoader = new NsdModelLoader( console ); + } + + public void addNsdDocument( String nsdFile, IRiseClipseConsole console ) { + console.info( "Loading nsd: " + nsdFile ); + nsdLoader.load( nsdFile ); + } + + public void prepare( @NonNull ComposedEValidator validator, IRiseClipseConsole console ) { + nsdLoader.getResourceSet().finalizeLoad( console ); + NsdEObjectValidator nsdEObjectValidator = new NsdEObjectValidator( nsdLoader.getResourceSet() ); + nsdEObjectValidator.initializeValidationData(); + validator.addChild( nsdEObjectValidator ); + } + +} 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 acfe5d5d052589e1c8d3983a67df26850689ae3b..68e562f5a639afdf821301a2d0d13b7b7edfc451 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 @@ -18,77 +18,96 @@ */ package fr.centralesupelec.edf.riseclipse.iec61850.scl.validator; -import java.io.File; import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; -import fr.centralesupelec.edf.riseclipse.iec61850.nsd.provider.NsdItemProviderAdapterFactory; import fr.centralesupelec.edf.riseclipse.iec61850.scl.SclPackage; import fr.centralesupelec.edf.riseclipse.iec61850.scl.provider.SclItemProviderAdapterFactory; import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole; +import fr.centralesupelec.edf.riseclipse.util.RiseClipseFatalException; import fr.centralesupelec.edf.riseclipse.util.TextRiseClipseConsole; import fr.centralesupelec.edf.riseclipse.validation.ocl.OCLValidator; -//import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.common.notify.AdapterFactory; +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.ecore.EAttribute; +import org.eclipse.emf.ecore.EDataType; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EStructuralFeature; +import org.eclipse.emf.ecore.EValidator; +import org.eclipse.emf.ecore.EValidator.SubstitutionLabelProvider; import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.Diagnostician; +import org.eclipse.emf.edit.provider.IItemLabelProvider; +import org.eclipse.ocl.pivot.validation.ComposedEValidator; public class RiseClipseValidatorSCL { + public static final String DIAGNOSTIC_SOURCE = "fr.centralesupelec.edf.riseclipse"; + private static OCLValidator oclValidator; private static SclItemProviderAdapterFactory sclAdapter; private static SCLModelLoader sclLoader; - private static NSDValidator nsdValidator; + private static NsdValidator nsdValidator; private static boolean oclValidation = false; private static boolean nsdValidation = false; - private static NsdItemProviderAdapterFactory nsdAdapter; - public static void usage( IRiseClipseConsole console ) { + private static final IRiseClipseConsole console = new TextRiseClipseConsole(); + + private static void usage() { console.setLevel( IRiseClipseConsole.INFO_LEVEL ); - console.info( "java -jar RiseClipseValidatorSCL.jar [--verbose] [--make-explicit-links] [<oclFile> | <nsdFile> | <sclFile>]*" ); + console.info( + "java -jar RiseClipseValidatorSCL.jar [--info | --verbose] [--make-explicit-links] [<oclFile> | <nsdFile> | <sclFile>]*" ); console.info( "Files ending with \".ocl\" are considered OCL files, " - + "files ending with \\\".nsd\\\" are considered NSD files, " - + "all others are considered SCL files" ); + + "files ending with \\\".nsd\\\" are considered NSD files, " + + "all others are considered SCL files" ); System.exit( -1 ); } public static void main( String[] args ) { - - final IRiseClipseConsole console = new TextRiseClipseConsole(); - + console.setLevel( IRiseClipseConsole.INFO_LEVEL ); - displayLegal( console ); - + displayLegal(); console.setLevel( IRiseClipseConsole.WARNING_LEVEL ); - if( args.length == 0 ) usage( console ); - + console.doNotDisplayIdenticalMessages(); + + if( args.length == 0 ) usage(); + boolean make_explicit_links = false; int posFiles = 0; for( int i = 0; i < args.length; ++i ) { - if( args[i].startsWith( "--" )) { + if( args[i].startsWith( "--" ) ) { posFiles = i + 1; - if( "--verbose".equals( args[i] )) { + if( "--info".equals( args[i] ) ) { console.setLevel( IRiseClipseConsole.INFO_LEVEL ); } - else if( "--make-explicit-links".equals( args[i] )) { + else if( "--verbose".equals( args[i] ) ) { + console.setLevel( IRiseClipseConsole.VERBOSE_LEVEL ); + } + else if( "--make-explicit-links".equals( args[i] ) ) { make_explicit_links = true; } else { console.error( "Unrecognized option " + args[i] ); - usage( console ); + usage(); } } } - ArrayList< File > oclFiles = new ArrayList<>(); + ArrayList< String > oclFiles = new ArrayList<>(); ArrayList< String > nsdFiles = new ArrayList<>(); ArrayList< String > sclFiles = new ArrayList<>(); for( int i = posFiles; i < args.length; ++i ) { - if( args[i].endsWith( ".ocl" )) { - oclFiles.add( new File( args[i] )); + if( args[i].endsWith( ".ocl" ) ) { + oclFiles.add( args[i] ); oclValidation = true; } - else if( args[i].endsWith( ".nsd" )) { + else if( args[i].endsWith( ".nsd" ) ) { nsdFiles.add( args[i] ); nsdValidation = true; } @@ -96,17 +115,19 @@ public class RiseClipseValidatorSCL { sclFiles.add( args[i] ); } } - - prepare( console, oclFiles, nsdFiles ); + + prepare( oclFiles, nsdFiles ); for( int i = 0; i < sclFiles.size(); ++i ) { - run( console, make_explicit_links, sclFiles.get( i )); + run( make_explicit_links, sclFiles.get( i )); } } - - public static void displayLegal( IRiseClipseConsole console ) { + + private static void displayLegal() { console.info( "Copyright (c) 2019 CentraleSupélec & EDF." ); - console.info( "All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0" ); - console.info( "which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html" ); + console.info( + "All rights reserved. This program and the accompanying materials are made available under the terms of the Eclipse Public License v1.0" ); + console.info( + "which accompanies this distribution, and is available at http://www.eclipse.org/legal/epl-v10.html" ); console.info( "" ); console.info( "This file is part of the RiseClipse tool." ); console.info( "Contributors:" ); @@ -118,40 +139,41 @@ public class RiseClipseValidatorSCL { console.info( "Web site:" ); console.info( " http://wdi.supelec.fr/software/RiseClipse/" ); console.info( "" ); - console.info( "RiseClipseValidatorSCL version: 1.0.0 (28 January 2019)" ); + console.info( "RiseClipseValidatorSCL version: 1.0.0 (2 april 2019)" ); console.info( "" ); } - public static void prepare( IRiseClipseConsole console, ArrayList< File > oclFiles, ArrayList< String > nsdFiles ) { + private static void prepare( ArrayList< String > oclFiles, ArrayList< String > nsdFiles ) { + SclPackage sclPg = SclPackage.eINSTANCE; + if( sclPg == null ) { + throw new RiseClipseFatalException( "SCL package not found", null ); + } + + ComposedEValidator validator = ComposedEValidator.install( sclPg ); + if( oclValidation ) { - oclValidator = new OCLValidator( SclPackage.eINSTANCE, true ); - + oclValidator = new OCLValidator( sclPg, console ); + for( int i = 0; i < oclFiles.size(); ++i ) { - console.info( "Loading ocl: " + oclFiles.get( i )); - // workaround for bug 486872 -// File file = new File( oclFiles.get( i )); -// URI uri = file.isFile() ? URI.createFileURI( file.getAbsolutePath() ) : URI.createURI( oclFiles.get( i )); -// oclFiles.add( uri ); -// ocl.addOCLDocument( uri, console ); oclValidator.addOCLDocument( oclFiles.get( i ), console ); } + oclValidator.prepare( validator, console ); } - + if( nsdValidation ) { - nsdValidator = new NSDValidator( SclPackage.eINSTANCE ); - NSDModelLoader nsdLoader = new NSDModelLoader( console ); + nsdValidator = new NsdValidator( sclPg, console ); for( int i = 0; i < nsdFiles.size(); ++i ) { - console.info( "Loading nsd: " + nsdFiles.get( i )); - nsdValidator.addNSDDocument( nsdLoader.load( nsdFiles.get( i )), console ); + nsdValidator.addNsdDocument( nsdFiles.get( i ), console ); } - nsdAdapter = new NsdItemProviderAdapterFactory(); + nsdValidator.prepare( validator, console ); } sclLoader = new SCLModelLoader( console ); sclAdapter = new SclItemProviderAdapterFactory(); + } - public static void run( IRiseClipseConsole console, boolean make_explicit_links, String sclFile ) { + private static void run( boolean make_explicit_links, String sclFile ) { sclLoader.reset(); Resource resource = sclLoader.loadWithoutValidation( sclFile ); if( make_explicit_links ) { @@ -159,16 +181,62 @@ public class RiseClipseValidatorSCL { sclLoader.finalizeLoad(); } if( resource != null ) { - if( oclValidation ) { - console.info( "Validating file: " + sclFile + " with OCL" ); - oclValidator.validate( resource, sclAdapter, console ); + console.info( "Validating file: " + sclFile ); + validate( resource, sclAdapter ); + } + } + + private static void validate( Resource resource, final AdapterFactory adapter ) { + Map< Object, Object > context = new HashMap< Object, Object >(); + SubstitutionLabelProvider substitutionLabelProvider = new EValidator.SubstitutionLabelProvider() { + + @Override + public String getValueLabel( EDataType eDataType, Object value ) { + return Diagnostician.INSTANCE.getValueLabel( eDataType, value ); } - if( nsdValidation ) { - console.info( "Validating file: " + sclFile + " with NSD" ); - nsdValidator.validate( resource, nsdAdapter, console ); + + @Override + public String getObjectLabel( EObject eObject ) { + IItemLabelProvider labelProvider = ( IItemLabelProvider ) adapter.adapt( eObject, + IItemLabelProvider.class ); + return labelProvider.getText( eObject ); } - } + + @Override + public String getFeatureLabel( EStructuralFeature eStructuralFeature ) { + return Diagnostician.INSTANCE.getFeatureLabel( eStructuralFeature ); + } + }; + 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 ); + + if( diagnostic.getSeverity() == Diagnostic.ERROR || diagnostic.getSeverity() == Diagnostic.WARNING ) { + for( Iterator< Diagnostic > i = diagnostic.getChildren().iterator(); i.hasNext(); ) { + Diagnostic childDiagnostic = i.next(); + switch( childDiagnostic.getSeverity() ) { + case Diagnostic.ERROR: + case Diagnostic.WARNING: + List< ? > data = childDiagnostic.getData(); + EObject object = ( EObject ) data.get( 0 ); + if( data.size() == 1 ) { + console.error( "\t" + childDiagnostic.getMessage() ); + } + else if( data.get( 1 ) instanceof EAttribute ) { + EAttribute attribute = ( EAttribute ) data.get( 1 ); + if( attribute == null ) continue; + console.error( "\tAttribute " + attribute.getName() + " of " + + substitutionLabelProvider.getObjectLabel( object ) + " : " + + childDiagnostic.getChildren().get( 0 ).getMessage() ); + } + else { + console.error( "\t" + childDiagnostic.getMessage() ); + } + } + } + } + } } } - diff --git a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/SCLModelLoader.java b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/SCLModelLoader.java index 59c99bdfc141d0b49c6aa991496c14b0a87a2022..f725dabdd5de4302cad4d13b6ee6b164e6948dcc 100644 --- a/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/SCLModelLoader.java +++ b/fr.centralesupelec.edf.riseclipse.iec61850.scl.tools/src/fr/centralesupelec/edf/riseclipse/iec61850/scl/validator/SCLModelLoader.java @@ -27,9 +27,8 @@ import fr.centralesupelec.edf.riseclipse.util.IRiseClipseConsole; import fr.centralesupelec.edf.riseclipse.util.RiseClipseModelLoader; import fr.centralesupelec.edf.riseclipse.util.TextRiseClipseConsole; - public class SCLModelLoader extends RiseClipseModelLoader { - + public SCLModelLoader( IRiseClipseConsole console ) { super( console ); } @@ -41,27 +40,27 @@ public class SCLModelLoader extends RiseClipseModelLoader { // Register the appropriate resource factory to handle all file // extensions. getResourceSet().getResourceFactoryRegistry().getExtensionToFactoryMap() - .put( Resource.Factory.Registry.DEFAULT_EXTENSION, new SclResourceFactoryImpl() ); + .put( Resource.Factory.Registry.DEFAULT_EXTENSION, new SclResourceFactoryImpl() ); // Register the package to ensure it is available during loading. getResourceSet().getPackageRegistry().put( SclPackage.eNS_URI, SclPackage.eINSTANCE ); } - + public Resource loadWithoutValidation( String name ) { Object eValidator = EValidator.Registry.INSTANCE.remove( SclPackage.eINSTANCE ); Resource resource = load( name ); - + if( eValidator != null ) { EValidator.Registry.INSTANCE.put( SclPackage.eINSTANCE, eValidator ); } return resource; } - + public static void main( String[] args ) { IRiseClipseConsole console = new TextRiseClipseConsole(); SCLModelLoader loader = new SCLModelLoader( console ); - + for( int i = 0; i < args.length; ++i ) { @SuppressWarnings( "unused" ) Resource resource = loader.load( args[i] );