diff --git a/documentation/abstract.md b/documentation/abstract.md deleted file mode 100644 index f978db2b009a6232fee3e7779235cf11d04ac97c..0000000000000000000000000000000000000000 --- a/documentation/abstract.md +++ /dev/null @@ -1,3 +0,0 @@ -The Smart Applications REFerence ontology (SAREF) is intended to enable interoperability between solutions from different providers and among various activity sectors in the Internet of Things (IoT), thus contributing to the development of the global digital market. - -SAREF shall use the SAREF Communication framework as defined in [[5]](#[5]) (ETSI TS 103 267: "SmartM2M; Smart Appliances; Communication Framework”). \ No newline at end of file diff --git a/documentation/acknowledgements.md b/documentation/acknowledgements.md deleted file mode 100644 index 62970096a1e1fff8c009974474a82db2f08998a7..0000000000000000000000000000000000000000 --- a/documentation/acknowledgements.md +++ /dev/null @@ -1,5 +0,0 @@ -The editors would like to thank the ETSI SmartM2M technical committee for providing guidance and expertise. - -Also, many thanks to the ETSI staff and all other current and former active Participants of the ETSI SmartM2M group for their support, technical input and suggestions that led to improvements to this ontology. - -Also, special thanks goes to the ETSI SmartM2M Technical Officer Guillemin Patrick for his help. diff --git a/documentation/creators.md b/documentation/creators.md deleted file mode 100644 index c2a4a679b9a8421f230be40c499f8c265bceea14..0000000000000000000000000000000000000000 --- a/documentation/creators.md +++ /dev/null @@ -1,4 +0,0 @@ -- [Laura Daniele](https://www.linkedin.com/in/lauradaniele) ([TNO](https://tno.nl/)) -- [Raúl Garcia-Castro](http://www.garcia-castro.com/foaf.rdf#me) ([Universidad Politécnica de Madrid](http://www.oeg-upm.net/)) -- [Maxime Lefrançois](http://maxime-lefrancois.info/me#) ([MINES Saint-Étienne](https://www.mines-stetienne.fr/)) -- [Maria Poveda-Villalon](https://w3id.org/people/mpoveda/) ([Universidad Politécnica de Madrid](http://www.oeg-upm.net/)) diff --git a/documentation/description.html b/documentation/description.html deleted file mode 100644 index 1377a39c8a43ce1f482f53f01dd4145667f736c2..0000000000000000000000000000000000000000 --- a/documentation/description.html +++ /dev/null @@ -1,135 +0,0 @@ -

General Overview

- -

Figure 1 shows an overview of the main classes of SAREF and their relationships.

- -

- SAREF Overview -
Figure 1: Overview of the SAREF ontology
-
- -

Device

- -

SAREF focuses on the concept of device, which is defined as a tangible object designed to accomplish a particular task in households, common public buildings or offices. In order to accomplish this task, the device performs one or more functions. Examples of devices are a light switch, a temperature sensor, an energy meter and a washing machine. A washing machine is designed to wash (task) and to accomplish this task it performs a start and stop function. The saref:Device class and its properties are shown in Figure 2.

- -
- Device class -
Figure 2: Device class
-
- -

A saref:Device can have some properties that uniquely characterize it, namely its model and manufacturer (saref:hasModel and saref:hasManufacturer properties, respectively).

-

SAREF is conceived in a modular way in order to allow the definition of any device from pre-defined building blocks, based on the function(s) that the device performs. Therefore, a saref:Device has at least one function (saref:hasFunction min 1 saref:Function). Moreover, a saref:Device can be used for (saref:isUsedFor property) the purpose of offering a commodity, such as saref:Water or saref:Gas. It can also measure a property, such as saref:Temperature, saref:Energy and saref:Smoke. Moreover, a device may consist of other devices (saref:consistsOf property).

- -
- Types of devices -
Figure 3: Types of devices
-
- -As shown in Figure 3, types of devices that can be represented are actuators (e.g. a saref:Switch that can be further specialized in saref:LightSwitch and saref:DoorSwitch), sensors (e.g. a saref:SmokeSensor and saref:TemperatureSensor), meters, and appliances. Note that more types of devices, sensors and actuators exist which can be defined to extend SAREF (the device types in Figure 4 represent only some examples that aim at explaining the rationale behind SAREF). A description of these types of devices is presented in the next clause, in combination with the function that they perform. Examples of devices for specific domains are defined in the SAREF extensions ([i.2] to [i.7]). - -

Function

- -

A function is represented in SAREF with the saref:Function class and is defined as the functionality necessary to accomplish the task for which a device is designed. Examples of functions are saref:ActuatingFunction, saref:SensingFunction, saref:MeteringFunction and saref:EventFunction. The saref:Function class and its properties are shown in Figure 4.

- -

In particular:

- - -
- Function class -
Figure 4: Function class
-
- - -

In order to show how these functions shall be used, some examples of devices and their functions are defined as follows:

- - - - -

Command

- -

A saref:Function shall have at least one command associated to it (saref:hasCommand min 1 saref:Command). Figure 5 shows the list of commands currently available in SAREF. This list is used here for illustration purposes and can be extended with new commands.

- - -
- Command class -
Figure 5: Command class
-
- - -

For example:

- - -

Figure 5 further shows that a command can act upon a state (saref:actsUpon relation) to represent that the consequence of a command can be a change of state of a device. Note that a command may act upon a state, but does not necessarily act upon a state. For example, the saref:OnCommand acts upon the saref:OnOffState, but the saref:GetCommand does not act upon any state, since it only gives a directive to retrieve a certain value.

- - -

State

- -

Depending on the function(s) it performs, a device can be found in a corresponding saref:State, as shown in Figure 6. For example, a switch can be found in the saref:OnOffState, which is further specialized in saref:OnState and saref:OffState. A light switch can be found in the saref:OnOffState upon which the saref:OnCommand and saref:OffCommand shall act. Note that SAREF is not restricted to binary states such as the saref:OnOffState, but allows to define also n-ary states (see, for example, the saref:MultiLevelState class).

- -
- State class -
Figure 6: State class
-
- - - -

Service

- -

Figure 7 shows that a device offers a service (the saref:Service class), which is a representation of a function to a network that makes this function discoverable, registerable and remotely controllable by other devices in the network. A service shall represent at least one function (saref:represents min 1 saref:Function) and is offered by at least one device that wants (a certain set of) its function(s) to be discoverable, registerable and remotely controllable by other devices in the network (saref:isOfferedBy min 1 saref:Device). Multiple devices can offer the same service. A service shall specify the device that is offering the service and the function(s) to be represented.

-

For example, a light switch can offer the service of remotely switching the lights in a home through mobile phone devices that are connected to the local network (saref:SwitchOnService class). This "remote switching" service represents the saref:OnOffFunction previously described.

-

Note that the concept of service is further elaborated in the oneM2M Base Ontology [4], to which the reader is referred in order to model the details of a service that are out of the scope of SAREF.

- -
- Service class -
Figure 7: Service class
-
- - -

Profile

- -

A device in SAREF can be further characterized by a profile. Figure 8 shows the saref:Profile class and its properties. A profile is a specification associated to a device to collect information about a certain property or commodity (e.g. energy or water) for optimizing its usage in the home/building in which the device is located. Therefore, a profile is linked to a certain property or commodity (using the saref:isAbout property), can be calculated over a time span (using the saref:hasTime property) and can be associated to some costs (using the saref:hasPrice property). A specialization of a profile is the Power Profile defined in the SAREF4ENER extension in ETSI TS 103 410-1 [i.2] (this power profile can be associated to a device for optimizing the energy efficiency in the home/building in which the device is located).

- -
- Profile class -
Figure 8: Profile class
-
- - -

Measurement, Property, and Unit of Measure

- -

The classes saref:Measurement, saref:Property and saref:UnitOfMeasure allow to relate different measurements from a given device for different properties measured in different units, i.e. the saref:Measurement class describes a measurement of a physical quantity (using the saref:hasValue property) for a given saref:Property and according to a given saref:UnitOfMeasure. In this way, it is possible to differentiate between properties and the measurements made for such properties, and to store measurements for a concrete property in different units of measurement. Furthermore, a timestamp can be added (using the saref:hasTimestamp property) to identify when the measurement applies to the property, which can be used either for single measurements or for series of measurements (e.g. measurement streams). Figure 9 shows that a saref:Device can measure or control a saref:Property (which may be from a saref:FeatureOfInterest), which in turn relates to a saref:Measurement, which in turn is measured in a given saref:UnitOfMeasure. Note that it is possible to follow also the inverse direction in which a saref:Device makes a measurement in a certain unit of measure (using the saref:makesMeasurement property), and this measurement can be related to a saref:Property (using the saref:relatesToProperty property). A saref:FeatureOfInterest represents any real world entity from which a saref:Property is measured.

- -

As an example, the saref:Power and saref:Energy classes can be related to a certain measurement value (using the saref:hasValue property), which is measured in a certain unit of measure i.e. Kilowatt for power (saref:PowerUnit) and Kilowatt_Hour for energy (saref:EnergyUnit). Analogously, the saref:Price class can be related to a certain measurement value that is measured using a certain saref:Currency, which is a subclass of the saref:UnitOfMeasure class. Further examples on how to define units of measure can be found in the different SAREF extensions ([i.2] to [i.7]).

- -

The saref:Time class allows to specify the "time" concept in terms of temporal entities (i.e. instants or intervals) according to the existing W3C® Time ontology to avoid defining this concept from scratch.

- - - -
- Measurement class -
Figure 9: Measurement class
-
diff --git a/documentation/diagrams/saref4auto-v1.1.1-AVP1.png b/documentation/diagrams/saref4auto-v1.1.1-AVP1.png deleted file mode 100644 index 0e4f93e751479d170e47157c406bc9f4c5859287..0000000000000000000000000000000000000000 Binary files a/documentation/diagrams/saref4auto-v1.1.1-AVP1.png and /dev/null differ diff --git a/documentation/diagrams/saref4auto-v1.1.1-AVP2.png b/documentation/diagrams/saref4auto-v1.1.1-AVP2.png deleted file mode 100644 index 4a137c7fc2030f2f1150d4230308b5ec9b71f8f7..0000000000000000000000000000000000000000 Binary files a/documentation/diagrams/saref4auto-v1.1.1-AVP2.png and /dev/null differ diff --git a/documentation/diagrams/saref4auto-v1.1.1-AVP3.png b/documentation/diagrams/saref4auto-v1.1.1-AVP3.png deleted file mode 100644 index 52214742c968c4d2b4fa3134a0dc4a8478876e6b..0000000000000000000000000000000000000000 Binary files a/documentation/diagrams/saref4auto-v1.1.1-AVP3.png and /dev/null differ diff --git a/documentation/diagrams/saref4auto-v1.1.1-Environment1.png b/documentation/diagrams/saref4auto-v1.1.1-Environment1.png deleted file mode 100644 index e9ea5a9e8872f66b88344be53ce600f535a482bc..0000000000000000000000000000000000000000 Binary files a/documentation/diagrams/saref4auto-v1.1.1-Environment1.png and /dev/null differ diff --git a/documentation/diagrams/saref4auto-v1.1.1-Environment2.png b/documentation/diagrams/saref4auto-v1.1.1-Environment2.png deleted file mode 100644 index 5d55090738c6aea3a8def464272f51ee258cee78..0000000000000000000000000000000000000000 Binary files a/documentation/diagrams/saref4auto-v1.1.1-Environment2.png and /dev/null differ diff --git a/documentation/diagrams/saref4auto-v1.1.1-Platoon1.png b/documentation/diagrams/saref4auto-v1.1.1-Platoon1.png deleted file mode 100644 index 30c09fe092f04d655d057e3e2c60b3a939e9d8b4..0000000000000000000000000000000000000000 Binary files a/documentation/diagrams/saref4auto-v1.1.1-Platoon1.png and /dev/null differ diff --git a/documentation/diagrams/saref4auto-v1.1.1-Platoon2.png b/documentation/diagrams/saref4auto-v1.1.1-Platoon2.png deleted file mode 100644 index e6a73f5e16b01f054fe9bd72cb113db2a216caaa..0000000000000000000000000000000000000000 Binary files a/documentation/diagrams/saref4auto-v1.1.1-Platoon2.png and /dev/null differ diff --git a/documentation/diagrams/saref4auto-v1.1.1-TrafficCongestionDetection.drawio b/documentation/diagrams/saref4auto-v1.1.1-TrafficCongestionDetection.drawio deleted file mode 100644 index ee62af858d4b8a520cde43a188738786858e49e2..0000000000000000000000000000000000000000 --- a/documentation/diagrams/saref4auto-v1.1.1-TrafficCongestionDetection.drawio +++ /dev/null @@ -1,933 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/documentation/diagrams/saref4auto-v1.1.1-TrafficCongestionDetection.png b/documentation/diagrams/saref4auto-v1.1.1-TrafficCongestionDetection.png deleted file mode 100644 index c2be6c368ca96c56a7bd3554c680b873c9d65d4b..0000000000000000000000000000000000000000 Binary files a/documentation/diagrams/saref4auto-v1.1.1-TrafficCongestionDetection.png and /dev/null differ diff --git a/documentation/diagrams/saref4auto-v1.1.1-figures.drawio b/documentation/diagrams/saref4auto-v1.1.1-figures.drawio deleted file mode 100644 index 3e700beba556de9758ea88ba70bedba9e24bd5d2..0000000000000000000000000000000000000000 --- a/documentation/diagrams/saref4auto-v1.1.1-figures.drawio +++ /dev/null @@ -1 +0,0 @@ -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 \ No newline at end of file diff --git a/documentation/references.html b/documentation/references.html deleted file mode 100644 index da8ec011c81eb81cf0ea7c38d6b99ec65a936523..0000000000000000000000000000000000000000 --- a/documentation/references.html +++ /dev/null @@ -1,24 +0,0 @@ -

Normative references

- - - -

Informative references

- - diff --git a/requirements/requirements.csv b/requirements/requirements.csv deleted file mode 100644 index 16132a1c3424b387c1d8f3e74c0169c9e4690385..0000000000000000000000000000000000000000 --- a/requirements/requirements.csv +++ /dev/null @@ -1,56 +0,0 @@ -Id;Category;Requirement -WATR-1;Water infrastructure;Which assets compose a water distribution infrastructure? Catchment well, raw water pipe, reservoirs, etc. -WATR-2;Water infrastructure;A catchment well is a well that has been constructed to collect water. -WATR-3;Water infrastructure;A wastewater treatment plant is a facility where contaminants are removed from wastewater or sewage. -WATR-4;Water infrastructure;Which types of sensors are used in water infrastructures? Water quality sensors, capacity sensors, tank level sensors, etc. -WATR-5;Water infrastructure;Which types of actuators are used in water infrastructures? Pressure regulators, pumps, valves, etc. -WATR-6;Water meter;A water meter is a device that measures different aspects of a water infrastructure. -WATR-7;Water meter;What is the type of the water meter? It is a cold-water meter. -WATR-8;Water meter;What is the fabrication number of the water meter? 4837QW. -WATR-9;Water meter;What are the manufacturer and the model of the water meter? It is a Meterall, model Turion. -WATR-10;Water meter;What is the version of the water meter? Version 1.2. -WATR-11;Water meter;What is the hardware version number of the water meter? 23.5b. -WATR-12;Water meter;What firmware version is the water meter using? The metrology (firmware) version is 123.7. -WATR-13;Water meter;What has been the on time for the water meter? 15 days. -WATR-14;Water meter;What is the operating time of the water meter? 5 hours. -WATR-15;Water meter;What is the operating time of the water meter's battery? 4 months and 4 days. -WATR-16;Water meter;When was the battery of the water meter previously changed? On February 23rd 2019, at 13:45. -WATR-17;Water meter;What is the remaining battery time of the water meter? 27 months. -WATR-18;Water meter;What is the power of the water meter? 24 volts. -WATR-19;Water meter;What is the radio frequency level of the water meter? 2.4 GHz. -WATR-20;Water meter;What is the geolocation of the water meter? Latitude 40.4165 and longitude -3.7025. -WATR-21;Meter measurements;What is the volume being measured by water meter 243? 127 liters. -WATR-22;Meter measurements;Which was the flow of water meter 44 on January 15th 2019 at 12:30? 32 liters per hour. -WATR-23;Meter measurements;How many water meters are measuring an external temperature greater than 23ºC? 5 meters. -WATR-24;Meter measurements;The maximum temperature limit of the water meter is of 49ºC. -WATR-25;Meter measurements;Water meters can provide measurements according to different temporal settings: current values, periodical values, set date values, billing date values, minimum values, and maximum values. -WATR-26;Meter measurements;Measurements can be related to a specific date and/or time, to some duration, or to a temporal interval. -WATR-27;Infrastructure measurements;What is the current level of the reservoir? 200 liters. -WATR-28;Infrastructure measurements;What are the inflow/outflow rates of the water reservoir? 500 liters. -WATR-29;Infrastructure measurements;What is the current water flow in water pipe 212? 250 liters per second. -WATR-30;Infrastructure measurements;What is the current water leak rate in water pipe 212? 0.4 liters per second. -WATR-31;Infrastructure measurements;Which systems had the water pressure lower than 100 on August 15th? Pump 123 and pump 145. -WATR-32;Infrastructure measurements;What is the maximum discharge flow of water pump 8? 500 liters per minute. -WATR-33;Water measurements;What are the physical properties of water? Temperature, conductance, turbidity, etc. -WATR-34;Water measurements;What are the chemical properties of water? pH, total hardness, concentration of different chemical components, etc. -WATR-35;Indicators;Is the minimum pressure level maintained everywhere the water distribution infrastructure? Yes. -WATR-36;Indicators;What is the capacity of wastewater treatment plants in Madrid? 12 Megaliters per day. -WATR-37;Indicators;Which water indicators are defined for Burgos? Number of connected residential properties, annual maintenance costs, volume of potable water supplied. -WATR-38;Tariff;What is the start date and time of the tariff in use in the water meter? 1st January 2019. -WATR-39;Tariff;What is the duration of the current tariff of the water meter? 1 year. -WATR-40;Tariff;What is the tariff period of the water meter? 1 month. -WATR-41;Tariff;What is the maximum contracted consumption of the water meter? 1,200 liters. -WATR-42;Tariff;What is the billing date of the water meter? 31st March 2019. -WATR-43;Tariff;What is the billing date period of the water meter? 1 month. -WATR-44;ICT4Water Cluster;There are four main types of water assets: source, sink, transport and storage ones. -WATR-45;ICT4Water Cluster;Examples of source assets are: lakes, lagoons or glaciers. -WATR-46;ICT4Water Cluster;Examples of sink assets are: rivers, seas, oceans or estuaries. -WATR-47;ICT4Water Cluster;An aquifer is a type of storage asset. -WATR-48;ICT4Water Cluster;An intake is a type of transport asset. -WATR-49;ICT4Water Cluster;A hydroelectric power plant is a type of water infrastructure. -WATR-50;ICT4Water Cluster;A gauging station is a type of water monitoring infrastructure. -WATR-51;ICT4Water Cluster;A water infrastructure is intended for a particular use of water, for example: industry, agriculture, recreation or aquaculture. -WATR-52;ICT4Water Cluster;Total dissolved solids is an acceptability property of water. -WATR-53;ICT4Water Cluster;Dissolved oxygen is a chemical property of water. -WATR-54;ICT4Water Cluster;Some environmental properties are relevant for water, such as external humidity, atmospheric pressure, amount of precipitation. -WATR-55;ICT4Water Cluster;A device can monitor a water asset. diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_10_1_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_10_1_Checker.java index 150207b38df0c19ed121fa2bcffdec10fbe71128..0645e4cbca4f704b8a27d719bc9c3d324e5baa8c 100644 --- a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_10_1_Checker.java +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_10_1_Checker.java @@ -27,11 +27,8 @@ package fr.mines_stetienne.ci.saref.checkers; import java.io.File; import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.List; import fr.mines_stetienne.ci.saref.SAREFPipelineException; import fr.mines_stetienne.ci.saref.managers.RepositoryManager; -import org.apache.commons.io.FileUtils; /** * Checks TS 103 673 Clause 10.1: Reference ontology pattern documentation and specification. @@ -60,16 +57,16 @@ public class Clause_10_1_Checker extends AbstractClauseChecker { } } try { - File file = new File(dir, "vocabulary.ttl"); + File file = new File(dir, "pattern.ttl"); if (!file.exists()) { logError(getMessage(Clause_10_1_Checker.MESSAGE.missing)); return; } - List lines = FileUtils.readLines(file, StandardCharsets.UTF_8); + /*List lines = FileUtils.readLines(file, StandardCharsets.UTF_8); if (lines.isEmpty() || !lines.get(0).equals(FIRST_LINE)) { - logError(getMessage(Clause_10_1_Checker.MESSAGE.line)); - } - } catch (IOException ex) { + logError(getMessage(Clause_10_1_Checker.MESSAGE.line));//<<< + }*/ + } catch (Exception ex) { logError(getMessage(Clause_10_1_Checker.MESSAGE.ioexception), ex); } // These are optional files so do NOT verify the html text within the file!!! diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_10_2_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_10_2_Checker.java index b253228ce097afcceaa757bfed3e3243ace7b668..2dc9026860ece85af5a50aec85d4df4a2e30f45b 100644 --- a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_10_2_Checker.java +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_10_2_Checker.java @@ -38,7 +38,7 @@ import fr.mines_stetienne.ci.saref.managers.RepositoryManager; public class Clause_10_2_Checker extends AbstractClauseChecker { private enum MESSAGE { - ioexception, one + ioexception, missing, one } public Clause_10_2_Checker(RepositoryManager repositoryManager) { @@ -52,7 +52,7 @@ public class Clause_10_2_Checker extends AbstractClauseChecker { if (!dir.isDirectory()) { if (dir.list().length < 1) { log(getMessage(MESSAGE.one)); - //<<< logWarning(getMessage(Clause_10_2_Checker.MESSAGE.missing)); + logWarning(getMessage(Clause_10_2_Checker.MESSAGE.missing)); } try { String[] lines = {}; // create empty file. diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_4_3_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_4_3_Checker.java index 30d128aa6baef29e4dfef65bd01f0dee930c4c99..970ff564dcc1abf982ecb4df820ca87081273fd9 100644 --- a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_4_3_Checker.java +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_4_3_Checker.java @@ -60,7 +60,7 @@ public class Clause_9_4_3_Checker extends AbstractClauseChecker { } onto++; } - if (onto != 1 || found == false) { + if (onto != 1 || found == false) { // But each extension has @prefix :, @prefix s4auto:, & @base all with the same URL. String msg = getMessage(MESSAGE.ontology_declaration, repository.getNamespace()); logError(msg); return; diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_4_4_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_4_4_Checker.java index ddd10ab4e6ea3f954e306c877ebdbe068268c4dc..9da58dad5bfc6b1619466123b9ddf88f1bf9521f 100644 --- a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_4_4_Checker.java +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_4_4_Checker.java @@ -41,7 +41,7 @@ public class Clause_9_4_4_Checker extends AbstractClauseChecker { @Override public void checkClause() throws SAREFPipelineException { new Clause_9_4_4_1_Checker(repositoryManager).check(); - new Clause_9_4_4_2_Checker(repositoryManager).check(); + //new Clause_9_4_4_2_Checker(repositoryManager).check(); this uses AbstractShaclChecker } } diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_5_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_5_Checker.java index d103e216a55cfe1c47814d8fe9c45860b35affc1..10dce3cd7b9a3c4104866cebc84e3c2d18ec16b3 100644 --- a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_5_Checker.java +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_5_Checker.java @@ -77,8 +77,7 @@ public class Clause_9_5_Checker extends AbstractClauseChecker { } /** - * @param errorLogger - * @param config + * @param repositoryManager */ public Clause_9_5_Checker(RepositoryManager repositoryManager) { super(repositoryManager, Clause_9_5_Checker.class); @@ -131,7 +130,7 @@ public class Clause_9_5_Checker extends AbstractClauseChecker { csvReader.forEach(row -> { String id = row[0]; // WATR-TEST-17 Resource testResource = requirements.getResource(String.format("%stests#%s", version.getIRI(), id)); - String requirementId = row[1]; // WATR-9 + /*<<< String requirementId = row[1]; Resource requirementResource = requirements .getResource(String.format("%srequirements#", version.getIRI(), requirementId)); String category = row[2]; // Water meter @@ -139,7 +138,7 @@ public class Clause_9_5_Checker extends AbstractClauseChecker { requirements.add(testResource, RDF.type, VTC.TestCaseDesign); requirements.add(testResource, VTC.testId, id); requirements.add(testResource, VTC.comesFromRequirement, requirementResource); - requirements.add(testResource, VTC.desiredBehaviour, test); + requirements.add(testResource, VTC.desiredBehaviour, test);*/ }); } catch (Exception e) { logWarning(getMessage(MESSAGE.ioexception), e); diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_6_3_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_6_3_Checker.java index 74df69fce4ef4b149d6d001edebb8ed64b87326a..928a27604c87febee4a32642892f4a08615c884f 100644 --- a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_6_3_Checker.java +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_6_3_Checker.java @@ -61,8 +61,8 @@ public class Clause_9_6_3_Checker extends AbstractShaclChecker { @Override protected Model getModel() { Model model = example.getModel(); - final String regex = "^" + example.getIRI().replace("v0.0.1", SAREF.REGEX_VERSION_NUMBER) + "$"; - + final String defaultVersion = "v0.0.1"; + final String regex = "^" + example.getIRI().replace(defaultVersion, SAREF.REGEX_VERSION_NUMBER) + "$"; int onto = 0; boolean found = false; for (ResIterator it = model.listSubjectsWithProperty(RDF.type, DCTypes.Dataset); it.hasNext();) { diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_1_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_1_Checker.java new file mode 100644 index 0000000000000000000000000000000000000000..013437b00c412476e7f10ea96d8c5e409b4130f9 --- /dev/null +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_1_Checker.java @@ -0,0 +1,82 @@ +/* + * Copyright 2020 ETSI + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package fr.mines_stetienne.ci.saref.checkers; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.stream.Collectors; + +import fr.mines_stetienne.ci.saref.SAREF; +import fr.mines_stetienne.ci.saref.SAREFPipelineException; +import fr.mines_stetienne.ci.saref.managers.RepositoryManager; + +/** + * Checks TS 103 673 Clause 9.8.1.1: The vocabularies directory. + * + */ +public class Clause_9_8_1_1_Checker extends AbstractClauseChecker { + + private enum MESSAGE { + directories, one, ttl, turtle, write_error + } + + public Clause_9_8_1_1_Checker(RepositoryManager repositoryManager) { + super(repositoryManager, Clause_9_8_1_1_Checker.class); + } + + @Override + public void checkClause() throws SAREFPipelineException { + try { + File dir = new File(repository.getDirectory(), "vocabularies"); + /*String directories = Files.walk(dir.toPath()).filter(p -> { + try { + return p.toFile().isDirectory() && !Files.isSameFile(dir.toPath(), p); + } catch(IOException ex) { + return false; + } + }).map(p -> p.toString()).collect(Collectors.joining(", ")); + if(directories.isEmpty()) { + logError(getMessage(MESSAGE.directories, directories)); + }*/ + + String nonTtl = Files.walk(dir.toPath(), 1).filter(p -> { + try { + return p.toFile().isFile() && !SAREF.TTL_MATCHER.matches(p) && !p.toFile().getName().startsWith("."); + } catch (Exception ex) { + return false; + } + }).map(p -> p.getFileName().toString()).collect(Collectors.joining(", ")); + if(nonTtl.length()>0) { + logError(getMessage(MESSAGE.ttl, nonTtl)); + } + + } catch (IOException ex) { + throw new SAREFPipelineException(ex); + } + } + +} diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_2_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_2_Checker.java new file mode 100644 index 0000000000000000000000000000000000000000..d6561d5ed2b132480a50e73334ed63c1f52250af --- /dev/null +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_2_Checker.java @@ -0,0 +1,117 @@ +/* + * Copyright 2024 ETSI + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package fr.mines_stetienne.ci.saref.checkers; + +import java.util.HashMap; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import fr.mines_stetienne.ci.saref.SAREF; +import fr.mines_stetienne.ci.saref.SAREFPipelineException; +import fr.mines_stetienne.ci.saref.entities.SAREFExtension; +import fr.mines_stetienne.ci.saref.managers.RepositoryManager; + +/** + * Checks TS 103 673 Clause 9.8.1.2: Prefixes declaration + * + */ +public class Clause_9_8_1_2_Checker extends AbstractClauseChecker { + + private final static Pattern PATTERN_PREFIX = Pattern.compile(SAREF.REGEX_EXTENSION_PREFIX); + + private static final Map PREFIXES = new HashMap(); + static { + PREFIXES.put("dc","http://purl.org/dc/elements/1.1/"); + PREFIXES.put("dcam","http://purl.org/dc/dcam/"); + PREFIXES.put("dcterms","http://purl.org/dc/terms/"); + PREFIXES.put("grddl","http://www.w3.org/2003/g/data-view#"); + PREFIXES.put("owl","http://www.w3.org/2002/07/owl#"); + PREFIXES.put("prov","http://www.w3.org/ns/prov#"); + PREFIXES.put("rdf","http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + PREFIXES.put("rdfs","http://www.w3.org/2000/01/rdf-schema#"); + PREFIXES.put("rlog","http://persistence.uni-leipzig.org/nlp2rdf/ontologies/rlog#"); + PREFIXES.put("rut","http://rdfunit.aksw.org/ns/core#"); + PREFIXES.put("sh","http://www.w3.org/ns/shacl#"); + PREFIXES.put("shr","http://rdfunit.aksw.org/ns/shacl-ext#"); + PREFIXES.put("shsh","http://www.w3.org/ns/shacl-shacl#"); + PREFIXES.put("skos","http://www.w3.org/2004/02/skos/core#"); + PREFIXES.put("spin","http://spinrdf.org/spin#"); + PREFIXES.put("vann","http://purl.org/vocab/vann/"); + PREFIXES.put("xml","http://www.w3.org/XML/1998/namespace"); + PREFIXES.put("xsd","http://www.w3.org/2001/XMLSchema#"); + /* PREFIXES.put("rdf", "http://www.w3.org/1999/02/22-rdf-syntax-ns#"); + PREFIXES.put("rdfs", "http://www.w3.org/2000/01/rdf-schema#"); + PREFIXES.put("owl", "http://www.w3.org/2002/07/owl#"); + PREFIXES.put("xsd", "http://www.w3.org/2001/XMLSchema#"); + PREFIXES.put("dcterms", "http://purl.org/dc/terms/"); + PREFIXES.put("vann", "http://purl.org/vocab/vann/"); + PREFIXES.put("voaf", "http://purl.org/vocommons/voaf#"); + PREFIXES.put("schema", "http://schema.org/"); + PREFIXES.put("geo", "http://www.opengis.net/ont/geosparql#"); + PREFIXES.put("saref", "https://saref.etsi.org/core/"); */ + } + + private static enum MESSAGE { + different, expect; + } + + public Clause_9_8_1_2_Checker(RepositoryManager repositoryManager) { + super(repositoryManager, Clause_9_8_1_2_Checker.class); + } + + @Override + public void checkClause() throws SAREFPipelineException { + final Map prefixes = version.getModel().getNsPrefixMap(); + for (String s : PREFIXES.keySet()) { + if (prefixes.containsKey(s)) { + if (!prefixes.get(s).equals(PREFIXES.get(s))) { + logError(getMessage(MESSAGE.different, s, PREFIXES.get(s), prefixes.get(s))); + } + } + } + boolean found = false; + for (String s : prefixes.keySet()) { + Matcher m = PATTERN_PREFIX.matcher(s); + if (m.matches()) { + String acronym = m.group(SAREF.REGEX_ACRONYM_VAR); + String expected = new SAREFExtension(acronym).getNamespace(); + if(!prefixes.get(s).equals(expected)) { + logError(getMessage(MESSAGE.different, s, expected, prefixes.get(s))); + } + } + if (s.equals(repository.getPrefix())) { + found = true; + } + } + if (!found) { + String namespace = repository.getNamespace(); + String prefix = repository.getPrefix(); + logError(getMessage(MESSAGE.expect, namespace, prefix)); + } + // how to check MESSAGE.BASE ? + } +} diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_3_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_3_Checker.java new file mode 100644 index 0000000000000000000000000000000000000000..4a3bb81001a0526baeab5ba72b2ac105db21332a --- /dev/null +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_3_Checker.java @@ -0,0 +1,82 @@ +/* + * Copyright 2024 ETSI + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package fr.mines_stetienne.ci.saref.checkers; + +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.ResIterator; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.vocabulary.OWL2; +import org.apache.jena.vocabulary.RDF; + +import fr.mines_stetienne.ci.saref.SAREFPipelineException; +import fr.mines_stetienne.ci.saref.managers.RepositoryManager; + +/** + * Checks TS 103 673 Clause 9.8.3: The ontology declaration + * + */ +public class Clause_9_8_1_3_Checker extends AbstractClauseChecker { + + private enum MESSAGE { + ontology_declaration + } + + public Clause_9_8_1_3_Checker(RepositoryManager repositoryManager) { + super(repositoryManager, Clause_9_8_1_3_Checker.class); + } + + @Override + public void checkClause() throws SAREFPipelineException { + Model model = version.getModel(); + int onto = 0; + boolean found = false; + for (ResIterator it = model.listSubjectsWithProperty(RDF.type, OWL2.Ontology); it.hasNext();) { + Resource r = it.next(); + if(r.getURI().equals( repository.getNamespace() )) { + found = true; + } + onto++; + } + if (onto != 1 || !found) { + String msg = getMessage(MESSAGE.ontology_declaration, repository.getNamespace()); + logError(msg); + } +// config.add(version.getRepository().getProject().getResource(), EX.hasVersion, version.getVersionResource()); +// config.add(version.getVersionResource(), RDF.type, EX.OntologyVersion); +// config.add(version.getVersionResource(), EX.repositoryName, version.getRepository().getProject().getName()); +// config.add(version.getVersionResource(), EX.versionInfo, version.getVersionName().toString()); +// SAREFVersionName priorVersionName = getPriorVersion(version); +// if (priorVersionName != null) { +// Resource priorVersionResource = ResourceFactory.createResource(version.getRepository().getVersionIRI(priorVersionName)); +// config.add(version.getVersionResource(), EX.priorVersion, priorVersionResource); +// } + + //new Clause_9_8_1_3_1_Checker(repositoryManager).check(); + //new Clause_9_8_1_3_2_Checker(repositoryManager).check(); + //new Clause_9_8_1_3_1_3_Checker(repositoryManager).check(); + } + +} diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_4_1_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_4_1_Checker.java new file mode 100644 index 0000000000000000000000000000000000000000..5830566c6263ce94a53ec1a2503405e4c39d0bb6 --- /dev/null +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_4_1_Checker.java @@ -0,0 +1,111 @@ +/* + * Copyright 2024 ETSI + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package fr.mines_stetienne.ci.saref.checkers; + +import java.util.HashSet; +import java.util.Set; +import java.util.regex.Pattern; +import java.util.stream.Collectors; + +import org.apache.jena.rdf.model.Model; +import org.apache.jena.rdf.model.Resource; +import org.apache.jena.vocabulary.OWL2; +import org.apache.jena.vocabulary.RDF; + +import fr.mines_stetienne.ci.saref.SAREFPipelineException; +import fr.mines_stetienne.ci.saref.entities.SAREFTerm; +import fr.mines_stetienne.ci.saref.managers.RepositoryManager; + +/** + * Checks TS 103 673 Clause 9.8.1.4.1: Term IRI + * + */ +public class Clause_9_8_1_4_1_Checker extends AbstractClauseChecker { + + private static final Pattern PATTERN_LOCAL_NAME = Pattern.compile("^[a-zA-Z0-9][a-zA-Z0-9]+$"); + private static final Pattern PATTERN_CAMEL_CASE = Pattern.compile("^[A-Z0-9][a-zA-Z0-9]+$"); + private static final Pattern PATTERN_MIXED_CASE = Pattern.compile("^[a-z0-9][a-zA-Z0-9]+$"); + + private static enum MESSAGE { + pattern, classs, namedindividual, objectproperty, datatypeproperty + } + + public Clause_9_8_1_4_1_Checker(RepositoryManager repositoryManager) { + super(repositoryManager, Clause_9_8_1_4_1_Checker.class); + } + + private final Set termsBadPattern = new HashSet<>(); + private final Set classesBadCase = new HashSet<>(); + private final Set namedIndividualsBadCase = new HashSet<>(); + private final Set objectPropertiesBadCase = new HashSet<>(); + private final Set datatypePropertiesBadCase = new HashSet<>(); + + + @Override + public void checkClause() throws SAREFPipelineException { + + Model model = version.getModel(); + for (SAREFTerm term : version.getDefinedTerms()) { + String localName = term.getLocalName(); + Resource t = term.getResource(); + + if (!PATTERN_LOCAL_NAME.matcher(localName).matches()) { + termsBadPattern.add(t); + } + if (model.contains(t, RDF.type, OWL2.Class) && !PATTERN_CAMEL_CASE.matcher(localName).matches()) { + classesBadCase.add(t); + } + if (model.contains(t, RDF.type, OWL2.NamedIndividual) && !PATTERN_CAMEL_CASE.matcher(localName).matches()) { + namedIndividualsBadCase.add(t); + } + if (model.contains(t, RDF.type, OWL2.ObjectProperty) && !PATTERN_MIXED_CASE.matcher(localName).matches()) { + objectPropertiesBadCase.add(t); + } + if (model.contains(t, RDF.type, OWL2.DatatypeProperty) + && !PATTERN_MIXED_CASE.matcher(localName).matches()) { + datatypePropertiesBadCase.add(t); + } + } + + if (!classesBadCase.isEmpty()) { + logError(getMessage(MESSAGE.classs, + classesBadCase.stream().map(Object::toString).collect(Collectors.joining(", ")))); + } + if (!namedIndividualsBadCase.isEmpty()) { + logError(getMessage(MESSAGE.namedindividual, + namedIndividualsBadCase.stream().map(Object::toString).collect(Collectors.joining(", ")))); + } + if (!objectPropertiesBadCase.isEmpty()) { + logError(getMessage(MESSAGE.objectproperty, + objectPropertiesBadCase.stream().map(Object::toString).collect(Collectors.joining(", ")))); + } + if (!datatypePropertiesBadCase.isEmpty()) { + logError(getMessage(MESSAGE.datatypeproperty, + datatypePropertiesBadCase.stream().map(Object::toString).collect(Collectors.joining(", ")))); + } + } + +} \ No newline at end of file diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_4_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_4_Checker.java new file mode 100644 index 0000000000000000000000000000000000000000..cfc820ea53352ebfda633b3dbac258fafca0dd65 --- /dev/null +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_4_Checker.java @@ -0,0 +1,46 @@ +/* + * Copyright 2024 ETSI + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package fr.mines_stetienne.ci.saref.checkers; + +import fr.mines_stetienne.ci.saref.SAREFPipelineException; +import fr.mines_stetienne.ci.saref.managers.RepositoryManager; + +/** + * Checks TS 103 673 Clause 9.8.1.4: Term declarations + * + */ +public class Clause_9_8_1_4_Checker extends AbstractClauseChecker { + + public Clause_9_8_1_4_Checker(RepositoryManager repositoryManager) { + super(repositoryManager, Clause_9_8_1_4_Checker.class); + } + + @Override + public void checkClause() throws SAREFPipelineException { + new Clause_9_8_1_4_1_Checker(repositoryManager).check(); + } + +} diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_5_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_5_Checker.java new file mode 100644 index 0000000000000000000000000000000000000000..fb205f19fefa3ee2b234d9dc3299d45b3984e8de --- /dev/null +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_5_Checker.java @@ -0,0 +1,233 @@ +/* + * Copyright 2024 ETSI + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package fr.mines_stetienne.ci.saref.checkers; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.SocketTimeoutException; +import java.util.ArrayList; +import java.util.Set; +import java.util.stream.Collectors; + +import org.apache.jena.rdf.model.Model; +import org.semanticweb.owl.explanation.api.Explanation; +import org.semanticweb.owl.explanation.api.ExplanationGenerator; +import org.semanticweb.owlapi.model.OWLAxiom; +import org.semanticweb.owlapi.model.OWLOntology; +import org.semanticweb.owlapi.profiles.OWL2DLProfile; +import org.semanticweb.owlapi.profiles.OWLProfileReport; +import org.semanticweb.owlapi.profiles.violations.UseOfDefinedDatatypeInDatatypeRestriction; +import org.semanticweb.owlapi.profiles.violations.UseOfDefinedDatatypeInLiteral; +import org.semanticweb.owlapi.profiles.violations.UseOfUndeclaredDatatype; +import org.semanticweb.owlapi.profiles.violations.UseOfUnknownDatatype; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NodeList; + +import fr.mines_stetienne.ci.saref.SAREF; +import fr.mines_stetienne.ci.saref.SAREFPipelineException; +import fr.mines_stetienne.ci.saref.managers.OntologyManager; +import fr.mines_stetienne.ci.saref.managers.RepositoryManager; +import fr.mines_stetienne.ci.saref.managers.ThemisManager; +import okhttp3.MediaType; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.RequestBody; +import okhttp3.Response; + +/** + * Checks TS 103 673 Clause 9.8.1.5: OWL Profile, Consistency, and Satisfiability of Classes + * + */ +public class Clause_9_8_1_5_Checker extends AbstractClauseChecker { + + private static enum MESSAGE { + profile, consistent, satisfiable, oops, oopsError; + } + + /** + */ + public Clause_9_8_1_5_Checker(RepositoryManager repositoryManager) { + super(repositoryManager, Clause_9_8_1_5_Checker.class); + } + + @Override + public void checkClause() throws SAREFPipelineException { + final OWLOntology ontology = pipeline.getOntologyManager().loadOntology(version, errorLogger); + if (ontology == null) { + return; + } + + final OWLProfileReport report = new OWL2DLProfile().checkOntology(ontology); + report.getViolations().removeIf(v -> { + if (v instanceof UseOfDefinedDatatypeInDatatypeRestriction || v instanceof UseOfDefinedDatatypeInLiteral + || v instanceof UseOfUndeclaredDatatype || v instanceof UseOfUnknownDatatype) { + return true; + } + return false; + }); + if (!report.getViolations().isEmpty()) { + String violations = report.getViolations().stream().map(Object::toString) + .collect(Collectors.joining("\n- ", "\n\n- ", "\n\n")); + logError(getMessage(MESSAGE.profile, violations)); + } + + OntologyManager ontologyManager = pipeline.getOntologyManager(); + + Set> incExplanation = ontologyManager.getInconsistenceExplanations(ontology, errorLogger); + if (incExplanation != null && !incExplanation.isEmpty()) { + String explanation = incExplanation.stream().map(e -> e.getAxioms().toString()) + .collect(Collectors.joining("\n- ", "\n\n- ", "\n\n")); + logError(getMessage(MESSAGE.consistent, explanation)); + } else { + ExplanationGenerator generator = ontologyManager.getExplanationGenerator(ontology); + ontology.classesInSignature().forEach(c -> { + if (c.isOWLNothing()) { + return; + } + Set> incExplanation2 = ontologyManager.getIncoherenceExplanations(generator, c); + if (!incExplanation2.isEmpty()) { + String explanation = incExplanation2.stream().map(e -> e.getAxioms().toString()) + .collect(Collectors.joining("\n- ", "\n\n- ", "\n\n")); + logError(getMessage(MESSAGE.satisfiable, c, explanation)); + + } + }); + } + try { + checkOops(); + } catch (Exception ex) { + logWarning(getMessage(MESSAGE.oopsError), ex); + } + } + + public void checkOops() throws Exception { + if (SAREF.IGNORE_OOPS) { + return; + } + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + String onto = ""; + + Model model = version.getModel(); + model.write(out, "RDF/XML"); // write in string and then replace + onto = out.toString().replaceAll("]]", "] ]"); + + String xmlRequest = "" + "" + "" + + "" + "" + + "RDF/XML" + ""; + + Object[] arrayData = new Object[0]; + + try { + + OkHttpClient httpClient = new OkHttpClient().newBuilder().build(); + + MediaType mediaType = MediaType.parse("application/xml"); + + RequestBody body = RequestBody.create(xmlRequest, mediaType); + + Request request = new Request.Builder().url("http://oops.linkeddata.es/rest").method("POST", body) + .addHeader("Content-Type", "application/xml").build(); + + try (Response response = httpClient.newCall(request).execute();) { + + if (response.code() != 200) { + throw new SAREFPipelineException("response", "Unexpected response code " + response.code()); + } + + String result = response.body().string(); + + Document doc = ThemisManager.convertStringToXMLDocument(result); + + NodeList nodeList = doc.getElementsByTagName("rdf:Description"); + + ArrayList oopsErrors = new ArrayList(); + for (int temp = 0; temp < nodeList.getLength(); temp++) { + org.w3c.dom.Node node = nodeList.item(temp); + if (node.getNodeType() == org.w3c.dom.Node.ELEMENT_NODE) { + Element element = (Element) node; + if (((Element) node).getElementsByTagName("oops:hasCode").item(0) != null) { + if (((Element) node).getElementsByTagName("oops:hasName").item(0) != null) { + String code = element.getElementsByTagName("oops:hasCode").item(0).getTextContent(); + String name = element.getElementsByTagName("oops:hasName").item(0).getTextContent(); + String description = element.getElementsByTagName("oops:hasDescription").item(0) + .getTextContent(); + String affected = ""; + NodeList affectedElements = element.getElementsByTagName("oops:hasAffectedElement"); + if (affectedElements != null) { + for (int k = 0; k < affectedElements.getLength(); k++) { + if (k == 0) { + affected += "\"" + affectedElements.item(k).getTextContent() + "\""; + } else { + affected += " ; \"" + affectedElements.item(k).getTextContent() + "\""; + } + } + } + + String oopsError = String.format( + "Code: %s, Name: %s, Description: %s, Affected Elements: %s", code, name, + description, affected); + oopsErrors.add(oopsError); + } else { + String code = element.getElementsByTagName("oops:hasCode").item(0).getTextContent(); + String description = element.getElementsByTagName("oops:hasDescription").item(0) + .getTextContent(); + String affected = ""; + NodeList affectedElements = element.getElementsByTagName("oops:hasAffectedElement"); + if (affectedElements != null) { + for (int k = 0; k < affectedElements.getLength(); k++) { + if (k == 0) { + affected += "\"" + affectedElements.item(k).getTextContent() + "\""; + } else { + affected += " ; \"" + affectedElements.item(k).getTextContent() + "\""; + } + } + } + + String oopsError = String.format("Code: %s, Description: %s, Affected Elements: %s", + code, description, affected); + oopsErrors.add(oopsError); + } + } + + } + } + if (!oopsErrors.isEmpty()) { + String data = oopsErrors.stream().map(e -> e.toString()) + .collect(Collectors.joining("\n- ", "\n\n- ", "\n\n")); + logWarning(getMessage(MESSAGE.oops, data)); + + } + } catch (SocketTimeoutException e) { + logWarning(getMessage(MESSAGE.oopsError), e); + } + } catch (IOException | SAREFPipelineException e) { + logWarning(getMessage(MESSAGE.oopsError), e); + } + } + +} diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_Checker.java new file mode 100644 index 0000000000000000000000000000000000000000..f38dabfb163d3a4c73859c3d02642fca2c432bba --- /dev/null +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_1_Checker.java @@ -0,0 +1,98 @@ +/* + * Copyright 2024 ETSI + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. Neither the name of the copyright holder nor the names of its contributors + * may be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package fr.mines_stetienne.ci.saref.checkers; + +import java.io.File; +import java.io.FileFilter; +import java.io.IOException; +import java.nio.file.Files; + +import fr.mines_stetienne.ci.saref.SAREFPipelineException; +import fr.mines_stetienne.ci.saref.managers.RepositoryManager; +import fr.mines_stetienne.ci.saref.utils.Languages; + +/** + * Checks TS 103 673 Clause 9.8.1: Vocabularies ontology directory. Need at least one file. + * + */ +public class Clause_9_8_1_Checker extends AbstractClauseChecker { + + private static enum MESSAGE { + error, missing, ioexception, line, one, name, turtle; + } + + public Clause_9_8_1_Checker(RepositoryManager repositoryManager) { + super(repositoryManager, Clause_9_8_1_Checker.class); + } + + @Override + public void checkClause() throws SAREFPipelineException { + File dir = new File(repository.getDirectory(), "vocabularies"); + if (!dir.isDirectory()) { + return; + } + File[] fileList = null; + + try { + if (Files.walk(dir.toPath(), 1).filter(p -> !p.toFile().isFile() && !p.toFile().getName().startsWith(".")) + .count() != 1) { + logError(getMessage(Clause_9_8_1_Checker.MESSAGE.one, repository.getProject().getOntologyFileName(Languages.TEXT_TURTLE))); + } + // Collect the available vocabulary files. + FileFilter filter = new FileFilter() { + public boolean accept(File f) + { + return f.getName().endsWith("ttl"); + } + }; + fileList = dir.listFiles(filter); + } catch (IOException e) { + logError(getMessage(Clause_9_8_1_Checker.MESSAGE.ioexception), e); + } + + /*File file = new File(dir, repository.getProject().getOntologyFileName(Languages.TEXT_TURTLE)); + if (!file.isFile()) { + String msg = getMessage(MESSAGE.name, repository.getOntologyFileName(Languages.TEXT_TURTLE)); + logError(msg); + throw new SAREFPipelineException(msg); + }*/ + for (File child : fileList) { + System.out.println("!!! "+child.getName()+" !!!");//<<< + } + //<<< Check if saref core imports each vocabulary file. Iterate over each element in fileList and call checks(). + try { + new Clause_9_8_1_1_Checker(repositoryManager).check(); + new Clause_9_8_1_2_Checker(repositoryManager).check(); + new Clause_9_8_1_3_Checker(repositoryManager).check(); + new Clause_9_8_1_4_Checker(repositoryManager).check(); + new Clause_9_8_1_5_Checker(repositoryManager).check(); + } catch (SAREFPipelineException ex) { + logError(getMessage(Clause_9_8_1_Checker.MESSAGE.error), ex); + } + + } + +} diff --git a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_Checker.java b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_Checker.java index fef92e3e7f019157ae8bd2adfde2c692af32205a..173b9acb843779384b48fd5659139304acfd1678 100644 --- a/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_Checker.java +++ b/src/main/java/fr/mines_stetienne/ci/saref/checkers/Clause_9_8_Checker.java @@ -26,10 +26,6 @@ package fr.mines_stetienne.ci.saref.checkers; import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.util.List; -import org.apache.commons.io.FileUtils; import fr.mines_stetienne.ci.saref.SAREFPipelineException; import fr.mines_stetienne.ci.saref.managers.RepositoryManager; @@ -39,40 +35,23 @@ import fr.mines_stetienne.ci.saref.managers.RepositoryManager; */ public class Clause_9_8_Checker extends AbstractClauseChecker { - private static final String FIRST_LINE = "Id;Vocabulary;Requirement"; //<<< - private enum MESSAGE { - missing, ioexception, line + error } public Clause_9_8_Checker(RepositoryManager repositoryManager) { super(repositoryManager, Clause_9_8_Checker.class); } - @Override public void checkClause() throws SAREFPipelineException { File dir = new File(repository.getDirectory(), "vocabularies"); if (!dir.isDirectory()) { - //return; - try { - String[] lines = {FIRST_LINE}; - CreateFileInDirectoryWithContents("vocabularies", "vocabulary.ttl", lines); - } catch (IOException ex) { - logError(getMessage(Clause_9_8_Checker.MESSAGE.ioexception)); - } + return; } try { - File file = new File(dir, "vocabulary.ttl"); - if (!file.exists()) { - logError(getMessage(MESSAGE.missing)); - return; - } - List lines = FileUtils.readLines(file, StandardCharsets.UTF_8); - if (lines.isEmpty() || !lines.get(0).equals(FIRST_LINE)) { - logError(getMessage(MESSAGE.line)); - } - } catch (IOException ex) { - logError(getMessage(MESSAGE.ioexception), ex); + new Clause_9_8_1_Checker(repositoryManager).check(); + } catch (SAREFPipelineException ex) { + logError(getMessage(Clause_9_8_Checker.MESSAGE.error), ex); } } diff --git a/src/main/resources/messages/Clause_10_1_Checker.properties b/src/main/resources/messages/Clause_10_1_Checker.properties index 71211dd1b5eaf868e5946171c0a5c236abe52d53..1189f2469e1ce87f25ad9c0b138f84caea26fff0 100644 --- a/src/main/resources/messages/Clause_10_1_Checker.properties +++ b/src/main/resources/messages/Clause_10_1_Checker.properties @@ -1,2 +1,4 @@ -ioexception=Error while checking the `documentation` directory +line=The requirements specification files in the patterns directory shall be in Turtle 1.1 format. +ioexception=Error while checking the `patterns` directory. +missing=The `patterns` directory should contain at least one file. This file shall conform to the pattern specification as defined in clause 10.3 in TS 103 673. diff --git a/src/main/resources/messages/Clause_10_2_Checker.properties b/src/main/resources/messages/Clause_10_2_Checker.properties index 5d4e63a40d99e1f606a8fe82376bdc3754f87e54..7e9e17452ebead9c0f302da6c999b3cd26714379 100644 --- a/src/main/resources/messages/Clause_10_2_Checker.properties +++ b/src/main/resources/messages/Clause_10_2_Checker.properties @@ -1,3 +1,3 @@ -one=The `documentation/diagrams` directory of the SAREF project version should contain at least one diagram file (such as aa *.drawio or *.png file) to illustrate how the ontology components are related to each other. -ioexception=Error while checking the `documentation` directory - +one=The `patterns` directory of the SAREF project version should contain at least one reference ontology pattern file in ttl format (e.g., pattern.ttl) to illustrate how the ontology components conform to the suite of SAREF patterns. +ioexception=Error while checking the `patterns` directory. +missing=The `patterns` directory should contain at least one file. This file shall conform to the pattern specification as defined in clause 10.3 in TS 103 673. diff --git a/src/main/resources/messages/Clause_9_4_4_Checker.properties b/src/main/resources/messages/Clause_9_4_4_Checker.properties index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..fb41069958106d4430cc13fd4640fec203601498 100644 --- a/src/main/resources/messages/Clause_9_4_4_Checker.properties +++ b/src/main/resources/messages/Clause_9_4_4_Checker.properties @@ -0,0 +1 @@ +error=An unknown error was encountered in Clause 9_4_4. diff --git a/src/main/resources/messages/Clause_9_8_1_1_Checker.properties b/src/main/resources/messages/Clause_9_8_1_1_Checker.properties new file mode 100644 index 0000000000000000000000000000000000000000..ba7748f412a70cbef571336b23b0c1a8f9df8437 --- /dev/null +++ b/src/main/resources/messages/Clause_9_8_1_1_Checker.properties @@ -0,0 +1,5 @@ +one=The `vocabularies` directory of the SAREF project version should contain at least one file called the **vocabulary documents** of the SAREF project version. +ttl=Every vocabulary document shall have the extension `.ttl`. The following documents violate this clause: %s +directories=There should not be directories in the `vocabularies` directory. Their content will be ignored. Got: %s +turtle=The vocabulary document shall contain the sources of an ontology in the Turtle 1.1 format. +write_error=Error while writing the vocabulary in the dataset. diff --git a/src/main/resources/messages/Clause_9_8_1_2_Checker.properties b/src/main/resources/messages/Clause_9_8_1_2_Checker.properties new file mode 100644 index 0000000000000000000000000000000000000000..5bfb68d50e608ceb632e7e9dc4230629f94dfbc9 --- /dev/null +++ b/src/main/resources/messages/Clause_9_8_1_2_Checker.properties @@ -0,0 +1,3 @@ +different=If a prefix declaration has prefix `%s`, then the namespace shall be equal to `<%s>`. Got: `<%s>`. See Clause 9.6.2 in TS 103 673. +expect=The ontology document shall contain namespace %s with corresponding prefix %s. + diff --git a/src/main/resources/messages/Clause_9_8_1_3_Checker.properties b/src/main/resources/messages/Clause_9_8_1_3_Checker.properties new file mode 100644 index 0000000000000000000000000000000000000000..97f00315983bde089b9384c5697d10f264892058 --- /dev/null +++ b/src/main/resources/messages/Clause_9_8_1_3_Checker.properties @@ -0,0 +1 @@ +ontology_declaration=The ontology document shall contain exactly one ontology declaration. The URI of the declared ontology shall be the %s. \ No newline at end of file diff --git a/src/main/resources/messages/Clause_9_8_1_4_1_Checker.properties b/src/main/resources/messages/Clause_9_8_1_4_1_Checker.properties new file mode 100644 index 0000000000000000000000000000000000000000..b4556020c513d6f2999204699e88712deb8000f6 --- /dev/null +++ b/src/main/resources/messages/Clause_9_8_1_4_1_Checker.properties @@ -0,0 +1,5 @@ +pattern=The _localName_ of these terms shall contain only letters and digits: %s +classs=The _localName_ of these classes should be in camel case : /^[A-Z][a-zA-Z0-9]+$/: %s +namedindividual=The _localName_ of these individuals should be in camel case : /^[A-Z][a-zA-Z0-9]+$/: %s +objectproperty=The _localName_ of these object properties should be in mixed case : /^[a-z][a-zA-Z0-9]+$/: %s +datatypeproperty=The _localName_ of these datatype properties should be in mixed case : /^[a-z][a-zA-Z0-9]+$/: %s diff --git a/src/main/resources/messages/Clause_9_8_1_4_Checker.properties b/src/main/resources/messages/Clause_9_8_1_4_Checker.properties new file mode 100644 index 0000000000000000000000000000000000000000..7d7c44780e32ba2630ccc19def7518dfca77ccfa --- /dev/null +++ b/src/main/resources/messages/Clause_9_8_1_4_Checker.properties @@ -0,0 +1 @@ +error=An unknown error was encountered in Clause 9_8_1_4. diff --git a/src/main/resources/messages/Clause_9_8_1_5_Checker.properties b/src/main/resources/messages/Clause_9_8_1_5_Checker.properties new file mode 100644 index 0000000000000000000000000000000000000000..8136a948581d4bef0ac528b60c9383729a8c6ee3 --- /dev/null +++ b/src/main/resources/messages/Clause_9_8_1_5_Checker.properties @@ -0,0 +1,5 @@ +profile=The ontology in the ontology document shall satisfy the OWL2 DL profile. Violations are: %s +consistent=The ontology in the ontology document shall be Consistent. Violations are: %s +satisfiable=OWL Class %s declared in the ontology document should be satisfiable. Violations are: %s +oops=OOPS found some problems. Violations are: %s +oopsError=OOPS error. The service may be under maintenance. \ No newline at end of file diff --git a/src/main/resources/messages/Clause_9_8_1_Checker.properties b/src/main/resources/messages/Clause_9_8_1_Checker.properties new file mode 100644 index 0000000000000000000000000000000000000000..878a81cc24e7cc5eb6a90c040f3a2ed53d82e2db --- /dev/null +++ b/src/main/resources/messages/Clause_9_8_1_Checker.properties @@ -0,0 +1,8 @@ +error=There is an error in the `patterns` directory regarding Clause 9_8_1. +missing=The `patterns` directory should contain at least one file. This file shall conform to the pattern specification as defined in clause 10.3 in TS 103 673. +ioexception=Error while checking the `patterns` directory. +line=The requirements specification files in the patterns directory shall be in Turtle 1.1 format. +one=The `patterns` directory of the SAREF project version shall contain a single file called the *ontology document* of the SAREF project version, and named `%s` +name=The patterns document shall be named `%s`. +turtle=The patterns document shall contain the sources of an ontology in the Turtle 1.1 format. See detailed error below. + diff --git a/src/main/resources/messages/Clause_9_8_Checker.properties b/src/main/resources/messages/Clause_9_8_Checker.properties index 153abffb6c39336edf7cf6eb960c652088b5d167..707b849d5ac85c45d5c423630eb41e1fbdbc9a4f 100644 --- a/src/main/resources/messages/Clause_9_8_Checker.properties +++ b/src/main/resources/messages/Clause_9_8_Checker.properties @@ -1,3 +1,2 @@ -missing=The `vocabularies` directory should contain a file `vocabulary.ttl`. This file shall conform to the vocabulary specification as defined in clause 9.8 in TS 103 673. -line=The vocabularies specification file shall be a Turtle-formatted file encoded in UTF-8. -ioexception=Error while checking the `vocabularies` directory. +error=Error while checking the `vocabularies` directory. + diff --git a/tests/tests.csv b/tests/tests.csv index adc42032642dd4cceb341a40edce1eb7d1c0b630..aceb4ef003522ab3f2b55a9a3577bec41f2803f4 100644 --- a/tests/tests.csv +++ b/tests/tests.csv @@ -1,172 +1,3 @@ Id;Requirement;Category;Test AUTO-TEST-1;AUTO-1;Automobile objects;WaterInfrastructure hasSubSystem WaterAsset -AUTO-TEST-2;AUTO-2;Automobile objects;Reservoir subClassOf WaterAsset - -Classes :: -AUTO-TEST-2;AUTO-2;Automobile objects;AutomotiveState - -AUTO-TEST-2;AUTO-2;Automobile objects;AbsolutePosition -AUTO-TEST-2;AUTO-2;Automobile objects;AbsoluteSpeed -AUTO-TEST-2;AUTO-2;Automobile objects;Acceleration -AUTO-TEST-2;AUTO-2;Automobile objects;AccelerationConfidence -AUTO-TEST-2;AUTO-2;Automobile objects;Address -AUTO-TEST-2;AUTO-2;Automobile objects;AngularDirection -AUTO-TEST-2;AUTO-2;Automobile objects;Assembling -AUTO-TEST-2;AUTO-2;Automobile objects;AtDropOffSpot -AUTO-TEST-2;AUTO-2;Automobile objects;AtPickUpSpot -AUTO-TEST-2;AUTO-2;Automobile objects;AutomationLevel -AUTO-TEST-2;AUTO-2;Automobile objects;AutomotiveObject -AUTO-TEST-2;AUTO-2;Automobile objects;BrakeCapacity -AUTO-TEST-2;AUTO-2;Automobile objects;Bus -AUTO-TEST-2;AUTO-2;Automobile objects;Car -AUTO-TEST-2;AUTO-2;Automobile objects;CardinalityUnit -AUTO-TEST-2;AUTO-2;Automobile objects;Charging -AUTO-TEST-2;AUTO-2;Automobile objects;Closed -AUTO-TEST-2;AUTO-2;Automobile objects;Confidence -AUTO-TEST-2;AUTO-2;Automobile objects;CriticalObject -AUTO-TEST-2;AUTO-2;Automobile objects;Disengaging -AUTO-TEST-2;AUTO-2;Automobile parking;DrivingToParkingSpot -AUTO-TEST-2;AUTO-2;Automobile parking;DrivingToPickUpSpot -AUTO-TEST-2;AUTO-2;Automobile parking;ElectricChargingParkingSpot -AUTO-TEST-2;AUTO-2;Automobile objects;ElectronicControlUnit -AUTO-TEST-2;AUTO-2;Automobile objects;EndPoint -AUTO-TEST-2;AUTO-2;Automobile objects;Engaging -AUTO-TEST-2;AUTO-2;Automobile objects;Forming -AUTO-TEST-2;AUTO-2;Automobile objects;Free -AUTO-TEST-2;AUTO-2;Automobile objects;Heading -AUTO-TEST-2;AUTO-2;Automobile objects;HeavyTruck -AUTO-TEST-2;AUTO-2;Automobile objects;Height -AUTO-TEST-2;AUTO-2;Automobile objects;HeightUnit -AUTO-TEST-2;AUTO-2;Automobile objects;Identifier -AUTO-TEST-2;AUTO-2;Automobile objects;LargeObject -AUTO-TEST-2;AUTO-2;Automobile objects;LateralAcceleration -AUTO-TEST-2;AUTO-2;Automobile objects;Length -AUTO-TEST-2;AUTO-2;Automobile objects;LengthUnit -AUTO-TEST-2;AUTO-2;Automobile objects;LightTruck -AUTO-TEST-2;AUTO-2;Automobile objects;LongitudinalAcceleration -AUTO-TEST-2;AUTO-2;Automobile objects;MediumObject -AUTO-TEST-2;AUTO-2;Automobile objects;Movement -AUTO-TEST-2;AUTO-2;Automobile objects;NotifiedEvent -AUTO-TEST-2;AUTO-2;Automobile objects;Occupied -AUTO-TEST-2;AUTO-2;Automobile objects;P1Pedestrian -AUTO-TEST-2;AUTO-2;Automobile objects;P2Bicyclist -AUTO-TEST-2;AUTO-2;Automobile objects;P3Motorcyclist -AUTO-TEST-2;AUTO-2;Automobile objects;P4Animal -AUTO-TEST-2;AUTO-2;Automobile parking;Parked -AUTO-TEST-2;AUTO-2;Automobile parking;Parking -AUTO-TEST-2;AUTO-2;Automobile parking;ParkingSpot -AUTO-TEST-2;AUTO-2;Automobile parking;ParkingSpotPoint -AUTO-TEST-2;AUTO-2;Automobile objects;PassengerCar -AUTO-TEST-2;AUTO-2;Automobile objects;PersonalDevice -AUTO-TEST-2;AUTO-2;Automobile platooning;Platoon -AUTO-TEST-2;AUTO-2;Automobile platooning;PlatoonAutomationLevel -AUTO-TEST-2;AUTO-2;Automobile platooning;PlatoonPosition -AUTO-TEST-2;AUTO-2;Automobile platooning;PlatoonRole -AUTO-TEST-2;AUTO-2;Automobile platooning;PlatoonState -AUTO-TEST-2;AUTO-2;Automobile platooning;PlatoonVehicleState -AUTO-TEST-2;AUTO-2;Automobile parking;ParkingSpotState -AUTO-TEST-2;AUTO-2;Automobile parking;ParkingVehicleState -AUTO-TEST-2;AUTO-2;Automobile parking;PerceptionState -AUTO-TEST-2;AUTO-2;Automobile platooning;Platooning -AUTO-TEST-2;AUTO-2;Automobile objects;Point -AUTO-TEST-2;AUTO-2;Automobile objects;Position -AUTO-TEST-2;AUTO-2;Automobile objects;PositionConfidenceEllipse -AUTO-TEST-2;AUTO-2;Automobile objects;PublicTransport -AUTO-TEST-2;AUTO-2;Automobile objects;RegularParkingSpot -AUTO-TEST-2;AUTO-2;Automobile objects;RelativePosition -AUTO-TEST-2;AUTO-2;Automobile objects;RelativeSpeed -AUTO-TEST-2;AUTO-2;Automobile objects;RendezvousLocation -AUTO-TEST-2;AUTO-2;Automobile objects;Reserved -AUTO-TEST-2;AUTO-2;Automobile objects;RoadEntity -AUTO-TEST-2;AUTO-2;Automobile objects;RoadObject -AUTO-TEST-2;AUTO-2;Automobile objects;RoadSideActuator -AUTO-TEST-2;AUTO-2;Automobile objects;RoadSideEquipment -AUTO-TEST-2;AUTO-2;Automobile objects;RoadSideSensor -AUTO-TEST-2;AUTO-2;Automobile objects;RoadTopologyPosition -AUTO-TEST-2;AUTO-2;Automobile objects;Role -AUTO-TEST-2;AUTO-2;Automobile objects;Route -AUTO-TEST-2;AUTO-2;Automobile objects;RoutePoint -AUTO-TEST-2;AUTO-2;Automobile objects;Searching -AUTO-TEST-2;AUTO-2;Automobile objects;Shape -AUTO-TEST-2;AUTO-2;Automobile objects;Size -AUTO-TEST-2;AUTO-2;Automobile objects;SmallObject -AUTO-TEST-2;AUTO-2;Automobile objects;SpecialPermitParkingSpot -AUTO-TEST-2;AUTO-2;Automobile objects;Speed -AUTO-TEST-2;AUTO-2;Automobile objects;SpeedConfidence -AUTO-TEST-2;AUTO-2;Automobile objects;SpeedUnit -AUTO-TEST-2;AUTO-2;Automobile objects;Standalone -AUTO-TEST-2;AUTO-2;Automobile objects;StartPoint -AUTO-TEST-2;AUTO-2;Automobile objects;StationID -AUTO-TEST-2;AUTO-2;Automobile objects;TrafficLightController -AUTO-TEST-2;AUTO-2;Automobile objects;TrafficManagementCentre -AUTO-TEST-2;AUTO-2;Automobile objects;Tram -AUTO-TEST-2;AUTO-2;Automobile objects;Truck -AUTO-TEST-2;AUTO-2;Automobile objects;TwoWheeler -AUTO-TEST-2;AUTO-2;Automobile objects;UUID -AUTO-TEST-2;AUTO-2;Automobile objects;Unknown -AUTO-TEST-2;AUTO-2;Automobile objects;Vehicle -AUTO-TEST-2;AUTO-2;Automobile objects;VehicleAutomationLevel -AUTO-TEST-2;AUTO-2;Automobile objects;VehicleEnvironment -AUTO-TEST-2;AUTO-2;Automobile objects;VehicleRole -AUTO-TEST-2;AUTO-2;Automobile objects;VulnerableRoadUser -AUTO-TEST-2;AUTO-2;Automobile objects;Weight -AUTO-TEST-2;AUTO-2;Automobile objects;Width -AUTO-TEST-2;AUTO-2;Automobile objects;WidthUnit -AUTO-TEST-2;AUTO-2;Automobile objects;YawRate - -ObjectProperty :: -:hasConfidenceUnitOfMeasure -:consistsOfEntity -:consistsOfEquipment -:consistsOfEvent -:consistsOfObject -:consistsOfUser -:consistsOfVehicle -:detectsPosition -:hasAbsolutePosition -:hasAutomationLevel -:hasBrakeCapacity -:hasConfidence -:hasDestination -:hasDestinationAddress -:hasDestinationEndPoint -:hasEnvironment -:hasEstimatedRendezvousLocation -:hasHeight -:hasIdentifier -:hasLength -:hasMember -:hasMovement -:hasOpeningTimeAvailability -:hasOrigin -:hasPlatoonMember -:hasPlatoonPosition -:hasPlatoonRole -:hasPosition -:hasRelativePosition -:hasRoadTopologyPosition -:hasRole -:hasRoute -:hasShape -:hasSize -:hasVehicleEnvironmentMember -:hasVehicleRole -:hasWidth -:isCollectionOf -:isConfidenceOf -:isMemberOf -:isMemberOfPlatoon -:isMemberOfVehicleEnvironment -:usesMeasurement - -DatatypeProperty :: -:hasConfidenceValue -:hasCoordinateX -:hasCoordinateY -:hasCoordinateZ -:hasDescriptionName -:hasEstimatedJoiningTime -:hasIDValue -:hasMaxSize -:hasPlatoonIndex