diff --git a/.github/workflows/build-project.yml b/.github/workflows/build-project.yml index 96d9281..f2a41a2 100644 --- a/.github/workflows/build-project.yml +++ b/.github/workflows/build-project.yml @@ -22,6 +22,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + with: + submodules: 'true' - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v1 @@ -48,9 +50,5 @@ jobs: with: output_file: custom_maven_settings.xml servers: '[{ "id": "github-packages-compas", "username": "OWNER", "password": "${{ secrets.GITHUB_TOKEN }}" }]' - - name: Build Native with Maven - if: ${{ github.event_name == 'pull_request' }} - run: ./mvnw -s custom_maven_settings.xml -B -Pnative clean verify - name: Build with Maven - if: ${{ github.event_name == 'push' }} run: ./mvnw -s custom_maven_settings.xml -B clean verify diff --git a/.github/workflows/release-project.yml b/.github/workflows/release-project.yml index a879bf3..dcb14e3 100644 --- a/.github/workflows/release-project.yml +++ b/.github/workflows/release-project.yml @@ -16,6 +16,8 @@ jobs: steps: - name: Checkout uses: actions/checkout@v3 + with: + submodules: 'true' - name: Set up Docker Buildx id: buildx uses: docker/setup-buildx-action@v1 @@ -57,6 +59,6 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Deploy with Maven to GitHub Packages and Docker Hub - run: ./mvnw -B -s custom_maven_settings.xml -Prelease,native clean deploy + run: ./mvnw -B -s custom_maven_settings.xml -Prelease clean deploy env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/sonarcloud-analysis.yml b/.github/workflows/sonarcloud-analysis.yml index 3b3b6f8..f122906 100644 --- a/.github/workflows/sonarcloud-analysis.yml +++ b/.github/workflows/sonarcloud-analysis.yml @@ -29,6 +29,7 @@ jobs: uses: actions/checkout@v3 with: fetch-depth: 0 + submodules: 'true' - name: Set up JDK 1.11 uses: actions/setup-java@v3 diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..d9bdeff --- /dev/null +++ b/.gitmodules @@ -0,0 +1,24 @@ +# SPDX-FileCopyrightText: 2022 Alliander N.V. +# +# SPDX-License-Identifier: Apache-2.0 + +# +# Remark: the option to ignore 'untracked' files is needed, because the submodules don't contain a file '.gitignore'. +# This cause the target directories to be untracked. +# +[submodule "riseclipse/riseclipse-developer"] + path = riseclipse/riseclipse-developer + url = git@github.com:riseclipse/riseclipse-developer.git + ignore = dirty +[submodule "riseclipse/riseclipse-main"] + path = riseclipse/riseclipse-main + url = git@github.com:riseclipse/riseclipse-main.git + ignore = dirty +[submodule "riseclipse/riseclipse-metamodel-scl2003"] + path = riseclipse/riseclipse-metamodel-scl2003 + url = git@github.com:riseclipse/riseclipse-metamodel-scl2003.git + ignore = dirty +[submodule "riseclipse/riseclipse-ocl-constraints-scl2003"] + path = riseclipse/riseclipse-ocl-constraints-scl2003 + url = git@github.com:riseclipse/riseclipse-ocl-constraints-scl2003.git + ignore = dirty diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md new file mode 100644 index 0000000..27e2f4c --- /dev/null +++ b/DEVELOPMENT.md @@ -0,0 +1,82 @@ + + +# Development + +## Git + +If the project is already cloned and a submodule is added use the following commands, first `git submodule init` and +next `git submodule update`. + +More about Git Submodules can be found [here](https://git-scm.com/book/en/v2/Git-Tools-Submodules). + +**Remark**: The URLs to the submodules are configured in the file `.gitmodules`, but these are using the SSH URLs. There +is a way described [here](https://git-scm.com/book/en/v2/Git-Tools-Submodules) that the URL can be overwritten locally +with an HTTPS URL of the GIT Repository. Because of the subdirectory where the submodules are in, this doesn't work +exactly that way. Use the following commands to update the URLs locally to HTTPS. + +``` +git config submodule.riseclipse/riseclipse-developer.url https://github.com/riseclipse/riseclipse-developer.git +git config submodule.riseclipse/riseclipse-main.url https://github.com/riseclipse/riseclipse-main.git +git config submodule.riseclipse/riseclipse-metamodel-scl2003.url https://github.com/riseclipse/riseclipse-metamodel-scl2003.git +git config submodule.riseclipse/riseclipse-ocl-constraints-scl2003.url https://github.com/riseclipse/riseclipse-ocl-constraints-scl2003.git + +git submodule init +git submodule update +``` + +## IntelliJ + +Importing the project is a bit harder for the SCL Validator then normal. It's caused because of the submodules that are +needed from RiseClipse. These projects are Eclipse projects using Eclipse Tycho to build and Eclipse project structure. + +A way to make everything work in IntelliJ is importing the project in the following way. + +- First step is to just import everything like it are Maven projects; +- Next step is to re-import the RiseClipse Submodule as Eclipse; + - In IntelliJ select "File" -> "New" -> "Module from Existing Sources..."; + - Select one of the RiseClipse Submodules, for instance "riseclipse-metamodel-scl2003"; + - Next select "Eclipse" by "Import module from External Model"; + - Follow the rest of the wizard, only to remember to select all subprojects that are available in the directory; + +Now the module should be correctly imported in IntelliJ to be used. Check the Module Settings of one of the subprojects +to check if the directory "src" is a Java Source Directory, for instance the module +"riseclipse/riseclipse-metamodel-scl2003/fr.centralesupelec.edf.riseclipse.iec61850.scl.utilities". + +## Eclipse + +Example about how to use Eclipse OCL was found +[here](https://help.eclipse.org/latest/index.jsp?topic=%2Forg.eclipse.ocl.doc%2Fhelp%2FPivotStandalone.html). + +## Running the application in dev mode + +You can run your application in dev mode that enables live coding using: + +```shell script +./mvnw package io.quarkus:quarkus-maven-plugin::dev +``` + +> **_NOTE:_** Quarkus now ships with a Dev UI, which is available in dev mode only at http://localhost:8080/q/dev/. + +## Packaging and running the application + +The application can be packaged using: + +```shell script +./mvnw package +``` + +It produces the `quarkus-run.jar` file in the `app/target/quarkus-app/` directory. Be aware that it’s not an _über-jar_ +as the dependencies are copied into the `app/target/quarkus-app/lib/` directory. + +If you want to build an _über-jar_, execute the following command: + +```shell script +./mvnw package -Dquarkus.package.type=uber-jar +``` + +The application is now runnable using `java -jar app/target/quarkus-app/quarkus-run.jar`. + diff --git a/README.md b/README.md index b0afaf7..efc1a15 100644 --- a/README.md +++ b/README.md @@ -14,27 +14,38 @@ SPDX-License-Identifier: Apache-2.0 Service to validate SCL Files. +## Development + +For the RiseClipse implementation of the validator parts of the RiseClipse project are being used. Currently, these +parts aren't distributed to any Maven Repository, so the Git Repositories need to be included. This is done using Git +Submodules. + +To clone the project or update the project this means that the Git commands are sometimes a little different. To clone +the project use the following command `git clone --recurse-submodules git@github.com:com-pas/compas-scl-validator.git`. +This will also clone the submodules. + +Tip: The URL to the submodules are configured in the file `.gitmodules`, but these are using the SSH URL. There is a way +described in the URL above that the URL can be overwritten locally with an HTTPS URL of the GIT Repository. + +Check the [Development](DEVELOPMENT.md) page for more detail information how to work with this repository, because of +the mixture with RiseClipse. ## Common Environment variables -Below environment variable(s) can be used to configure which claims and information are used to fill the UserInfo -response. +Below environment variable(s) can be used to configure the validator. -| Environment variable | Java Property | Description | Example | -| -------------------------------- | ------------------------------- | ----------------------------------------------------------- | ---------------- | -| USERINFO_NAME_CLAIMNAME | compas.userinfo.name.claimname | The Name of the user logged in. | name | -| USERINFO_WHO_CLAIMNAME | compas.userinfo.who.claimname | The Name of the user used in the Who History. | name | -| USERINFO_SESSION_WARNING | compas.userinfo.session.warning | Number of minutes a Session Warning can be displayed. | 20 | -| USERINFO_SESSION_EXPIRES | compas.userinfo.session.expires | Number of minutes a Session Expires to display in Frontend. | 30 | +| Environment variable | Java Property | Description | Example | +|---------------------------------------|---------------------------------------|---------------------------------------------------|-----------| +| COMPAS_VALIDATOR_OCL_CUSTOM_DIRECTORY | compas.validator.ocl.custom.directory | Reference to a directory to load custom OCL Files | /data/ocl | ## Security To use most of the endpoints the users needs to be authenticated using JWT in the authorization header. There are 4 environment variables that can be set in the container to configure the validation/processing of the JWT. -| Environment variable | Java Property | Description | Example | -| -------------------------------- | -------------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------- | -| JWT_VERIFY_KEY | smallrye.jwt.verify.key.location | Location of certificates to verify the JWT. | http://localhost:8089/auth/realms/compas/protocol/openid-connect/certs | -| JWT_VERIFY_ISSUER | mp.jwt.verify.issuer | The issuer of the JWT. | http://localhost:8089/auth/realms/compas | -| JWT_VERIFY_CLIENT_ID | mp.jwt.verify.audiences | The Client ID that should be in the "aud" claim. | scl-validator | -| JWT_GROUPS_PATH | smallrye.jwt.path.groups | The JSON Path where to find the roles of the user. | resource_access/scl-validator/roles | +| Environment variable | Java Property | Description | Example | +|----------------------|----------------------------------|----------------------------------------------------|------------------------------------------------------------------------| +| JWT_VERIFY_KEY | smallrye.jwt.verify.key.location | Location of certificates to verify the JWT. | http://localhost:8089/auth/realms/compas/protocol/openid-connect/certs | +| JWT_VERIFY_ISSUER | mp.jwt.verify.issuer | The issuer of the JWT. | http://localhost:8089/auth/realms/compas | +| JWT_VERIFY_CLIENT_ID | mp.jwt.verify.audiences | The Client ID that should be in the "aud" claim. | scl-validator | +| JWT_GROUPS_PATH | smallrye.jwt.path.groups | The JSON Path where to find the roles of the user. | resource_access/scl-validator/roles | diff --git a/app/pom.xml b/app/pom.xml index 30f2594..d9ac269 100644 --- a/app/pom.xml +++ b/app/pom.xml @@ -86,6 +86,12 @@ SPDX-License-Identifier: Apache-2.0 test-jar test + + org.lfenergy.compas.scl.validator + validator-riseclipse + test-jar + test + io.quarkus @@ -112,6 +118,11 @@ SPDX-License-Identifier: Apache-2.0 quarkus-jacoco test + + org.mockito + mockito-junit-jupiter + test + com.openpojo openpojo @@ -156,8 +167,13 @@ SPDX-License-Identifier: Apache-2.0 native - true - true + + true + + true + + --allow-incomplete-classpath + @@ -174,8 +190,12 @@ SPDX-License-Identifier: Apache-2.0 - ${project.build.directory}/${project.build.finalName}-runner - org.jboss.logmanager.LogManager + + ${project.build.directory}/${project.build.finalName}-runner + + + org.jboss.logmanager.LogManager + ${maven.home} @@ -201,8 +221,8 @@ SPDX-License-Identifier: Apache-2.0 release - true + true latest diff --git a/app/src/main/docker/Dockerfile.jvm b/app/src/main/docker/Dockerfile.jvm index fcd9ec4..fcbad5c 100644 --- a/app/src/main/docker/Dockerfile.jvm +++ b/app/src/main/docker/Dockerfile.jvm @@ -48,6 +48,12 @@ COPY --chown=1001 target/quarkus-app/*.jar /deployments/ COPY --chown=1001 target/quarkus-app/app/ /deployments/app/ COPY --chown=1001 target/quarkus-app/quarkus/ /deployments/quarkus/ +RUN mkdir -p /data/ocl \ + && mkdir -p /data/temp \ + && chown -R 1001 /data \ + && chmod -R "g+rwX" /data +VOLUME /data/ocl + EXPOSE 8080 USER 1001 diff --git a/app/src/main/docker/Dockerfile.native b/app/src/main/docker/Dockerfile.native index 211c60f..286bd97 100644 --- a/app/src/main/docker/Dockerfile.native +++ b/app/src/main/docker/Dockerfile.native @@ -21,6 +21,12 @@ RUN chown 1001 /work \ && chown 1001:root /work COPY --chown=1001:root target/*-runner /work/application +RUN mkdir -p /data/ocl \ + && mkdir -p /data/temp \ + && chown -R 1001 /data \ + && chmod -R "g+rwX" /data +VOLUME /data/ocl + EXPOSE 8080 USER 1001 diff --git a/app/src/main/java/org/lfenergy/compas/scl/validator/rest/CompasSclValidatorConfiguration.java b/app/src/main/java/org/lfenergy/compas/scl/validator/rest/CompasSclValidatorConfiguration.java index dd9dd26..eefef07 100644 --- a/app/src/main/java/org/lfenergy/compas/scl/validator/rest/CompasSclValidatorConfiguration.java +++ b/app/src/main/java/org/lfenergy/compas/scl/validator/rest/CompasSclValidatorConfiguration.java @@ -4,6 +4,9 @@ package org.lfenergy.compas.scl.validator.rest; import org.lfenergy.compas.core.commons.ElementConverter; +import org.lfenergy.compas.scl.validator.collector.CompasOclFileCollector; +import org.lfenergy.compas.scl.validator.collector.OclFileCollector; +import org.lfenergy.compas.scl.validator.impl.SclRiseClipseValidator; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.inject.Produces; @@ -17,4 +20,17 @@ public class CompasSclValidatorConfiguration { public ElementConverter createElementConverter() { return new ElementConverter(); } + + @Produces + @ApplicationScoped + public OclFileCollector createOclFileCollector(ValidatorProperties properties) { + return new CompasOclFileCollector(properties.oclCustomDirectory()); + } + + @Produces + @ApplicationScoped + public SclRiseClipseValidator createSclRiseClipseValidator(OclFileCollector oclFileCollector, + ValidatorProperties properties) { + return new SclRiseClipseValidator(oclFileCollector, properties.tempDirectory()); + } } diff --git a/app/src/main/java/org/lfenergy/compas/scl/validator/rest/ValidatorProperties.java b/app/src/main/java/org/lfenergy/compas/scl/validator/rest/ValidatorProperties.java new file mode 100644 index 0000000..ae11818 --- /dev/null +++ b/app/src/main/java/org/lfenergy/compas/scl/validator/rest/ValidatorProperties.java @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2021 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.rest; + +import io.smallrye.config.ConfigMapping; +import io.smallrye.config.WithName; + +import java.nio.file.Path; + +@ConfigMapping(prefix = "compas.validator") +public interface ValidatorProperties { + @WithName("ocl.custom.directory") + String oclCustomDirectory(); + + @WithName("temp.directory") + Path tempDirectory(); +} diff --git a/app/src/main/resources/application.properties b/app/src/main/resources/application.properties index 0ead43d..d98a2e6 100644 --- a/app/src/main/resources/application.properties +++ b/app/src/main/resources/application.properties @@ -2,7 +2,8 @@ # # SPDX-License-Identifier: Apache-2.0 -compas.userinfo.who.claimname = ${USERINFO_WHO_CLAIMNAME:name} +compas.validator.ocl.custom.directory = /data/ocl +compas.validator.temp.directory = /data/temp quarkus.http.cors = false quarkus.http.root-path = /compas-scl-validator/ @@ -11,18 +12,11 @@ quarkus.http.limits.max-body-size = 150M quarkus.log.level = INFO quarkus.log.category."org.lfenergy.compas.scl.validator".level = INFO -# Add scanning these dependencies for scanning, also used by native compilation. -quarkus.index-dependency.scl2007b4.group-id=org.lfenergy.compas.core -quarkus.index-dependency.scl2007b4.artifact-id=commons - -quarkus.index-dependency.jaxb-api.group-id=org.jboss.spec.javax.xml.bind -quarkus.index-dependency.jaxb-api.artifact-id=jboss-jaxb-api_2.3_spec - -# Settings needed for native compilation of the project. -quarkus.native.resources.includes=ConvergenceLibrary/*.*,*.css - # Dev Profile overrides. -%dev.quarkus.http.port = 9092 +%dev.compas.validator.ocl.custom.directory = ./src/test/data/ocl +%dev.compas.validator.temp.directory = ./target/data/temp + +%dev.quarkus.http.port = 9093 %dev.quarkus.http.cors = true %dev.quarkus.log.level = DEBUG diff --git a/app/src/test/data/ocl/Busbar.ocl b/app/src/test/data/ocl/Busbar.ocl new file mode 100644 index 0000000..f6a2785 --- /dev/null +++ b/app/src/test/data/ocl/Busbar.ocl @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 + +/* +************************************************************************* +** Copyright (c) 2016-2021 CentraleSupélec & EDF. +** All rights reserved. This program and the accompanying materials +** are made available under the terms of the Eclipse Public License v2.0 +** which accompanies this distribution, and is available at +** https://www.eclipse.org/legal/epl-v20.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: +** https://riseclipse.github.io/ +************************************************************************* +*/ + +import scl: 'http://www.iec.ch/61850/2003/SCL' + +package scl + +context Bay +-- extends EquipmentContainer + + -- The name attribute is verified in Naming.ocl + inv Busbar_nothing + : + true + + +endpackage + diff --git a/app/src/test/java/org/lfenergy/compas/scl/validator/rest/CompasOclFileCollectorFromJarTest.java b/app/src/test/java/org/lfenergy/compas/scl/validator/rest/CompasOclFileCollectorFromJarTest.java new file mode 100644 index 0000000..5a6c641 --- /dev/null +++ b/app/src/test/java/org/lfenergy/compas/scl/validator/rest/CompasOclFileCollectorFromJarTest.java @@ -0,0 +1,24 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.rest; + +import org.junit.jupiter.api.Test; +import org.lfenergy.compas.scl.validator.collector.AbstractCompasOclFileCollectorTest; +import org.lfenergy.compas.scl.validator.collector.CompasOclFileCollector; + +/** + * This test is added in this project to check if loading the OCL Files from a JAR File is also working. + * Loading works in a different way from the module itself and from another module through a JAR File. + */ +class CompasOclFileCollectorFromJarTest extends AbstractCompasOclFileCollectorTest { + @Test + void getDefaultOclFiles_WhenCalledWithoutCustomDirectory_ThenListReturned() { + assertValidateOclFileCollector(new CompasOclFileCollector(null), 226); + } + + @Test + void getDefaultOclFiles_WhenCalledWithCustomDirectory_ThenListReturned() { + assertValidateOclFileCollector(new CompasOclFileCollector("./src/test/data/ocl"), 227); + } +} diff --git a/app/src/test/java/org/lfenergy/compas/scl/validator/rest/CompasSclValidatorConfigurationTest.java b/app/src/test/java/org/lfenergy/compas/scl/validator/rest/CompasSclValidatorConfigurationTest.java index e0c264e..b3932ba 100644 --- a/app/src/test/java/org/lfenergy/compas/scl/validator/rest/CompasSclValidatorConfigurationTest.java +++ b/app/src/test/java/org/lfenergy/compas/scl/validator/rest/CompasSclValidatorConfigurationTest.java @@ -4,12 +4,45 @@ package org.lfenergy.compas.scl.validator.rest; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.lfenergy.compas.scl.validator.collector.OclFileCollector; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.nio.file.Path; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.mockito.Mockito.*; +@ExtendWith(MockitoExtension.class) class CompasSclValidatorConfigurationTest { + @Mock + private ValidatorProperties validatorProperties; + @Mock + private OclFileCollector oclFileCollector; + @Test void createElementConverter_WhenCalled_ThenObjectReturned() { assertNotNull(new CompasSclValidatorConfiguration().createElementConverter()); } -} \ No newline at end of file + + @Test + void createOclFileCollector_WhenCalled_ThenObjectReturned() { + when(validatorProperties.oclCustomDirectory()).thenReturn("/somedirectory"); + + assertNotNull(new CompasSclValidatorConfiguration().createOclFileCollector(validatorProperties)); + + verify(validatorProperties, times(1)).oclCustomDirectory(); + } + + @Test + void createSclRiseClipseValidator_WhenCalled_ThenObjectReturned() { + when(validatorProperties.tempDirectory()).thenReturn(Path.of("./target/tempdirectory")); + + assertNotNull(new CompasSclValidatorConfiguration().createSclRiseClipseValidator( + oclFileCollector, + validatorProperties)); + + verify(validatorProperties, times(1)).tempDirectory(); + } +} diff --git a/pom.xml b/pom.xml index 1a2c801..6051fe0 100644 --- a/pom.xml +++ b/pom.xml @@ -33,7 +33,7 @@ SPDX-License-Identifier: Apache-2.0 validator - validator-riseclipse + riseclipse service app @@ -51,6 +51,9 @@ SPDX-License-Identifier: Apache-2.0 github-packages-compas Github Packages CoMPAS https://maven.pkg.github.com/com-pas/* + + false + @@ -114,6 +117,12 @@ SPDX-License-Identifier: Apache-2.0 ${project.version} test-jar + + org.lfenergy.compas.scl.validator + validator-riseclipse + ${project.version} + test-jar + com.openpojo @@ -139,6 +148,9 @@ SPDX-License-Identifier: Apache-2.0 org.apache.maven.plugins maven-surefire-plugin ${surefire-plugin.version} + + false + diff --git a/riseclipse/pom.xml b/riseclipse/pom.xml new file mode 100644 index 0000000..1a47cce --- /dev/null +++ b/riseclipse/pom.xml @@ -0,0 +1,116 @@ + + + + 4.0.0 + + org.lfenergy.compas.scl.validator + compas-scl-validator + local-SNAPSHOT + + + riseclipse + pom + + + riseclipse-developer + riseclipse-main + riseclipse-metamodel-scl2003 + validator-riseclipse + + + + 3.16.0 + 2.25.0 + 2.23.0 + 1.17.0 + 3.2.0 + 1.1.0-SNAPSHOT + + ${project.basedir}/riseclipse-developer + + + + + local-eclipse-p2-mirror + + file:///${riseclipse.developer.root}/fr.centralesupelec.edf.riseclipse.developer.p2_to_m2/target/maven/repository/final + + + + + + + + fr.centralesupelec.edf.riseclipse + fr.centralesupelec.edf.riseclipse.iec61850.scl + ${riseclipse.version} + + + + org.eclipse.core + org.eclipse.core.resources + ${eclipse.core.resources.version} + + + + org.eclipse.emf + org.eclipse.emf.common + ${eclipse.emf.common.version} + + + org.eclipse.emf + org.eclipse.emf.ecore + ${eclipse.emf.ecore.version} + + + + org.eclipse.ocl + org.eclipse.ocl.pivot + ${eclipse.ocl.version} + + + org.eclipse.ocl + org.eclipse.ocl.xtext.completeocl + ${eclipse.ocl.version} + + + org.antlr + antlr-runtime + + + + org.eclipse.ocl + org.eclipse.ocl.pivot.uml + + + + org.eclipse.emf + org.eclipse.emf.codegen + + + + org.eclipse.platform + org.eclipse.equinox.common + + + + + org.eclipse.ocl + org.eclipse.ocl.xtext.oclstdlib + ${eclipse.ocl.version} + + + + org.antlr.runtime + org.antlr.runtime + ${antlr.runtime.version} + + + + diff --git a/riseclipse/riseclipse-developer b/riseclipse/riseclipse-developer new file mode 160000 index 0000000..e889e0c --- /dev/null +++ b/riseclipse/riseclipse-developer @@ -0,0 +1 @@ +Subproject commit e889e0cfc6e245abba13e98ff652b8ebf119a831 diff --git a/riseclipse/riseclipse-main b/riseclipse/riseclipse-main new file mode 160000 index 0000000..de05dba --- /dev/null +++ b/riseclipse/riseclipse-main @@ -0,0 +1 @@ +Subproject commit de05dba3434591303437d3ec34d88ecdc7a3af09 diff --git a/riseclipse/riseclipse-metamodel-scl2003 b/riseclipse/riseclipse-metamodel-scl2003 new file mode 160000 index 0000000..63e5fe4 --- /dev/null +++ b/riseclipse/riseclipse-metamodel-scl2003 @@ -0,0 +1 @@ +Subproject commit 63e5fe4526aa1f3834d7ec947094de4451a2f570 diff --git a/riseclipse/riseclipse-ocl-constraints-scl2003 b/riseclipse/riseclipse-ocl-constraints-scl2003 new file mode 160000 index 0000000..484205c --- /dev/null +++ b/riseclipse/riseclipse-ocl-constraints-scl2003 @@ -0,0 +1 @@ +Subproject commit 484205cd33bc5b543bfeb215fdf8679effe4641f diff --git a/riseclipse/validator-riseclipse/pom.xml b/riseclipse/validator-riseclipse/pom.xml new file mode 100644 index 0000000..6f92e11 --- /dev/null +++ b/riseclipse/validator-riseclipse/pom.xml @@ -0,0 +1,122 @@ + + + + 4.0.0 + + org.lfenergy.compas.scl.validator + riseclipse + local-SNAPSHOT + + + validator-riseclipse + jar + + + ${project.basedir}/../riseclipse-developer + + + + + org.lfenergy.compas.scl.validator + validator + + + + fr.centralesupelec.edf.riseclipse + fr.centralesupelec.edf.riseclipse.iec61850.scl + + + + org.eclipse.core + org.eclipse.core.resources + + + + org.eclipse.emf + org.eclipse.emf.common + + + org.eclipse.emf + org.eclipse.emf.ecore + + + + org.eclipse.ocl + org.eclipse.ocl.pivot + + + org.eclipse.ocl + org.eclipse.ocl.xtext.completeocl + + + org.eclipse.ocl + org.eclipse.ocl.xtext.oclstdlib + + + + org.antlr.runtime + org.antlr.runtime + + + + + org.mockito + mockito-junit-jupiter + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.slf4j + slf4j-simple + test + + + + + + + maven-resources-plugin + 3.2.0 + + + copy-resources + + validate + + copy-resources + + + ${project.build.outputDirectory}/ocl + + + + ../riseclipse-ocl-constraints-scl2003/fr.centralesupelec.edf.riseclipse.iec61850.scl.ocl + + false + + .project + + + + + + + + + + org.jboss.jandex + jandex-maven-plugin + + + + diff --git a/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/collector/AbstractFileCollector.java b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/collector/AbstractFileCollector.java new file mode 100644 index 0000000..57fc4c2 --- /dev/null +++ b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/collector/AbstractFileCollector.java @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.collector; + +import org.eclipse.emf.common.util.URI; +import org.lfenergy.compas.scl.validator.exception.SclValidatorException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.net.URISyntaxException; +import java.nio.file.*; +import java.util.Collections; +import java.util.List; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static org.lfenergy.compas.scl.validator.exception.SclValidatorErrorCode.LOADING_CUSTOM_OCL_FILES_FAILED; +import static org.lfenergy.compas.scl.validator.exception.SclValidatorErrorCode.LOADING_OCL_FILES_FAILED; + +/** + * Abstract class to support retrieving default files from the ClassPath or from a Directory. + */ +public abstract class AbstractFileCollector implements OclFileCollector { + private static final Logger LOGGER = LoggerFactory.getLogger(AbstractFileCollector.class); + + private static final String DEFAULT_OCL_DIRECTORY = "/ocl/"; + + /** + * Search for all files (with extension ocl) in the directory 'ocl' on the classpath. + * + * @return The List of Default OCL Files as URI that Compas uses to validate with RiseClipse. + * @throws SclValidatorException Thrown when there is some I/O or URI Syntax Error. + */ + protected List getDefaultOclFilesFromClasspath() { + Predicate filter = path -> path.toString().endsWith(".ocl"); + + try { + LOGGER.debug("Using Thread to search for Resource"); + var resource = Thread.currentThread().getContextClassLoader().getResource(DEFAULT_OCL_DIRECTORY); + if (resource == null) { + LOGGER.debug("Using Class to search for Resource"); + resource = getClass().getResource(DEFAULT_OCL_DIRECTORY); + } + if (resource != null) { + var uri = resource.toURI(); + LOGGER.debug("Resource '{}' found with schema '{}'.", uri, uri.getScheme()); + // The directory is in a JAR, search will be different. + if (uri.getScheme().equals("jar")) { + try (FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap())) { + var oclDirectoryPath = fileSystem.getPath(DEFAULT_OCL_DIRECTORY); + try (var walk = Files.walk(oclDirectoryPath)) { + return walk.filter(filter) + .map(path -> URI.createURI(path.toUri().toString())) + .collect(Collectors.toList()); + } + } + } else { + var oclDirectoryPath = Paths.get(uri); + try (var walk = Files.walk(oclDirectoryPath)) { + return walk.filter(filter) + .map(Path::toFile) + .filter(File::isFile) + .map(file -> URI.createFileURI(file.getAbsolutePath())) + .collect(Collectors.toList()); + } + } + } else { + LOGGER.error("No Resource '{}' found!", DEFAULT_OCL_DIRECTORY); + } + return Collections.emptyList(); + } catch (URISyntaxException | IOException exp) { + throw new SclValidatorException(LOADING_OCL_FILES_FAILED, "Error loading OCL Files", exp); + } + } + + /** + * Search (recursively) for all files in the directory passed. The filter can be used to filter files from the List. + * + * @param directoryName The directory in which top search for files (recursively). + * @param filter The filter used to filter the list of file, use '(path) -> true' to return them all. + * @return The list of Files as URI found. + */ + protected List getFilesFromDirectory(String directoryName, Predicate filter) { + try { + File directory = new File(directoryName); + if (directory.exists() && directory.isDirectory()) { + var oclDirectoryPath = Paths.get(directory.toURI()); + try (var walk = Files.walk(oclDirectoryPath)) { + return walk.filter(filter) + .map(Path::toFile) + .filter(File::isFile) + .map(file -> URI.createFileURI(file.getAbsolutePath())) + .collect(Collectors.toList()); + } + } + return Collections.emptyList(); + } catch (IOException exp) { + throw new SclValidatorException(LOADING_CUSTOM_OCL_FILES_FAILED, "Error loading Custom OCL Files", exp); + } + } +} diff --git a/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/collector/CompasOclFileCollector.java b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/collector/CompasOclFileCollector.java new file mode 100644 index 0000000..947ef71 --- /dev/null +++ b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/collector/CompasOclFileCollector.java @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.collector; + +import org.eclipse.emf.common.util.URI; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.ArrayList; +import java.util.List; + +/** + * OCL File collector which combines the default OCL Files from the Classpath with all files found in a custom + * directory configured. + */ +public class CompasOclFileCollector extends AbstractFileCollector { + private static final Logger LOGGER = LoggerFactory.getLogger(CompasOclFileCollector.class); + + private final String oclCustomDirectory; + + public CompasOclFileCollector(String oclCustomDirectory) { + this.oclCustomDirectory = oclCustomDirectory; + } + + @Override + public List getOclFiles() { + LOGGER.debug("Searching for OCL Files in classpath."); + + var oclFiles = new ArrayList<>(getDefaultOclFilesFromClasspath()); + if (oclCustomDirectory != null) { + LOGGER.debug("Searching for OCL Files in custom directory '{}'.", oclCustomDirectory); + oclFiles.addAll(getFilesFromDirectory(oclCustomDirectory, path -> path.toString().endsWith(".ocl"))); + } + return oclFiles; + } +} diff --git a/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/collector/OclFileCollector.java b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/collector/OclFileCollector.java new file mode 100644 index 0000000..ddb4996 --- /dev/null +++ b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/collector/OclFileCollector.java @@ -0,0 +1,15 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.collector; + +import org.eclipse.emf.common.util.URI; + +import java.util.List; + +/** + * Interface used to collect OCL Files for use in the SCL Validator. + */ +public interface OclFileCollector { + List getOclFiles(); +} diff --git a/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/impl/OclFileLoader.java b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/impl/OclFileLoader.java new file mode 100644 index 0000000..320f828 --- /dev/null +++ b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/impl/OclFileLoader.java @@ -0,0 +1,108 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.impl; + +import fr.centralesupelec.edf.riseclipse.iec61850.scl.SclPackage; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource.Diagnostic; +import org.eclipse.ocl.pivot.resource.CSResource; +import org.eclipse.ocl.pivot.utilities.OCL; +import org.eclipse.ocl.pivot.validation.ComposedEValidator; +import org.eclipse.ocl.xtext.completeocl.validation.CompleteOCLEObjectValidator; +import org.lfenergy.compas.scl.validator.exception.SclValidatorException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.List; + +import static org.lfenergy.compas.scl.validator.exception.SclValidatorErrorCode.*; + +public class OclFileLoader { + private static final Logger LOGGER = LoggerFactory.getLogger(OclFileLoader.class); + + private final Path oclTempFile; + private final OCL ocl; + + public OclFileLoader(OCL ocl, Path tempDirectoryPath) { + this.ocl = ocl; + + // *.ocl Complete OCL documents support required + org.eclipse.ocl.xtext.completeocl.CompleteOCLStandaloneSetup.doSetup(); + // *.oclstdlib OCL Standard Library support required + org.eclipse.ocl.xtext.oclstdlib.OCLstdlibStandaloneSetup.doSetup(); + + // First make sure the directory for temporary file exists. + var tempDirectory = tempDirectoryPath.toFile(); + if (!tempDirectory.exists() && !tempDirectory.mkdirs()) { + throw new SclValidatorException(CREATE_OCL_TEMP_DIR_FAILED, "Unable to create temporary directory"); + } + + try { + oclTempFile = Files.createTempFile(tempDirectoryPath, "allConstraints", ".ocl"); + } catch (IOException exp) { + throw new SclValidatorException(CREATE_OCL_TEMP_FILES_FAILED, "Unable to create temporary file", exp); + } + } + + public void addOCLDocument(URI oclUri) { + if (oclUri == null) { + throw new SclValidatorException(NO_URI_PASSED, "Unable to create URI for temporary file"); + } + + // We want to check the validity of OCL files + // So, we have to do it now, before concatenating it to oclTempFile + CSResource oclResource; + try { + oclResource = ocl.getCSResource(oclUri); + if (!oclResource.getErrors().isEmpty()) { + logErrorMessage(oclUri, oclResource.getErrors()); + } else { + appendToTempFile(oclUri); + } + } catch (IOException exp) { + LOGGER.error("Unable to read OCL file '{}'", oclUri, exp); + } + } + + private void appendToTempFile(URI oclUri) { + try { + BufferedWriter o = Files.newBufferedWriter(oclTempFile, StandardOpenOption.APPEND); + o.write("import '" + oclUri + "'\n"); + o.close(); + } catch (IOException exp) { + throw new SclValidatorException(WRITE_TO_OCL_TEMP_FILES_FAILED, "Unable to write temporary OCL file", exp); + } + } + + private void logErrorMessage(URI oclUri, List errors) { + StringBuilder message = new StringBuilder("Syntax error in '" + oclUri + "':\n"); + for (Diagnostic error : errors) { + message.append("Error: ").append(error.getMessage()).append("\n"); + } + if (LOGGER.isErrorEnabled()) { + LOGGER.error(message.toString()); + } + } + + public void prepareValidator(ComposedEValidator validator) { + URI uri = URI.createFileURI(oclTempFile.toFile().getAbsolutePath()); + CompleteOCLEObjectValidator oclValidator = new CompleteOCLEObjectValidator(SclPackage.eINSTANCE, uri); + validator.addChild(oclValidator); + } + + public void cleanup() { + try { + if (!Files.deleteIfExists(oclTempFile)) { + LOGGER.warn("Unable to remove temporary file '{}'.", oclTempFile); + } + } catch (IOException exp) { + LOGGER.warn("Unable to remove temporary file '{}'.", oclTempFile, exp); + } + } +} diff --git a/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/impl/SclModelLoader.java b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/impl/SclModelLoader.java new file mode 100644 index 0000000..092050c --- /dev/null +++ b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/impl/SclModelLoader.java @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.impl; + +import fr.centralesupelec.edf.riseclipse.iec61850.scl.util.SclResourceFactoryImpl; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.resource.ResourceSet; +import org.eclipse.emf.ecore.xmi.XMLResource; +import org.eclipse.ocl.pivot.utilities.OCL; +import org.lfenergy.compas.scl.validator.exception.SclValidatorException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayInputStream; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.UUID; + +import static org.lfenergy.compas.scl.validator.exception.SclValidatorErrorCode.LOADING_SCL_FILE_ERROR_CODE; + +public class SclModelLoader { + private static final Logger LOGGER = LoggerFactory.getLogger(SclModelLoader.class); + + private final ResourceSet resourceSet; + private final HashMap options; + + public SclModelLoader(OCL ocl) { + this.resourceSet = ocl.getResourceSet(); + + // Register the appropriate resource factory to handle all file extensions. + this.resourceSet.getResourceFactoryRegistry() + .getExtensionToFactoryMap() + .put(Resource.Factory.Registry.DEFAULT_EXTENSION, new SclResourceFactoryImpl()); + + this.options = new HashMap<>(); + this.options.put(XMLResource.OPTION_DEFER_IDREF_RESOLUTION, true); + } + + public Resource load(String sclData) { + LOGGER.debug("Loading SCL Data in RiseClipse."); + try { + UUID uuid = UUID.randomUUID(); + Resource resource = resourceSet.createResource(URI.createURI(uuid.toString())); + resource.load(new ByteArrayInputStream(sclData.getBytes(StandardCharsets.UTF_8)), options); + return resource; + } catch (Exception exp) { + throw new SclValidatorException(LOADING_SCL_FILE_ERROR_CODE, "Problem loading SCL Data", exp); + } + } +} diff --git a/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/impl/SclRiseClipseValidator.java b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/impl/SclRiseClipseValidator.java new file mode 100644 index 0000000..828945d --- /dev/null +++ b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/impl/SclRiseClipseValidator.java @@ -0,0 +1,132 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.impl; + +import fr.centralesupelec.edf.riseclipse.iec61850.scl.SclPackage; +import org.eclipse.emf.common.util.BasicDiagnostic; +import org.eclipse.emf.common.util.Diagnostic; +import org.eclipse.emf.common.util.URI; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.impl.EPackageRegistryImpl; +import org.eclipse.emf.ecore.resource.Resource; +import org.eclipse.emf.ecore.util.Diagnostician; +import org.eclipse.emf.ecore.util.EObjectValidator; +import org.eclipse.ocl.pivot.utilities.OCL; +import org.eclipse.ocl.pivot.validation.ComposedEValidator; +import org.lfenergy.compas.scl.extensions.model.SclFileType; +import org.lfenergy.compas.scl.validator.SclValidator; +import org.lfenergy.compas.scl.validator.collector.OclFileCollector; +import org.lfenergy.compas.scl.validator.exception.SclValidatorException; +import org.lfenergy.compas.scl.validator.model.ValidationError; +import org.lfenergy.compas.scl.validator.util.OclFileUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; + +import static org.lfenergy.compas.scl.validator.exception.SclValidatorErrorCode.OCL_MODEL_PACKAGE_NOT_FOUND; +import static org.lfenergy.compas.scl.validator.util.MessageUtil.cleanupMessage; + +public class SclRiseClipseValidator implements SclValidator { + private static final Logger LOGGER = LoggerFactory.getLogger(SclRiseClipseValidator.class); + + private final List oclFiles = new ArrayList<>(); + private final Path tempDirectory; + + public SclRiseClipseValidator(OclFileCollector oclFileCollector, Path tempDirectory) { + this.oclFiles.addAll(oclFileCollector.getOclFiles()); + this.tempDirectory = tempDirectory; + + // Check if the SclPackage can be initialized. + var sclPck = SclPackage.eINSTANCE; + if (sclPck == null) { + throw new SclValidatorException(OCL_MODEL_PACKAGE_NOT_FOUND, "SCL package not found"); + } + } + + @Override + public List validate(SclFileType type, String sclData) { + // List with Validation Error Results if there are any. + var validationErrors = new ArrayList(); + + // Create an EPackage.Registry for the SclPackage. + var registry = new EPackageRegistryImpl(); + registry.put(SclPackage.eNS_URI, SclPackage.eINSTANCE); + // Create an OCL that creates a ResourceSet using the minimal EPackage.Registry + var ocl = OCL.newInstance(registry); + + OclFileLoader oclFileLoader = new OclFileLoader(ocl, tempDirectory); + try { + // Load all the OCL Files, adding them to the OCL Instance. + LOGGER.info("Loading OCL Files for type '{}'.", type); + oclFiles.stream() + .filter(uri -> OclFileUtil.includeOnType(uri, type)) + .forEach(oclFileLoader::addOCLDocument); + + // Create the validator and prepare it with the OCL Files. + var validator = ComposedEValidator.install(SclPackage.eINSTANCE); + oclFileLoader.prepareValidator(validator); + + // Load the SCL File as Resource ready to be processed. + LOGGER.info("Loading SCL Data for type '{}'.", type); + var sclLoader = new SclModelLoader(ocl); + var resource = sclLoader.load(sclData); + + LOGGER.info("Validating SCL Data for type '{}'.", type); + var diagnostician = new CompasDiagnostician(); + var diagnostic = diagnostician.validate(resource); + processDiagnostic(diagnostic, validationErrors); + } finally { + oclFileLoader.cleanup(); + } + + return validationErrors; + } + + private void processDiagnostic(Diagnostic diagnostic, List validationErrors) { + // If there are children in the diagnostic there are validation errors to be processed. + for (Diagnostic childDiagnostic : diagnostic.getChildren()) { + var validationError = new ValidationError(); + validationErrors.add(validationError); + + String message = cleanupMessage(childDiagnostic.getMessage()); + validationError.setMessage(message); + LOGGER.debug("SCL Validation Error '{}'", message); + + // Also process the children of the children. + processDiagnostic(childDiagnostic, validationErrors); + } + } + + /** + * Simple extension of the Diagnostician to make working with the Resource easier. + */ + private static class CompasDiagnostician extends Diagnostician { + /** + * Create a basic diagnostic instance from the resource. + * + * @param resource The Resource to be processed. + * @return The Diagnostic to which the results are added. + */ + public BasicDiagnostic createDefaultDiagnostic(Resource resource) { + return new BasicDiagnostic(EObjectValidator.DIAGNOSTIC_SOURCE, 0, "", new Object[]{resource}); + } + + /** + * Validate the passed Resource. + * + * @param resource The Resource to be validated. + * @return The Diagnostic containing the results of the validation. + */ + public Diagnostic validate(Resource resource) { + BasicDiagnostic diagnostics = createDefaultDiagnostic(resource); + for (EObject eObject : resource.getContents()) { + super.validate(eObject, diagnostics); + } + return diagnostics; + } + } +} diff --git a/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/util/MessageUtil.java b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/util/MessageUtil.java new file mode 100644 index 0000000..1206669 --- /dev/null +++ b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/util/MessageUtil.java @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.util; + +public class MessageUtil { + MessageUtil() { + throw new UnsupportedOperationException("MessageUtil class"); + } + + public static String cleanupMessage(String message) { + String cleanedMessage = message; + if (cleanedMessage != null + && cleanedMessage.toUpperCase().startsWith("ERROR:")) { + cleanedMessage = cleanedMessage.substring(6); + } + return cleanedMessage; + } +} diff --git a/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/util/OclFileUtil.java b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/util/OclFileUtil.java new file mode 100644 index 0000000..e2f56f9 --- /dev/null +++ b/riseclipse/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/util/OclFileUtil.java @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.util; + +import org.eclipse.emf.common.util.URI; +import org.lfenergy.compas.scl.extensions.model.SclFileType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import static java.io.File.separator; + +public class OclFileUtil { + private static final Logger LOGGER = LoggerFactory.getLogger(OclFileUtil.class); + + private static final String FILE_SPECIFICS_DIR_NAME = "FileSpecifics"; + private static final String COMMON_DIR_NAME = "Common"; + + OclFileUtil() { + throw new UnsupportedOperationException("OclFileUtil class"); + } + + public static boolean includeOnType(URI uri, SclFileType type) { + var fullPath = uri.path(); + // OCL Files that are not in the directory 'FileSpecifics' will always be included. + // In the directory 'FileSpecifics' only the OCL Files that are in the directory 'Common' and + // from the directory for the requested SCL File, for instance 'CID', will be included. + var include = fullPath.contains(separator + FILE_SPECIFICS_DIR_NAME + separator + type + separator) + || fullPath.contains(separator + FILE_SPECIFICS_DIR_NAME + separator + COMMON_DIR_NAME + separator) + || !fullPath.contains(separator + FILE_SPECIFICS_DIR_NAME + separator); + LOGGER.debug("Full Path '{}' will be included: {}", fullPath, include); + return include; + } +} diff --git a/riseclipse/validator-riseclipse/src/test/data/ocl/Busbar.ocl b/riseclipse/validator-riseclipse/src/test/data/ocl/Busbar.ocl new file mode 100644 index 0000000..fe27d68 --- /dev/null +++ b/riseclipse/validator-riseclipse/src/test/data/ocl/Busbar.ocl @@ -0,0 +1,42 @@ +/* + SPDX-FileCopyrightText: 2022 Alliander N.V. + + SPDX-License-Identifier: Apache-2.0 +*/ + +/* +************************************************************************* +** Copyright (c) 2016-2021 CentraleSupélec & EDF. +** All rights reserved. This program and the accompanying materials +** are made available under the terms of the Eclipse Public License v2.0 +** which accompanies this distribution, and is available at +** https://www.eclipse.org/legal/epl-v20.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: +** https://riseclipse.github.io/ +************************************************************************* +*/ + +import scl: 'http://www.iec.ch/61850/2003/SCL' + +package scl + +context Bay +-- extends EquipmentContainer + + -- The name attribute is verified in Naming.ocl + inv Busbar_nothing + : + true + + +endpackage + diff --git a/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/collector/AbstractCompasOclFileCollectorTest.java b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/collector/AbstractCompasOclFileCollectorTest.java new file mode 100644 index 0000000..1bc9b3f --- /dev/null +++ b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/collector/AbstractCompasOclFileCollectorTest.java @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.collector; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +public abstract class AbstractCompasOclFileCollectorTest { + protected void assertValidateOclFileCollector(OclFileCollector collector, int expectedFiles) { + var result = collector.getOclFiles(); + + assertNotNull(result); + assertEquals(expectedFiles, result.size()); + } +} diff --git a/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/collector/CompasOclFileCollectorTest.java b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/collector/CompasOclFileCollectorTest.java new file mode 100644 index 0000000..c90d1eb --- /dev/null +++ b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/collector/CompasOclFileCollectorTest.java @@ -0,0 +1,18 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.collector; + +import org.junit.jupiter.api.Test; + +class CompasOclFileCollectorTest extends AbstractCompasOclFileCollectorTest { + @Test + void getDefaultOclFiles_WhenCalledWithoutCustomDirectory_ThenListReturned() { + assertValidateOclFileCollector(new CompasOclFileCollector(null), 226); + } + + @Test + void getDefaultOclFiles_WhenCalledWithCustomDirectory_ThenListReturned() { + assertValidateOclFileCollector(new CompasOclFileCollector("./src/test/data/ocl"), 227); + } +} diff --git a/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/impl/OclFileLoaderTest.java b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/impl/OclFileLoaderTest.java new file mode 100644 index 0000000..597618d --- /dev/null +++ b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/impl/OclFileLoaderTest.java @@ -0,0 +1,89 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.impl; + +import org.eclipse.emf.common.util.URI; +import org.eclipse.ocl.pivot.validation.ComposedEValidator; +import org.eclipse.ocl.xtext.completeocl.validation.CompleteOCLEObjectValidator; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.lfenergy.compas.scl.validator.exception.SclValidatorException; +import org.mockito.junit.jupiter.MockitoExtension; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.lfenergy.compas.scl.validator.exception.SclValidatorErrorCode.NO_URI_PASSED; +import static org.lfenergy.compas.scl.validator.util.TestSupportUtil.createSclOcl; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class OclFileLoaderTest { + private OclFileLoader loader; + private Path tempFile; + + @BeforeEach + void setup() throws IOException { + var tempDirectory = "./target/data/temp"; + var tempDirectoryPath = Path.of(tempDirectory); + loader = new OclFileLoader(createSclOcl(), tempDirectoryPath); + tempFile = Files.walk(tempDirectoryPath) + .filter(path -> path.toString().contains(File.separator + "allConstraints")) + .findFirst() + .orElseThrow(); + } + + @Test + void addOCLDocument_WhenCalledWithNull_ThenExceptionThrown() { + var exception = assertThrows(SclValidatorException.class, + () -> loader.addOCLDocument(null)); + + assertEquals(NO_URI_PASSED, exception.getErrorCode()); + } + + @Test + void addOCLDocument_WhenCalledWithValidOcl_ThenOclFileIsAddedToTempFile() throws IOException { + var oclFile = findOCL("example.ocl"); + + loader.addOCLDocument(oclFile); + + assertEquals(1, Files.lines(tempFile).count()); + } + + @Test + void addOCLDocument_WhenCalledWithInvalidOcl_ThenOclFileIsNotAddedToTempFile() throws IOException { + var oclFile = findOCL("invalid.ocl"); + + loader.addOCLDocument(oclFile); + + assertEquals(0, Files.lines(tempFile).count()); + } + + @Test + void prepareValidator_whenCalledWithValidator_ThenValidatorIsAdded() { + var validator = mock(ComposedEValidator.class); + loader.prepareValidator(validator); + + verify(validator, times(1)).addChild(any(CompleteOCLEObjectValidator.class)); + } + + @AfterEach + void cleanup() { + loader.cleanup(); + } + + private URI findOCL(String filename) { + var url = getClass().getResource("/ocl-testfiles/" + filename); + if (url != null) { + return URI.createFileURI(url.getPath()); + } + throw new NullPointerException("File /ocl/" + filename + " not found!"); + } +} \ No newline at end of file diff --git a/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/impl/SclModelLoaderTest.java b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/impl/SclModelLoaderTest.java new file mode 100644 index 0000000..61e81e1 --- /dev/null +++ b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/impl/SclModelLoaderTest.java @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.impl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.lfenergy.compas.scl.validator.exception.SclValidatorException; + +import java.io.IOException; + +import static org.junit.jupiter.api.Assertions.*; +import static org.lfenergy.compas.scl.validator.exception.SclValidatorErrorCode.LOADING_SCL_FILE_ERROR_CODE; +import static org.lfenergy.compas.scl.validator.util.TestSupportUtil.createSclOcl; +import static org.lfenergy.compas.scl.validator.util.TestSupportUtil.readSCL; + +class SclModelLoaderTest { + private SclModelLoader loader; + + @BeforeEach + void setup() { + loader = new SclModelLoader(createSclOcl()); + } + + @Test + void load_WhenCalledWithValidSCXML_ThenResourceLoaded() throws IOException { + var sclData = readSCL("example.scd"); + + var result = loader.load(sclData); + + assertNotNull(result); + } + + @Test + void load_WhenCalledWithInvalidSCXML_ThenExceptionThrown() throws IOException { + var sclData = readSCL("invalid.scd"); + + var exception = assertThrows(SclValidatorException.class, + () -> loader.load(sclData)); + + assertEquals(LOADING_SCL_FILE_ERROR_CODE, exception.getErrorCode()); + } +} \ No newline at end of file diff --git a/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/impl/SclRiseClipseValidatorTest.java b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/impl/SclRiseClipseValidatorTest.java new file mode 100644 index 0000000..3b35e5b --- /dev/null +++ b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/impl/SclRiseClipseValidatorTest.java @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.impl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.lfenergy.compas.scl.extensions.model.SclFileType; +import org.lfenergy.compas.scl.validator.collector.CompasOclFileCollector; + +import java.io.IOException; +import java.nio.file.Path; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.lfenergy.compas.scl.validator.util.TestSupportUtil.readSCL; + +class SclRiseClipseValidatorTest { + private SclRiseClipseValidator sclValidator; + + @BeforeEach + public void setup() { + var oclFileCollector = new CompasOclFileCollector(null); + this.sclValidator = new SclRiseClipseValidator(oclFileCollector, Path.of("./target/data/temp")); + } + + @Test + void validate_WhenCalled_ThenEmptyListReturned() throws IOException { + var type = SclFileType.CID; + var sclData = readSCL("example.scd"); + + var result = sclValidator.validate(type, sclData); + + assertNotNull(result); + assertEquals(15, result.size()); + } +} diff --git a/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/util/MessageUtilTest.java b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/util/MessageUtilTest.java new file mode 100644 index 0000000..d39b0cc --- /dev/null +++ b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/util/MessageUtilTest.java @@ -0,0 +1,41 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.util; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; +import static org.lfenergy.compas.scl.validator.util.MessageUtil.cleanupMessage; + +class MessageUtilTest { + @Test + void constructor_WhenConstructorCalled_ThenShouldThrowExceptionCauseForbidden() { + assertThrows(UnsupportedOperationException.class, MessageUtil::new); + } + + @Test + void cleanupMessage_WhenCalledWithNullMessage_ThenNullIsReturned() { + var result = cleanupMessage(null); + + assertNull(result); + } + + @Test + void cleanupMessage_WhenCalledWithAlreadyCleanMessage_ThenSameMessageIsReturned() { + var expectedMessage = "Some validation message"; + + var result = cleanupMessage(expectedMessage); + + assertEquals(expectedMessage, result); + } + + @Test + void cleanupMessage_WhenCalledWithMessageThatStartWithError_ThenCleanedMessageIsReturned() { + var expectedMessage = "Some validation message"; + + var result = cleanupMessage("ERROR:" + expectedMessage); + + assertEquals(expectedMessage, result); + } +} diff --git a/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/util/OclFileUtilTest.java b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/util/OclFileUtilTest.java new file mode 100644 index 0000000..b883c54 --- /dev/null +++ b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/util/OclFileUtilTest.java @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.util; + +import org.eclipse.emf.common.util.URI; +import org.junit.jupiter.api.Test; +import org.lfenergy.compas.scl.extensions.model.SclFileType; +import org.lfenergy.compas.scl.validator.collector.CompasOclFileCollector; +import org.lfenergy.compas.scl.validator.collector.OclFileCollector; + +import static org.junit.jupiter.api.Assertions.*; + +class OclFileUtilTest { + private OclFileCollector collector = new CompasOclFileCollector(null); + + @Test + void constructor_WhenConstructorCalled_ThenShouldThrowExceptionCauseForbidden() { + assertThrows(UnsupportedOperationException.class, OclFileUtil::new); + } + + @Test + void includeOnType_WhenCalledWithExpectedSclFileTypeUri_ThenReturnTrue() { + assertTrue(executeTest("/ocl/FileSpecifics/CID/ExtRef.ocl")); + } + + @Test + void includeOnType_WhenCalledWithUnexpectedSclFileTypeUri_ThenReturnFalse() { + assertFalse(executeTest("/ocl/FileSpecifics/ICD/DOType.ocl")); + } + + @Test + void includeOnType_WhenCalledWithCommonUri_ThenReturnTrue() { + assertTrue(executeTest("/ocl/FileSpecifics/Common/ReportControl.ocl")); + } + + @Test + void includeOnType_WhenCalledWithNoFileSpecificUri_ThenReturnTrue() { + assertTrue(executeTest("/ocl/SemanticConstraints/Server.ocl")); + } + + private boolean executeTest(String oclFileName) { + var uri = getResource(oclFileName); + return OclFileUtil.includeOnType(uri, SclFileType.CID); + } + + private URI getResource(String oclFileName) { + return collector.getOclFiles() + .stream() + .filter(uri -> uri.toFileString().endsWith(oclFileName)) + .findFirst() + .orElseThrow(); + } +} diff --git a/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/util/TestSupportUtil.java b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/util/TestSupportUtil.java new file mode 100644 index 0000000..142f2a9 --- /dev/null +++ b/riseclipse/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/util/TestSupportUtil.java @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2022 Alliander N.V. +// +// SPDX-License-Identifier: Apache-2.0 +package org.lfenergy.compas.scl.validator.util; + +import fr.centralesupelec.edf.riseclipse.iec61850.scl.SclPackage; +import org.eclipse.emf.ecore.impl.EPackageRegistryImpl; +import org.eclipse.ocl.pivot.utilities.OCL; + +import java.io.IOException; + +public final class TestSupportUtil { + TestSupportUtil() { + throw new UnsupportedOperationException("FileTestUtil class"); + } + + public static String readSCL(String filename) throws IOException { + var inputStream = TestSupportUtil.class.getResourceAsStream("/scl/" + filename); + assert inputStream != null; + + return new String(inputStream.readAllBytes()); + } + + public static OCL createSclOcl() { + // Create an EPackage.Registry for the SclPackage. + var registry = new EPackageRegistryImpl(); + registry.put(SclPackage.eNS_URI, SclPackage.eINSTANCE); + // Create an OCL that creates a ResourceSet using the minimal EPackage.Registry + return OCL.newInstance(registry); + } +} diff --git a/riseclipse/validator-riseclipse/src/test/resources/ocl-testfiles/example.ocl b/riseclipse/validator-riseclipse/src/test/resources/ocl-testfiles/example.ocl new file mode 100644 index 0000000..fe27d68 --- /dev/null +++ b/riseclipse/validator-riseclipse/src/test/resources/ocl-testfiles/example.ocl @@ -0,0 +1,42 @@ +/* + SPDX-FileCopyrightText: 2022 Alliander N.V. + + SPDX-License-Identifier: Apache-2.0 +*/ + +/* +************************************************************************* +** Copyright (c) 2016-2021 CentraleSupélec & EDF. +** All rights reserved. This program and the accompanying materials +** are made available under the terms of the Eclipse Public License v2.0 +** which accompanies this distribution, and is available at +** https://www.eclipse.org/legal/epl-v20.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: +** https://riseclipse.github.io/ +************************************************************************* +*/ + +import scl: 'http://www.iec.ch/61850/2003/SCL' + +package scl + +context Bay +-- extends EquipmentContainer + + -- The name attribute is verified in Naming.ocl + inv Busbar_nothing + : + true + + +endpackage + diff --git a/riseclipse/validator-riseclipse/src/test/resources/ocl-testfiles/invalid.ocl b/riseclipse/validator-riseclipse/src/test/resources/ocl-testfiles/invalid.ocl new file mode 100644 index 0000000..33288ab --- /dev/null +++ b/riseclipse/validator-riseclipse/src/test/resources/ocl-testfiles/invalid.ocl @@ -0,0 +1,42 @@ +/* + SPDX-FileCopyrightText: 2022 Alliander N.V. + + SPDX-License-Identifier: Apache-2.0 +*/ + +/* +************************************************************************* +** Copyright (c) 2016-2021 CentraleSupélec & EDF. +** All rights reserved. This program and the accompanying materials +** are made available under the terms of the Eclipse Public License v2.0 +** which accompanies this distribution, and is available at +** https://www.eclipse.org/legal/epl-v20.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: +** https://riseclipse.github.io/ +************************************************************************* +*/ + +import scl: 'http://www.iec.ch/61850/2003/SCL' + +package scl + +context Bay +-- extends EquipmentContainer + + -- The name attribute is verified in Naming.ocl + inv Busbar_nothing + : + true + + +endpackage_invalid + diff --git a/riseclipse/validator-riseclipse/src/test/resources/scl/example.scd b/riseclipse/validator-riseclipse/src/test/resources/scl/example.scd new file mode 100644 index 0000000..4dc2b38 --- /dev/null +++ b/riseclipse/validator-riseclipse/src/test/resources/scl/example.scd @@ -0,0 +1,98 @@ + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + IEC 61850-7-3:2007B + + + + + + + + + + + + + + + + + + + IEC 61850-8-1:2003 + + + + + IEC 61850-8-1:2003 + + + + + IEC 61850-8-1:2003 + + + Completed + Cancelled + New adjustments + AnotherValue + + + Va + Vb + Vc + Aa + Ab + Ac + Vab + Vbc + Vca + AnotherValue + + + \ No newline at end of file diff --git a/riseclipse/validator-riseclipse/src/test/resources/scl/invalid.scd b/riseclipse/validator-riseclipse/src/test/resources/scl/invalid.scd new file mode 100644 index 0000000..61fba55 --- /dev/null +++ b/riseclipse/validator-riseclipse/src/test/resources/scl/invalid.scd @@ -0,0 +1,11 @@ + + + + + + +
+ + \ No newline at end of file diff --git a/validator-riseclipse/pom.xml b/validator-riseclipse/pom.xml deleted file mode 100644 index e9a91ae..0000000 --- a/validator-riseclipse/pom.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - 4.0.0 - - org.lfenergy.compas.scl.validator - compas-scl-validator - local-SNAPSHOT - - - validator-riseclipse - jar - - - - org.lfenergy.compas.scl.validator - validator - - - - - org.mockito - mockito-junit-jupiter - test - - - org.junit.jupiter - junit-jupiter-engine - test - - - org.slf4j - slf4j-simple - test - - - - - - - org.jboss.jandex - jandex-maven-plugin - - - - diff --git a/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/impl/SclRiseclipseValidator.java b/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/impl/SclRiseclipseValidator.java deleted file mode 100644 index 7b2d10b..0000000 --- a/validator-riseclipse/src/main/java/org/lfenergy/compas/scl/validator/impl/SclRiseclipseValidator.java +++ /dev/null @@ -1,20 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Alliander N.V. -// -// SPDX-License-Identifier: Apache-2.0 -package org.lfenergy.compas.scl.validator.impl; - -import org.lfenergy.compas.scl.extensions.model.SclFileType; -import org.lfenergy.compas.scl.validator.SclValidator; -import org.lfenergy.compas.scl.validator.model.ValidationError; - -import javax.enterprise.context.ApplicationScoped; -import java.util.Collections; -import java.util.List; - -@ApplicationScoped -public class SclRiseclipseValidator implements SclValidator { - @Override - public List validate(SclFileType type, String sclData) { - return Collections.emptyList(); - } -} diff --git a/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/impl/SclRiseclipseValidatorTest.java b/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/impl/SclRiseclipseValidatorTest.java deleted file mode 100644 index 674ed68..0000000 --- a/validator-riseclipse/src/test/java/org/lfenergy/compas/scl/validator/impl/SclRiseclipseValidatorTest.java +++ /dev/null @@ -1,28 +0,0 @@ -// SPDX-FileCopyrightText: 2022 Alliander N.V. -// -// SPDX-License-Identifier: Apache-2.0 -package org.lfenergy.compas.scl.validator.impl; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.lfenergy.compas.scl.extensions.model.SclFileType; -import org.mockito.junit.jupiter.MockitoExtension; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -@ExtendWith(MockitoExtension.class) -class SclRiseclipseValidatorTest { - private SclRiseclipseValidator sclValidator = new SclRiseclipseValidator(); - - @Test - void validate_WhenCalled_ThenEmptyListReturned() { - var type = SclFileType.CID; - var sclData = "Some String"; - - var result = sclValidator.validate(type, sclData); - - assertNotNull(result); - assertEquals(0, result.size()); - } -} \ No newline at end of file diff --git a/validator/pom.xml b/validator/pom.xml index ad222e3..157a8c7 100644 --- a/validator/pom.xml +++ b/validator/pom.xml @@ -27,11 +27,6 @@ SPDX-License-Identifier: Apache-2.0 scl-extension - - jakarta.enterprise - jakarta.enterprise.cdi-api - - org.eclipse.microprofile.openapi microprofile-openapi-api diff --git a/validator/src/main/java/org/lfenergy/compas/scl/validator/exception/SclValidatorErrorCode.java b/validator/src/main/java/org/lfenergy/compas/scl/validator/exception/SclValidatorErrorCode.java index c7b0532..249706b 100644 --- a/validator/src/main/java/org/lfenergy/compas/scl/validator/exception/SclValidatorErrorCode.java +++ b/validator/src/main/java/org/lfenergy/compas/scl/validator/exception/SclValidatorErrorCode.java @@ -9,4 +9,14 @@ public class SclValidatorErrorCode { } public static final String NO_SCL_ELEMENT_FOUND_ERROR_CODE = "SVS-0001"; + public static final String LOADING_SCL_FILE_ERROR_CODE = "SVS-0002"; + + public static final String LOADING_OCL_FILES_FAILED = "SVS-1001"; + public static final String LOADING_CUSTOM_OCL_FILES_FAILED = "SVS-1002"; + + public static final String CREATE_OCL_TEMP_FILES_FAILED = "SVS-2001"; + public static final String CREATE_OCL_TEMP_DIR_FAILED = "SVS-2002"; + public static final String WRITE_TO_OCL_TEMP_FILES_FAILED = "SVS-2003"; + public static final String OCL_MODEL_PACKAGE_NOT_FOUND = "SVS-2005"; + public static final String NO_URI_PASSED = "SVS-2006"; } diff --git a/validator/src/main/java/org/lfenergy/compas/scl/validator/exception/SclValidatorException.java b/validator/src/main/java/org/lfenergy/compas/scl/validator/exception/SclValidatorException.java index 51c9a26..49a31d8 100644 --- a/validator/src/main/java/org/lfenergy/compas/scl/validator/exception/SclValidatorException.java +++ b/validator/src/main/java/org/lfenergy/compas/scl/validator/exception/SclValidatorException.java @@ -9,4 +9,8 @@ public class SclValidatorException extends CompasException { public SclValidatorException(String errorCode, String message) { super(errorCode, message); } + + public SclValidatorException(String errorCode, String msg, Throwable throwable) { + super(errorCode, msg, throwable); + } } diff --git a/validator/src/main/java/org/lfenergy/compas/scl/validator/model/ValidationError.java b/validator/src/main/java/org/lfenergy/compas/scl/validator/model/ValidationError.java index e42a449..c7aac63 100644 --- a/validator/src/main/java/org/lfenergy/compas/scl/validator/model/ValidationError.java +++ b/validator/src/main/java/org/lfenergy/compas/scl/validator/model/ValidationError.java @@ -3,17 +3,23 @@ // SPDX-License-Identifier: Apache-2.0 package org.lfenergy.compas.scl.validator.model; -public class ValidationError { - private String code; - private String message; +import org.eclipse.microprofile.openapi.annotations.media.Schema; - public String getCode() { - return code; - } +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlElement; - public void setCode(String code) { - this.code = code; - } +import static org.lfenergy.compas.scl.validator.SclValidatorConstants.SCL_VALIDATOR_SERVICE_V1_NS_URI; + +@Schema(description = "Single validation error containing the message.") +@XmlAccessorType(XmlAccessType.FIELD) +public class ValidationError { + @Schema(description = "The message of the validation error that occurred.", + example = "ERROR:[SemanticConstraints] Terminal (name=T1) (line 27) does not refer an existing ConnectivityNode") + @XmlElement(name = "Message", + namespace = SCL_VALIDATOR_SERVICE_V1_NS_URI, + required = true) + private String message; public String getMessage() { return message; diff --git a/validator/src/test/java/org/lfenergy/compas/scl/validator/exception/SclValidatorExceptionTest.java b/validator/src/test/java/org/lfenergy/compas/scl/validator/exception/SclValidatorExceptionTest.java index 79bf10a..6ebbbd1 100644 --- a/validator/src/test/java/org/lfenergy/compas/scl/validator/exception/SclValidatorExceptionTest.java +++ b/validator/src/test/java/org/lfenergy/compas/scl/validator/exception/SclValidatorExceptionTest.java @@ -15,4 +15,15 @@ void constructor_WhenCalledWithOnlyMessage_ThenMessageCanBeRetrieved() { Assertions.assertEquals(SclValidatorErrorCode.NO_SCL_ELEMENT_FOUND_ERROR_CODE, exception.getErrorCode()); Assertions.assertEquals(expectedMessage, exception.getMessage()); } + + @Test + void constructor_WhenCalledWithMessageAndExceptionm_ThenMessageAndExceptionCanBeRetrieved() { + var expectedMessage = "The message"; + var expectedException = new RuntimeException(); + var exception = new SclValidatorException(SclValidatorErrorCode.NO_SCL_ELEMENT_FOUND_ERROR_CODE, expectedMessage, expectedException); + + Assertions.assertEquals(SclValidatorErrorCode.NO_SCL_ELEMENT_FOUND_ERROR_CODE, exception.getErrorCode()); + Assertions.assertEquals(expectedMessage, exception.getMessage()); + Assertions.assertEquals(expectedException, exception.getCause()); + } } \ No newline at end of file