diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 98ffd76..9eca45e 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -12,16 +12,16 @@ jobs:
runs-on: ubuntu-20.04
strategy:
matrix:
- java: [ '8', '11', '13', '15' ]
+ java: ["11", "17", "21"]
name: Java ${{ matrix.Java }}
steps:
- uses: actions/checkout@v3
- name: Setup java
uses: actions/setup-java@v3
with:
- distribution: 'adopt'
+ distribution: "adopt"
java-version: ${{ matrix.java }}
- name: Build with Maven
- run: mvn -B package --file pom.xml
+ run: mvn -B package --file pom.xml
- name: Test with Maven
- run: mvn -B test --file pom.xml
\ No newline at end of file
+ run: mvn -B test --file pom.xml
diff --git a/.gitignore b/.gitignore
index 8263487..ae9493e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -41,6 +41,9 @@ example.yaml
# .idea/*.iml
# .idea/modules
+# Generated files
+.vscode/settings.json
+
# CMake
cmake-build-*/
diff --git a/CITATION.cff b/CITATION.cff
new file mode 100644
index 0000000..8f5475b
--- /dev/null
+++ b/CITATION.cff
@@ -0,0 +1,25 @@
+title: "OBA: Ontology-Based APIs"
+license: Apache-2.0
+authors:
+ - family-names: Osorio
+ given-names: Maximiliano
+ orcid: "https://orcid.org/0000-0002-3611-6510"
+ - family-names: Garijo
+ given-names: Daniel
+ orcid: "https://orcid.org/0000-0003-0454-7145"
+cff-version: 1.2.0
+message: "If you use this software, please cite both the article from preferred-citation and the software itself."
+preferred-citation:
+ authors:
+ - family-names: Osorio
+ given-names: Maximiliano
+ - family-names: Garijo
+ given-names: Daniel
+ title: "OBA: An Ontology-Based Framework for Creating REST APIs for Knowledge Graphs"
+ type: article
+ year: 2021
+ doi: 10.1007/978-3-030-62466-8_4
+identifiers:
+ - description: "Collection of archived snapshots for OBA"
+ type: doi
+ value: 10.5281/zenodo.6639554
diff --git a/README.md b/README.md
index 9b07e28..fa63d4a 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
-# Ontology-Based APIs (OBA) [![Test](https://github.com/KnowledgeCaptureAndDiscovery/OBA/actions/workflows/build.yaml/badge.svg)](https://github.com/KnowledgeCaptureAndDiscovery/OBA/actions/workflows/build.yaml)
+# Ontology-Based APIs (OBA) [![Test](https://github.com/KnowledgeCaptureAndDiscovery/OBA/actions/workflows/build.yaml/badge.svg)](https://github.com/KnowledgeCaptureAndDiscovery/OBA/actions/workflows/build.yaml) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6639554.svg)](https://doi.org/10.5281/zenodo.6639554)
OBA reads ontologies (OWL) and generates an OpenAPI Specification (OAS). Using this definition, OBA creates a REST API server automatically.
-![Diagram](docs/figures/oba.svg)
+![Diagram](docs/figures/oba.svg)
## Quickstart
@@ -11,6 +11,11 @@ There are two option to run OBA:
1. Download the binary.
2. Build the binary from the repository.
+### Pre-requisites
+
+Due to recent versions of the OpenAPI generator being built with Java 11, you will need Java 11 or higher to run OBA v3.7.0. The current recommended distribution of Java 11+ JDKs (and "JREs") is at [Adoptium's releases page](https://adoptium.net/temurin/releases/?version=11).
+
+Java versions higher than 11 are also available to use. Java 11 is simply the minimum version.
### Downloading binary
@@ -35,3 +40,20 @@ $ java -jar oba-*-jar-with-dependencies.jar -c config.yaml
Congratulations! You have generated an Open Api Specification.
For instructions on using OBA to create your API server, go to the [documentation](https://oba.readthedocs.io/en/latest/)
+
+## Citation
+
+Please cite our work as follows:
+
+```
+@inproceedings{garijo2020OBA,
+ title = {{OBA}: An Ontology-Based Framework for Creating REST APIs for Knowledge Graphs},
+ author = {Garijo, Daniel and Osorio, Maximiliano},
+ booktitle={International Semantic Web Conference},
+ pages={48--64},
+ year={2020},
+ doi={https://doi.org/10.1007/978-3-030-62466-8_4},
+ organization = {Springer, Cham},
+ isbn={978-3-030-62466-8}
+}
+```
diff --git a/docs/configuration_file.md b/docs/configuration_file.md
index ec27bb2..ee777de 100644
--- a/docs/configuration_file.md
+++ b/docs/configuration_file.md
@@ -7,8 +7,7 @@ Below is an example YAML file which may require some changes for your project's
You can find examples in [GitHub](https://github.com/KnowledgeCaptureAndDiscovery/OBA/tree/master/examples)
!!! info
- If you experience any issues when using OBA, or if you would like us to support additional exciting features, please open an issue on our [GitHub repository](https://github.com/KnowledgeCaptureAndDiscovery/OBA/issues).
-
+If you experience any issues when using OBA, or if you would like us to support additional exciting features, please open an issue on our [GitHub repository](https://github.com/KnowledgeCaptureAndDiscovery/OBA/issues).
```yaml
#Name of the project
@@ -25,7 +24,7 @@ openapi:
version: v1.3.0
externalDocs:
description: DBpedia
- url: http://dbpedia.org/
+ url: http://dbpedia.org/
servers:
- url: https://dbpedia.dbpedia.oba.isi.edu/v1.3.0
- url: http://localhost:8080/v1.3.0
@@ -50,9 +49,21 @@ enable_put_paths: false
classes:
- http://dbpedia.org/ontology/Genre
- http://dbpedia.org/ontology/Band
+
follow_references: false
-```
+## Enable/disable generation of a default description for each schema
+default_descriptions: true
+
+## Enable/disable generation of default properties (description, id, label, and type) for each schema
+default_properties: true
+
+## Enable/disable generation of arrays for property type(s) all the time, regardless of cardinality / restrictions
+always_generate_arrays: true
+
+## Enable/disable generation of list of required properties for a schema, if the the cardinality indicates it is required (e.g. exactly 1)
+required_properties_from_cardinality: false
+```
## Supported settings
@@ -60,9 +71,9 @@ follow_references: false
The name of OpenAPI
-| Field | Value |
-|---|---|
-| **Required:** | ``true`` |
+| Field | Value |
+| ------------- | ------ |
+| **Required:** | `true` |
Example:
@@ -70,16 +81,14 @@ Example:
name: dbpedia_music
```
-
### output_dir
The output directory of the OpenApi specification files, relative to the root of the project.
-| Field | Value |
-|---|---|
-| **Required:** | ``false`` |
-| **Default:** | ``outputs`` |
-
+| Field | Value |
+| ------------- | --------- |
+| **Required:** | `false` |
+| **Default:** | `outputs` |
Example:
@@ -87,17 +96,15 @@ Example:
output_dir: outputs
```
-
### OpenAPI
Basic information of API using OpenAPI Spec.
More info: [OpenAPI Base file](https://swagger.io/docs/specification/basic-structure/)
-| Field | Value |
-|---|---|
-| **Required:** | ``true`` |
-| **Type:** | ``OpenAPI`` |
-
+| Field | Value |
+| ------------- | --------- |
+| **Required:** | `true` |
+| **Type:** | `OpenAPI` |
Example:
@@ -110,56 +117,51 @@ openapi:
version: v1.3.0
externalDocs:
description: DBpedia
- url: http://dbpedia.org/
+ url: http://dbpedia.org/
servers:
- url: https://dbpedia.dbpedia.oba.isi.edu/v1.3.0
- url: http://localhost:8080/v1.3.0
```
-
-
### enable_get_paths
Enable the GET method for the paths
-| Field | Value |
-|---|---|
-| **Required:** | ``false`` |
-| **Type:** | ``boolean`` |
-| **Default:** | ``true`` |
+| Field | Value |
+| ------------- | --------- |
+| **Required:** | `false` |
+| **Type:** | `boolean` |
+| **Default:** | `true` |
-### enable_post_paths:
+### enable_post_paths:
Enable the POST method for the paths
-| Field | Value |
-|---|---|
-| **Required:** | ``false`` |
-| **Type:** | ``boolean`` |
-| **Default:** | ``false`` |
-
+| Field | Value |
+| ------------- | --------- |
+| **Required:** | `false` |
+| **Type:** | `boolean` |
+| **Default:** | `false` |
### enable_delete_paths
Enable the DELETE method for the paths
-| Field | Value |
-|---|---|
-| **Required:** | ``false`` |
-| **Type:** | ``boolean`` |
-| **Default:** | ``false`` |
+| Field | Value |
+| ------------- | --------- |
+| **Required:** | `false` |
+| **Type:** | `boolean` |
+| **Default:** | `false` |
### enable_put_paths
Enable the PUT method for the paths
-| Field | Value |
-|---|---|
-| **Required:** | ``false`` |
-| **Type:** | ``boolean`` |
-| **Default:** | ``false`` |
-
-
+| Field | Value |
+| ------------- | --------- |
+| **Required:** | `false` |
+| **Type:** | `boolean` |
+| **Default:** | `false` |
### endpoint
@@ -170,64 +172,57 @@ endpoint:
url: http://dbpedia.org/sparql
prefix: http://dbpedia.org/resource
# Add the GRAPH clause. Enable it when you are using authentication.
- # OBA uses a graph to store the user contents on a personal namespace.
+ # OBA uses a graph to store the user contents on a personal namespace.
# For DBpedia, dont use it.
- graph: http://endpoint.mint.isi.edu/modelCatalog-1.4.0/data/
+ graph: http://endpoint.mint.isi.edu/modelCatalog-1.4.0/data/
```
### endpoint.url
-The url of the SPARQL Endpoint
-
-| Field | Value |
-|---|---|
-| **Required:** | ``true`` |
-| **Type:** | ``url`` |
+The url of the SPARQL Endpoint
+| Field | Value |
+| ------------- | ------ |
+| **Required:** | `true` |
+| **Type:** | `url` |
Example:
```yaml
- url: http://dbpedia.org/sparql
+url: http://dbpedia.org/sparql
```
-
### endpoint.prefix
-
The prefix of the SPARQL Endpoint.
This is useful when you create a new resource.
-| Field | Value |
-|---|---|
-| **Required:** | ``true`` |
-| **Type:** | ``url`` |
-
+| Field | Value |
+| ------------- | ------ |
+| **Required:** | `true` |
+| **Type:** | `url` |
Example:
```yaml
- prefix: http://dbpedia.org/resource
+prefix: http://dbpedia.org/resource
```
-
### endpoint.graph_base
-OBA uses a graph to store the user contents on a personal namespace.
-
-| Field | Value |
-|---|---|
-| **Required:** | ``true`` |
-| **Type:** | ``url`` |
+OBA uses a graph to store the user contents on a personal namespace.
+| Field | Value |
+| ------------- | ------ |
+| **Required:** | `true` |
+| **Type:** | `url` |
Example:
```yaml
- graph_base: http://ontosoft.isi.edu:3030/modelCatalog-1.2.0/data/
+graph_base: http://ontosoft.isi.edu:3030/modelCatalog-1.2.0/data/
```
-
## ontologies
Example:
@@ -236,17 +231,18 @@ Example:
ontologies:
- https://tinyurl.com/dbpediaoba
```
-| Field | Value |
-|---|---|
-| **Required:** | ``true`` |
-| **Type:** | ``List[string]`` |
+
+| Field | Value |
+| ------------- | -------------- |
+| **Required:** | `true` |
+| **Type:** | `List[string]` |
## custom_queries_directory
-| Field | Value |
-|---|---|
-| **Required:** | ``false`` |
-| **Type:** | ``List[Path]`` |
+| Field | Value |
+| ------------- | ------------ |
+| **Required:** | `false` |
+| **Type:** | `List[Path]` |
[Go to how to add custom queries](adding_custom_queries.md) for more information
@@ -256,10 +252,10 @@ Some ontologies contain numerous classes. However, you can be interested in a su
### classes
-| Field | Value |
-|---|---|
-| **Required:** | ``false`` |
-| **Type:** | ``List[URI]`` |
+| Field | Value |
+| ------------- | ----------- |
+| **Required:** | `false` |
+| **Type:** | `List[URI]` |
```yaml
classes:
@@ -269,12 +265,11 @@ classes:
### follow_references
-| Field | Value |
-|---|---|
-| **Required:** | ``false`` |
-| **Type:** | ``Boolean`` |
-| **Default:** | ``True`` |
-
+| Field | Value |
+| ------------- | --------- |
+| **Required:** | `false` |
+| **Type:** | `Boolean` |
+| **Default:** | `True` |
For more information, go to [filtering classes](filtering.md#following-references)
@@ -282,18 +277,80 @@ For more information, go to [filtering classes](filtering.md#following-reference
follow_references: false
```
+### default_descriptions
+
+Enable/disable generation of a default description for each schema.
+
+| Field | Value |
+| ------------- | --------- |
+| **Required:** | `false` |
+| **Type:** | `Boolean` |
+| **Default:** | `True` |
+
+For more information, go to [filtering classes](filtering.md#default_descriptions)
+
+```yaml
+default_descriptions: false
+```
+
+### default_properties
+
+Enable/disable generation of default properties (description, id, label, and type) for each schema.
+
+| Field | Value |
+| ------------- | --------- |
+| **Required:** | `false` |
+| **Type:** | `Boolean` |
+| **Default:** | `True` |
+
+For more information, go to [filtering classes](filtering.md#default_properties)
+
+```yaml
+default_properties: false
+```
+
+### always_generate_arrays
+
+Enable/disable generation of arrays for property type(s) all the time, regardless of cardinality / restrictions.
+
+| Field | Value |
+| ------------- | --------- |
+| **Required:** | `false` |
+| **Type:** | `Boolean` |
+| **Default:** | `True` |
+
+For more information, go to [filtering classes](filtering.md#always_generate_arrays)
+
+```yaml
+always_generate_arrays: true
+```
+
+### required_properties_from_cardinality
+
+Enable/disable generation of list of required properties for a schema, if the the cardinality indicates it is required (e.g. exactly 1).
+
+| Field | Value |
+| ------------- | --------- |
+| **Required:** | `false` |
+| **Type:** | `Boolean` |
+| **Default:** | `False` |
+
+For more information, go to [filtering classes](filtering.md#required_properties_from_cardinality)
+
+```yaml
+required_properties_from_cardinality: true
+```
## auth
Add login to the API and add security to the following methods: `POST`, `PUT` and `DELETE`
-
### provider
-| Field | Value |
-|---|---|
-| **Required:** | ``true`` |
-| **Type:** | ``str`` |
+| Field | Value |
+| ------------- | ------ |
+| **Required:** | `true` |
+| **Type:** | `str` |
The providers supported:
@@ -314,12 +371,10 @@ firebase:
To authenticate a service account and authorize it to access Firebase services, you must generate a private key file.
-
-
-| Field | Value |
-|---|---|
-| **Required:** | ``true`` |
-| **Type:** | ``str`` |
+| Field | Value |
+| ------------- | ------ |
+| **Required:** | `true` |
+| **Type:** | `str` |
```
firebase:
diff --git a/docs/filtering.md b/docs/filtering.md
index 06b97e4..aa3130b 100644
--- a/docs/filtering.md
+++ b/docs/filtering.md
@@ -3,8 +3,8 @@ OBA can filter the classes.
The following example is selecting two classes:
- - http://dbpedia.org/ontology/Genre
- - http://dbpedia.org/ontology/Band
+- http://dbpedia.org/ontology/Genre
+- http://dbpedia.org/ontology/Band
```yaml
### For more information about the section. Go to the official documentation
@@ -42,12 +42,24 @@ enable_put_paths: false
classes:
- http://dbpedia.org/ontology/Genre
- http://dbpedia.org/ontology/Band
+
follow_references: false
+
+## Enable/disable generation of a default description for each schema
+default_descriptions: true
+
+## Enable/disable generation of default properties (description, id, label, and type) for each schema
+default_properties: true
+
+## Enable/disable generation of arrays for property type(s) all the time, regardless of cardinality / restrictions
+always_generate_arrays: true
+
+## Enable/disable generation of list of required properties for a schema, if the the cardinality indicates it is required (e.g. exactly 1)
+required_properties_from_cardinality: false
```
The result is available at: [DBPedia Music](https://app.swaggerhub.com/apis/mosoriob/dbpedia-music/v1.3.0)
-
### Following references
If you inspect the properties of a Band, you can see the a Band has one or more locationCity. However, a locationCity is a object then you don't have information about the object.
@@ -68,24 +80,23 @@ The option `follow_references` enables to follow the references.
Let's enable the option for the previous example.
Now, you have the whole information:
-- A city has 423 properties.
-- One property is the leaderName and a leaderName is Person.
-- A person has 285.
+- A city has 423 properties.
+- One property is the leaderName and a leaderName is Person.
+- A person has 285.
!!! warning
- For large ontologies, we don't recommend use the option because the result can be too heavy.
-
+For large ontologies, we don't recommend use the option because the result can be too heavy.
```yaml
components:
schemas:
Band:
- locationCity:
- items:
- $ref: '#/components/schemas/City'
- nullable: true
- type: array
+ locationCity:
+ items:
+ $ref: "#/components/schemas/City"
+ nullable: true
+ type: array
City:
properties:
cityType:
@@ -100,7 +111,7 @@ components:
type: array
reffBourgmestre:
items:
- $ref: '#/components/schemas/Person'
+ $ref: "#/components/schemas/Person"
nullable: true
type: array
communityIsoCode:
@@ -110,14 +121,14 @@ components:
type: array
leaderName:
items:
- $ref: '#/components/schemas/Person'
+ $ref: "#/components/schemas/Person"
nullable: true
type: array
Person:
properties:
parent:
items:
- $ref: '#/components/schemas/Person'
+ $ref: "#/components/schemas/Person"
nullable: true
type: array
viafId:
@@ -127,17 +138,190 @@ components:
type: array
competitionTitle:
items:
- $ref: '#/components/schemas/SportsEvent'
+ $ref: "#/components/schemas/SportsEvent"
nullable: true
type: array
artPatron:
items:
- $ref: '#/components/schemas/Artist'
+ $ref: "#/components/schemas/Artist"
nullable: true
type: array
hairColour:
items:
type: string
nullable: true
- type: array
+ type: array
+```
+
+### Including default schema descriptions
+
+It is generally good practice to include a high-level description for a schema. By default, a placeholder description is included with the text `Description not available`. For example:
+
+```yaml
+components:
+ schemas:
+ YourClass:
+ description: Description not available
+ properties: {}
+ type: object
+```
+
+The option `default_descriptions` allows you to disable the default description for a schema (i.e. if there is no description/comment defined for an entity/class in the ontology). By setting the `default_descriptions` value to `false`, the above example becomes:
+
+```yaml
+components:
+ schemas:
+ YourClass:
+ properties: {}
+ type: object
+```
+
+### Including default schema properties
+
+You may wish to include common properties for each even if not defined for the entity/class. Currently, the default properites that are added to each schema are `description`, `id`, `label`, and `type`. Additional default properties are included (`eventDateTime`, `quantity`, `isBool`) which are meant to provide examples are other common data types. For example:
+
+```yaml
+components:
+ schemas:
+ YourClass:
+ properties:
+ propertyA:
+ type: string
+ propertyB:
+ type: integer
+ eventDateTime:
+ description: a date/time of the resource
+ format: date-time
+ nullable: true
+ type: string
+ quantity:
+ description: a number quantity of the resource
+ nullable: true
+ type: number
+ isBool:
+ description: a boolean indicator of the resource
+ nullable: true
+ type: boolean
+ description:
+ description: small description
+ nullable: true
+ type: string
+ label:
+ description: short description of the resource
+ nullable: true
+ type: string
+ id:
+ description: identifier
+ format: int32
+ nullable: false
+ type: integer
+ type:
+ description: type(s) of the resource
+ items:
+ type: string
+ nullable: true
+ type: array
+ type: object
+```
+
+The option `default_properties` allows you to disable the default properties for a schema. If one or more of the properties are defined for the class, however, the property will still be included in the OpenAPI YAML specification. By setting the `default_properties` value to `false`, the above example becomes:
+
+```yaml
+components:
+ schemas:
+ YourClass:
+ properties:
+ propertyA:
+ type: string
+ propertyB:
+ type: integer
+ type: object
+```
+
+### Generating property types as array of items uniformly vs. non-array when cardinality/restrictions warrant it
+
+When a property can have multiple items (e.g. a list of names), the property schema will always generate `type: array` with an `items:` key and sub-item types (e.g. `type: string`). However, in cases where the property is restricted by cardinality, the API spec can be generated so that the property is not an array but a single type (e.g. `type: string`). These cases include cardinality where the property is exactly 1 or is a maximum of 1.
+
+The default is to treat everything as an array, such as:
+
+```yaml
+components:
+ schemas:
+ YourClass:
+ properties:
+ propertyA:
+ items:
+ maxItems: 1
+ minItems: 1
+ type: string
+ type: array
+ propertyB:
+ items:
+ maxItems: 3
+ type: string
+ type: array
+ type: object
+```
+
+The option `always_generate_arrays` allows you to disable the generating all properties with an array of items, if the class restrictions warrant it (e.g. there is exactly one property value allowed). By setting the `always_generate_arrays` value to `false`, the above example becomes:
+
+```yaml
+components:
+ schemas:
+ YourClass:
+ properties:
+ propertyA:
+ type: array
+ propertyB:
+ items:
+ maxItems: 3
+ type: string
+ type: array
+ type: object
+```
+
+### Generating list of required property/properties for a class, when cardinality/restrictions warrant it
+
+When a property is known to be required based on class restrictions (e.g. exactly 1 or a minimum >= 1), OpenAPI specification supports a `required` key directly under the property. By default, OBA does not generate this required list of properties (for each class), for example:
+
+```yaml
+components:
+ schemas:
+ YourClass:
+ properties:
+ propertyA:
+ items:
+ maxItems: 1
+ minItems: 1
+ type: string
+ type: array
+ propertyB:
+ items:
+ maxItems: 3
+ type: string
+ type: array
+ type: object
+```
+
+The option `required_properties_from_cardinality` allows you to generate this list based on class restrictions (e.g. there is exactly one property value or there is a minimum of 1 or more of the property value). By setting the `required_properties_from_cardinality` value to `true`, the above example becomes:
+
+```yaml
+components:
+ schemas:
+ YourClass:
+ properties:
+ propertyA:
+ items:
+ maxItems: 1
+ minItems: 1
+ type: string
+ type: array
+ propertyB:
+ items:
+ maxItems: 3
+ type: string
+ type: array
+ type: object
+ required:
+ - propertyA
```
diff --git a/pom.xml b/pom.xml
index 0362dd1..cd1bfe1 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,17 +6,17 @@
jar
edu.isi.oba
oba
- 3.6.1
+ 3.9.0
core
https://github.com/KnowledgeCaptureAndDiscovery/OBA
UTF-8
- 1.8
- 1.8
- 1.8
- 3.1.1
+ 11
+ 11
+
+ 3.5.2
@@ -24,60 +24,68 @@
org.json
json
- 20190722
+ 20240303
+
- com.github.jsonld-java
- jsonld-java
- 0.11.1
+ org.junit.jupiter
+ junit-jupiter-api
+ 5.10.2
+ test
-
-
-
-
- log4j
- log4j
- 1.2.17
+ io.swagger
+ swagger-compat-spec-parser
+ 1.0.70
-
+
+
+ io.swagger.core.v3
+ swagger-models
+ 2.2.21
+
+
+
+ io.swagger.parser.v3
+ swagger-parser
+ 2.1.21
+
+
- org.slf4j
- slf4j-simple
- 1.7.28
+ io.swagger.parser.v3
+ swagger-parser-core
+ 2.1.21
- -->
+
- junit
- junit
- 4.13.1
- test
+ org.openapitools
+ openapi-generator
+ 7.4.0
+
+
net.sourceforge.owlapi
owlapi-api
- 5.1.10
+ 5.5.0
+
net.sourceforge.owlapi
owlapi-apibinding
- 5.1.10
-
-
-
- org.openapitools
- openapi-generator
- 4.0.0
-
+ 5.5.0
+
net.sourceforge.owlapi
- owlapi-compatibility
- 5.1.10
+ owlapi-impl
+ 5.5.0
+
org.yaml
@@ -90,13 +98,21 @@
maven-dependency-plugin
3.1.1
+
commons-cli
commons-cli
- 1.3.1
+ 1.6.0
+
+
+
+ com.fasterxml.jackson.core
+ jackson-core
+ 2.17.0
+
@@ -106,26 +122,35 @@
+
org.apache.maven.plugins
maven-eclipse-plugin
- 2.9
+ 2.10
true
false
+
org.apache.maven.plugins
maven-compiler-plugin
- 2.3.2
+ 3.13.0
${jdk.version}
+
+
+ org.apache.maven.plugins
+ maven-surefire-plugin
+ 3.2.5
+
+
maven-assembly-plugin
diff --git a/src/main/java/edu/isi/oba/Mapper.java b/src/main/java/edu/isi/oba/Mapper.java
index 1c3fcf1..a80f515 100644
--- a/src/main/java/edu/isi/oba/Mapper.java
+++ b/src/main/java/edu/isi/oba/Mapper.java
@@ -1,14 +1,12 @@
package edu.isi.oba;
+import edu.isi.oba.config.CONFIG_FLAG;
import edu.isi.oba.config.YamlConfig;
+import static edu.isi.oba.Oba.logger;
+
import io.swagger.v3.oas.models.Paths;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.media.StringSchema;
-import org.semanticweb.owlapi.apibinding.OWLManager;
-import org.semanticweb.owlapi.io.FileDocumentSource;
-import org.semanticweb.owlapi.model.*;
-
-import static edu.isi.oba.Oba.logger;
import java.io.File;
import java.io.IOException;
@@ -19,6 +17,10 @@
import java.util.logging.Logger;
import java.util.stream.Collectors;
+import org.semanticweb.owlapi.apibinding.OWLManager;
+import org.semanticweb.owlapi.io.FileDocumentSource;
+import org.semanticweb.owlapi.model.*;
+
class Mapper {
public static final String DEFAULT_DIR_QUERY = "_default_";
public final Map schemaNames = new HashMap<>(); //URI-names of the schemas
@@ -32,24 +34,23 @@ class Mapper {
YamlConfig config_data;
public OWLOntologyManager manager = OWLManager.createOWLOntologyManager();
- private Boolean follow_references;
public Mapper(YamlConfig config_data) throws OWLOntologyCreationException, IOException {
this.config_data = config_data;
this.selected_paths = config_data.getPaths();
this.mappedClasses = new ArrayList<>();
- this.follow_references = config_data.getFollow_references();
List config_ontologies = config_data.getOntologies();
String destination_dir = config_data.getOutput_dir() + File.separator + config_data.getName();
File outputDir = new File(destination_dir);
- if (!outputDir.exists()){
+ if (!outputDir.exists()) {
outputDir.mkdirs();
}
+
//Load the ontology into the manager
int i = 0;
List ontologyPaths = new ArrayList<>();
- download_ontologies(config_ontologies, destination_dir, i, ontologyPaths);
+ this.download_ontologies(config_ontologies, destination_dir, i, ontologyPaths);
//set ontology paths in YAML to the ones we have downloaded (for later reference by owl2jsonld)
this.config_data.setOntologies(ontologyPaths);
ontologies = this.manager.ontologies().collect(Collectors.toList());
@@ -57,11 +58,13 @@ public Mapper(YamlConfig config_data) throws OWLOntologyCreationException, IOExc
//Create a temporal Map schemaNames with the classes
for (OWLOntology ontology : ontologies) {
Set classes = ontology.getClassesInSignature();
- setSchemaNames(classes);
- setSchemaDrescriptions(classes,ontology);
+ this.setSchemaNames(classes);
+ this.setSchemaDrescriptions(classes,ontology);
+ }
+
+ if (config_data.getClasses() != null) {
+ this.selected_classes = this.filter_classes();
}
- if (config_data.getClasses() != null)
- this.selected_classes = filter_classes();
}
private void download_ontologies(List config_ontologies, String destination_dir, int i, List ontologyPaths) throws OWLOntologyCreationException, IOException {
@@ -98,21 +101,19 @@ private void download_ontologies(List config_ontologies, String destinat
* The schemas includes the properties
*
* @param destination_dir directory to write the final results
- * @param config_data yaml configuration
*/
- public void createSchemas(String destination_dir, YamlConfig config_data) {
+ public void createSchemas(String destination_dir) {
Query query = new Query(destination_dir);
- Path pathGenerator = new Path(config_data.getEnable_get_paths(),
- config_data.getEnable_post_paths(),
- config_data.getEnable_put_paths(),
- config_data.getEnable_delete_paths(),
- config_data.getAuth().getEnable()
+ PathGenerator pathGenerator = new PathGenerator(this.config_data.getConfigFlags(),
+ this.config_data.getAuth().getEnable()
);
+
try {
query.get_all(DEFAULT_DIR_QUERY);
} catch (Exception e) {
logger.severe("Unable write the queries");
}
+
for (OWLOntology ontology : this.ontologies) {
OWLDocumentFormat format = ontology.getFormat();
@@ -121,22 +122,24 @@ public void createSchemas(String destination_dir, YamlConfig config_data) {
logger.severe("Unable to find the default prefix for the ontology");
System.exit(1);
}
- Set classes = ontology.getClassesInSignature();
+ Set classes = ontology.getClassesInSignature();
for (OWLClass cls : classes) {
//filter if the class prefix does not have the default ontology prefix
if (cls.getIRI() != null) {
- if (selected_classes == null || selected_classes.contains(cls)){
- add_owlclass_to_openapi(query, pathGenerator, ontology, defaultOntologyPrefixIRI, cls, true);
+ if (this.selected_classes == null || this.selected_classes.contains(cls)) {
+ this.add_owlclass_to_openapi(query, pathGenerator, ontology, defaultOntologyPrefixIRI, cls, true);
}
}
}
}
- if (this.config_data.getAuth().getEnable())
- add_user_path(pathGenerator);
+
+ if (this.config_data.getAuth().getEnable()) {
+ this.add_user_path(pathGenerator);
+ }
}
- private void add_user_path(Path pathGenerator) {
+ private void add_user_path(PathGenerator pathGenerator) {
//User schema
Map userProperties = new HashMap<>();
StringSchema username = new StringSchema();
@@ -153,51 +156,53 @@ private void add_user_path(Path pathGenerator) {
this.paths.addPathItem("/user/login", pathGenerator.user_login(userSchema.getName()));
}
- private List add_owlclass_to_openapi(Query query, Path pathGenerator, OWLOntology ontology,
+ private List add_owlclass_to_openapi(Query query, PathGenerator pathGenerator, OWLOntology ontology,
String defaultOntologyPrefixIRI, OWLClass cls, Boolean topLevel) {
List ref = new ArrayList<>();
String classPrefixIRI = cls.getIRI().getNamespace();
if (defaultOntologyPrefixIRI.equals(classPrefixIRI)) {
try{
MapperSchema mapperSchema = getMapperSchema(query, ontology, cls, this.schemaDescriptions.get(cls.getIRI()));
+
// add references to schemas in class restrictions (check selected classes to avoid conflicts)
for (String classToCheck : mapperSchema.getPropertiesFromObjectRestrictions_ranges()) {
OWLClass clsToCheck = manager.getOWLDataFactory().getOWLClass(IRI.create(classPrefixIRI + classToCheck));
- if (this.mappedClasses.contains(clsToCheck) || this.selected_classes.contains(clsToCheck)){
+ if (this.mappedClasses.contains(clsToCheck) || (this.selected_classes != null && this.selected_classes.contains(clsToCheck))){
logger.info("The class " + clsToCheck + " exists ");
} else {
//rare cases have instances, so we filter them out and recheck that the target is a class.
if(ontology.containsClassInSignature(clsToCheck.getIRI())) {
System.out.println("ADD "+ clsToCheck);
for (OWLOntology temp_ontology : this.ontologies) {
- if (follow_references) {
+ if (this.config_data.getConfigFlagValue(CONFIG_FLAG.FOLLOW_REFERENCES)) {
this.mappedClasses.add(clsToCheck);
- getMapperSchema(query, temp_ontology, clsToCheck, this.schemaDescriptions.get(clsToCheck.getIRI()));
- add_owlclass_to_openapi(query, pathGenerator, temp_ontology, classPrefixIRI, clsToCheck, false);
+ this.getMapperSchema(query, temp_ontology, clsToCheck, this.schemaDescriptions.get(clsToCheck.getIRI()));
+ this.add_owlclass_to_openapi(query, pathGenerator, temp_ontology, classPrefixIRI, clsToCheck, false);
}
}
}
}
}
+
// add references to schemas in property ranges
for (OWLClass ref_class : mapperSchema.getProperties_range()) {
if (this.mappedClasses.contains(ref_class)){
logger.info("The class " + ref_class + " exists ");
} else {
for (OWLOntology temp_ontology : this.ontologies) {
- if ( follow_references ) {
+ if (this.config_data.getConfigFlagValue(CONFIG_FLAG.FOLLOW_REFERENCES)) {
this.mappedClasses.add(ref_class);
- getMapperSchema(query, temp_ontology, ref_class,this.schemaDescriptions.get(ref_class.getIRI()));
-// OWLDocumentFormat format = ontology.getFormat();
-// String temp_defaultOntologyPrefixIRI = format.asPrefixOWLDocumentFormat().getDefaultPrefix();
- add_owlclass_to_openapi(query, pathGenerator, temp_ontology, classPrefixIRI, ref_class, false);
+ this.getMapperSchema(query, temp_ontology, ref_class,this.schemaDescriptions.get(ref_class.getIRI()));
+ this.add_owlclass_to_openapi(query, pathGenerator, temp_ontology, classPrefixIRI, ref_class, false);
}
}
}
}
+
//Add the OpenAPI paths
- if (topLevel)
+ if (topLevel) {
addOpenAPIPaths(pathGenerator, mapperSchema, cls);
+ }
}catch(Exception e){
logger.log(Level.SEVERE,"Could not parse class "+cls.getIRI().toString());
}
@@ -207,7 +212,7 @@ private List add_owlclass_to_openapi(Query query, Path pathGenerator,
private MapperSchema getMapperSchema(Query query, OWLOntology ontology, OWLClass cls, String cls_description) {
//Convert from OWL Class to OpenAPI Schema.
- MapperSchema mapperSchema = new MapperSchema(this.ontologies, cls, cls_description, schemaNames, ontology, follow_references);
+ MapperSchema mapperSchema = new MapperSchema(this.ontologies, cls, cls_description, schemaNames, ontology, this.config_data.getConfigFlags());
//Write queries
query.write_readme(mapperSchema.name);
//Create the OpenAPI schema
@@ -216,16 +221,17 @@ private MapperSchema getMapperSchema(Query query, OWLOntology ontology, OWLClass
return mapperSchema;
}
- private void addOpenAPIPaths(Path pathGenerator, MapperSchema mapperSchema, OWLClass cls) {
- if (selected_classes != null && !selected_classes.contains(cls))
+ private void addOpenAPIPaths(PathGenerator pathGenerator, MapperSchema mapperSchema, OWLClass cls) {
+ if (this.selected_classes != null && !this.selected_classes.contains(cls)) {
logger.info("Ignoring class " + cls.toString());
- else
- add_path(pathGenerator, mapperSchema);
+ } else {
+ this.add_path(pathGenerator, mapperSchema);
+ }
}
private void setSchemaNames(Set classes) {
for (OWLClass cls : classes) {
- schemaNames.put(cls.getIRI(), cls.getIRI().getShortForm());
+ this.schemaNames.put(cls.getIRI(), cls.getIRI().getShortForm());
}
}
@@ -235,14 +241,14 @@ private void setSchemaNames(Set classes) {
* @param classes the classes you want the description for
* @param ontology the ontology from where we will extract the descriptions
*/
- private void setSchemaDrescriptions(Set classes,OWLOntology ontology){
- for (OWLClass cls : classes) {
+ private void setSchemaDrescriptions(Set classes, OWLOntology ontology){
+ for (OWLClass cls: classes) {
System.out.println(cls);
- schemaDescriptions.put(cls.getIRI(), ObaUtils.getDescription(cls, ontology));
+ schemaDescriptions.put(cls.getIRI(), ObaUtils.getDescription(cls, ontology, this.config_data.getConfigFlagValue(CONFIG_FLAG.DEFAULT_DESCRIPTIONS)));
}
}
- private void add_path(Path pathGenerator, MapperSchema mapperSchema) {
+ private void add_path(PathGenerator pathGenerator, MapperSchema mapperSchema) {
String singular_name = "/" + mapperSchema.name.toLowerCase() + "s/{id}";
String plural_name = "/" + mapperSchema.name.toLowerCase() + "s";
//Create the plural paths: for example: /models/
diff --git a/src/main/java/edu/isi/oba/MapperDataProperty.java b/src/main/java/edu/isi/oba/MapperDataProperty.java
index cdfc631..38ca8d0 100644
--- a/src/main/java/edu/isi/oba/MapperDataProperty.java
+++ b/src/main/java/edu/isi/oba/MapperDataProperty.java
@@ -1,70 +1,66 @@
package edu.isi.oba;
+import static edu.isi.oba.Oba.logger;
+
import io.swagger.v3.oas.models.media.*;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import static edu.isi.oba.Oba.logger;
-
class MapperDataProperty {
- private final HashMap dataTypes;
-
- private void setDataTypes() {
- this.dataTypes.put("ENTITIES", "string");
- this.dataTypes.put("ENTITY", "string");
- this.dataTypes.put("ID", "string");
- this.dataTypes.put("IDREF", "string");
- this.dataTypes.put("IDREFS", "string");
- this.dataTypes.put("NCName", "string");
- this.dataTypes.put("NMTOKEN", "string");
- this.dataTypes.put("NMTOKENS", "string");
- this.dataTypes.put("NOTATION", "string");
- this.dataTypes.put("Name", "string");
- this.dataTypes.put("QName", "string");
- this.dataTypes.put("anySimpleType", "string");
- this.dataTypes.put("anyType", "string");
- this.dataTypes.put("anyURI", "string");
- this.dataTypes.put("base64Binary", "string");
- this.dataTypes.put("boolean", "boolean");
- this.dataTypes.put("byte", "integer");
- this.dataTypes.put("date", "string");
- this.dataTypes.put("dateTime", "dateTime");
- this.dataTypes.put("dateTimeStamp", "dateTime");
- this.dataTypes.put("decimal", "number");
- this.dataTypes.put("double", "number");
- this.dataTypes.put("duration", "string");
- this.dataTypes.put("float", "number");
- this.dataTypes.put("gDay", "string");
- this.dataTypes.put("gMonth", "string");
- this.dataTypes.put("gMonthYear", "string");
- this.dataTypes.put("gYear", "string");
- this.dataTypes.put("gYearMonth", "string");
- this.dataTypes.put("hexBinary", "string");
- this.dataTypes.put("int", "integer");
- this.dataTypes.put("integer", "integer");
- this.dataTypes.put("language", "string");
- this.dataTypes.put("long", "integer");
- this.dataTypes.put("negativeInteger", "integer");
- this.dataTypes.put("nonNegativeInteger", "integer");
- this.dataTypes.put("nonPositiveInteger", "integer");
- this.dataTypes.put("normalizedString", "string");
- this.dataTypes.put("positiveInteger", "integer");
- this.dataTypes.put("short", "integer");
- this.dataTypes.put("string", "string");
- this.dataTypes.put("time", "string");
- this.dataTypes.put("token", "string");
- this.dataTypes.put("unsignedByte", "integer");
- this.dataTypes.put("unsignedInt", "integer");
- this.dataTypes.put("unsignedLong", "integer");
- this.dataTypes.put("unsignedShort", "integer");
- this.dataTypes.put("langString", "string");
- this.dataTypes.put("Literal", "string");
-
- }
+ private final Map dataTypes = Map.ofEntries(
+ Map.entry("ENTITIES", "string"),
+ Map.entry("ENTITY", "string"),
+ Map.entry("ID", "string"),
+ Map.entry("IDREF", "string"),
+ Map.entry("IDREFS", "string"),
+ Map.entry("NCName", "string"),
+ Map.entry("NMTOKEN", "string"),
+ Map.entry("NMTOKENS", "string"),
+ Map.entry("NOTATION", "string"),
+ Map.entry("Name", "string"),
+ Map.entry("QName", "string"),
+ Map.entry("anySimpleType", "string"),
+ Map.entry("anyType", "string"),
+ Map.entry("anyURI", "string"),
+ Map.entry("base64Binary", "string"),
+ Map.entry("boolean", "boolean"),
+ Map.entry("byte", "integer"),
+ Map.entry("date", "string"),
+ Map.entry("dateTime", "dateTime"),
+ Map.entry("dateTimeStamp", "dateTime"),
+ Map.entry("decimal", "number"),
+ Map.entry("double", "number"),
+ Map.entry("duration", "string"),
+ Map.entry("float", "number"),
+ Map.entry("gDay", "string"),
+ Map.entry("gMonth", "string"),
+ Map.entry("gMonthYear", "string"),
+ Map.entry("gYear", "string"),
+ Map.entry("gYearMonth", "string"),
+ Map.entry("hexBinary", "string"),
+ Map.entry("int", "integer"),
+ Map.entry("integer", "integer"),
+ Map.entry("language", "string"),
+ Map.entry("long", "integer"),
+ Map.entry("negativeInteger", "integer"),
+ Map.entry("nonNegativeInteger", "integer"),
+ Map.entry("nonPositiveInteger", "integer"),
+ Map.entry("normalizedString", "string"),
+ Map.entry("positiveInteger", "integer"),
+ Map.entry("short", "integer"),
+ Map.entry("string", "string"),
+ Map.entry("time", "string"),
+ Map.entry("token", "string"),
+ Map.entry("unsignedByte", "integer"),
+ Map.entry("unsignedInt", "integer"),
+ Map.entry("unsignedLong", "integer"),
+ Map.entry("unsignedShort", "integer"),
+ Map.entry("langString", "string"),
+ Map.entry("Literal", "string")
+ );
- private String getDataType(String key){
+ private String getDataType(String key) {
return this.dataTypes.get(key);
}
@@ -83,10 +79,7 @@ private String getDataType(String key){
private Map restrictions;
private List valuesFromDataRestrictions_ranges;
-
- public MapperDataProperty(String name, String description, Boolean isFunctional,Map restrictions,List valuesFromDataRestrictions_ranges, List type, Boolean array, Boolean nullable) {
- this.dataTypes = new HashMap<>();
- this.setDataTypes();
+ public MapperDataProperty(String name, String description, Boolean isFunctional, Map restrictions, List valuesFromDataRestrictions_ranges, List type, Boolean array, Boolean nullable) {
this.name = name;
this.description = description;
this.type = type;
@@ -97,33 +90,33 @@ public MapperDataProperty(String name, String description, Boolean isFunctional,
this.valuesFromDataRestrictions_ranges=valuesFromDataRestrictions_ranges;
}
- public Schema getSchemaByDataProperty(){
+ public Schema getSchemaByDataProperty() {
- if (this.type.size() == 0) {
- return (array) ? arraySchema(new StringSchema(), nullable) : new StringSchema().nullable(nullable).description(description);
- }
- else if (this.type.size() > 1){
- return (array) ? composedSchema(this.type, nullable) : new Schema().nullable(nullable).description(description);
+ if (this.type.isEmpty()) {
+ return (this.array) ? this.arraySchema(new StringSchema()) : this.nonArraySchema(new StringSchema());
+ } else if (this.type.size() > 1) {
+ return (this.array) ? this.composedSchema() : this.nonArraySchema(new Schema());
}
String schemaType = getDataType(this.type.get(0));
- if (schemaType == null){
+ if (schemaType == null) {
logger.severe("property " + this.name + " type " + this.type);
}
+
switch (schemaType) {
case STRING_TYPE:
- return (array) ? arraySchema(new StringSchema(), nullable) : new StringSchema().nullable(nullable).description(description);
+ return (this.array) ? this.arraySchema(new StringSchema()) : this.nonArraySchema(new StringSchema());
case NUMBER_TYPE:
- return (array) ? arraySchema(new NumberSchema(), nullable) : new NumberSchema().nullable(nullable).description(description);
+ return (this.array) ? this.arraySchema(new NumberSchema()) : this.nonArraySchema(new NumberSchema());
case INTEGER_TYPE:
- return (array) ? arraySchema(new IntegerSchema(), nullable) : new IntegerSchema().nullable(nullable).description(description);
+ return (this.array) ? this.arraySchema(new IntegerSchema()) : this.nonArraySchema(new IntegerSchema());
case BOOLEAN_TYPE:
- return (array) ? arraySchema(new BooleanSchema(), nullable) : new BooleanSchema().nullable(nullable).description(description);
+ return (this.array) ? this.arraySchema(new BooleanSchema()) : this.nonArraySchema(new BooleanSchema());
case DATETIME_TYPE:
- return (array) ? arraySchema(new DateTimeSchema() , nullable) : new DateTimeSchema().nullable(nullable).description(description);
+ return (this.array) ? this.arraySchema(new DateTimeSchema()) : this.nonArraySchema(new DateTimeSchema());
default:
logger.warning("datatype mapping failed " + this.type.get(0));
- return (array) ? arraySchema(new Schema(), nullable) : new Schema().nullable(nullable).description(description);
+ return (this.array) ? this.arraySchema(new Schema()) : this.nonArraySchema(new Schema());
}
}
@@ -132,42 +125,54 @@ else if (this.type.size() > 1){
*
* @return An ArraySchema: including a composedSchema with a list of items for anyOf, allOf restrictions.
*/
- private ArraySchema composedSchema(List base, boolean nullable){
+ private ArraySchema composedSchema() {
ArraySchema array = new ArraySchema();
- Schema schema ;
- ComposedSchema composedSchema = new ComposedSchema() ;
+ Schema schema;
+ ComposedSchema composedSchema = new ComposedSchema();
array.setDescription(description);
- array.setNullable(nullable);
+ array.setNullable(this.nullable);
+
// Operations for managing boolean combinations
- for (String restriction: restrictions.keySet()) {
- String value = restrictions.get(restriction);
- for (String item:base) {
- switch (getDataType(item)) {
+ for (String restriction: this.restrictions.keySet()) {
+ String value = this.restrictions.get(restriction);
+ for (String item: this.type) {
+ switch (this.getDataType(item)) {
case STRING_TYPE:
schema = new StringSchema();
- if (item.equals("anyURI"))
- schema.format("uri");
- else if (item.equals("byte"))
- schema.format("byte");
- break ;
+
+ if (item.equals("anyURI")) {
+ schema.format("uri");
+ } else if (item.equals("byte")) {
+ schema.format("byte");
+ }
+
+ break;
case NUMBER_TYPE:
schema = new NumberSchema();
- if (item.equals("float"))
- schema.format("float");
- else if (item.equals("double"))
- schema.format("double");
- break ;
+
+ if (item.equals("float")) {
+ schema.format("double");
+ } else if (item.equals("double")) {
+ schema.format("double");
+ } else {
+ schema.format("number");
+ }
+
+ break;
case INTEGER_TYPE:
schema = new IntegerSchema();
- if (item.equals("long"))
- schema.format("int64");
- break ;
+
+ if (item.equals("long")) {
+ schema.format("int64");
+ }
+
+ break;
case BOOLEAN_TYPE:
schema = new BooleanSchema();
- break ;
+ break;
case DATETIME_TYPE:
schema = new DateTimeSchema();
- break ;
+ break;
default:
logger.warning("datatype mapping failed " + this.type.get(0));
schema = new Schema();
@@ -175,13 +180,17 @@ else if (item.equals("double"))
switch (restriction) {
case "unionOf":
- if (value=="someValuesFrom")
- nullable=false;
+ if (value == "someValuesFrom") {
+ this.nullable = false;
+ }
+
composedSchema.addAnyOfItem(schema);
break;
case "intersectionOf":
- if (value=="someValuesFrom")
- nullable=false;
+ if (value == "someValuesFrom") {
+ this.nullable = false;
+ }
+
composedSchema.addAllOfItem(schema);
break;
default:
@@ -189,66 +198,102 @@ else if (item.equals("double"))
}
}
}
- array.setItems(composedSchema);
- if (isFunctional)
- array.setMaxItems(1);
- array.setNullable(nullable);
- return array ;
+ array.setItems(composedSchema);
+ array.setNullable(this.nullable);
+
+ if (isFunctional) {
+ array.setMaxItems(1);
+ }
+
+ return array;
+ }
+
+ private Schema nonArraySchema(Schema base) {
+ base.setDescription(this.description);
+ base.setNullable(this.nullable);
+
+ return this.getSchemaRestrictions(base);
}
- private ArraySchema arraySchema(Schema base, boolean nullable) {
+ private ArraySchema arraySchema(Schema base) {
ArraySchema array = new ArraySchema();
- array.setDescription(description);
+ array.setDescription(this.description);
+
+ if (this.isFunctional) {
+ array.setMaxItems(1);
+ }
+
+ if (this.restrictions.containsKey("complementOf")) {
+ Schema schema = new Schema();
+ Schema complementOf = new Schema();
+ complementOf.setType(this.getDataType(this.type.get(0)));
+ complementOf.setFormat(this.type.get(0));
+ schema.setNot(complementOf);
+ array.setNullable(this.nullable);
+ array.setItems(schema);
+ return array;
+ }
- if (isFunctional)
- array.setMaxItems(1);
-
- for (String restriction: restrictions.keySet()) {
- String value = restrictions.get(restriction);
- switch (restriction) {
- case "dataHasValue":
- base.setDefault(value);
- break;
- case "maxCardinality":
- base.setMaxItems(Integer.parseInt(value));
- break ;
- case "minCardinality":
- base.setMinItems(Integer.parseInt(value));
- break ;
- case "exactCardinality":
- base.setMaxItems(Integer.parseInt(value));
- base.setMinItems(Integer.parseInt(value));
- break ;
- case "someValuesFrom":
- nullable=false;
- break ;
- case "allValuesFrom":
- //nothing to do
- break ;
- case "oneOf":
- if (value=="someValuesFrom")
- nullable=false;
- for (String rangeValue:valuesFromDataRestrictions_ranges)
- base.addEnumItemObject(rangeValue);
- break;
- case "complementOf":
- Schema schema = new Schema();
- Schema complementOf = new Schema();
- complementOf.setType(getDataType(type.get(0)));
- complementOf.setFormat(type.get(0));
- schema.setNot(complementOf);
- array.setNullable(nullable);
- array.setItems(schema);
- return array;
- default:
- }
- }
-
- array.setNullable(nullable);
+ base = this.getSchemaRestrictions(base);
+
+ // Can this be done in a better way?
+ Integer minItemsInteger = base.getMinItems();
+ if (minItemsInteger != null) {
+ base.setMinItems(null);
+ array.setMinItems(minItemsInteger);
+ }
+
+ // Can this be done in a better way?
+ Integer maxItemsInteger = base.getMaxItems();
+ if (maxItemsInteger != null) {
+ base.setMaxItems(null);
+ array.setMaxItems(maxItemsInteger);
+ }
+
+ array.setNullable(this.nullable);
array.setItems(base);
return array;
}
+ private Schema getSchemaRestrictions(Schema base) {
+ for (String restriction: this.restrictions.keySet()) {
+ String value = restrictions.get(restriction);
+ switch (restriction) {
+ case "dataHasValue":
+ base.setDefault(value);
+ break;
+ case "maxCardinality":
+ base.setMaxItems(Integer.parseInt(value));
+ break;
+ case "minCardinality":
+ base.setMinItems(Integer.parseInt(value));
+ break;
+ case "exactCardinality":
+ base.setMaxItems(Integer.parseInt(value));
+ base.setMinItems(Integer.parseInt(value));
+ break;
+ case "someValuesFrom":
+ this.nullable = false;
+ break;
+ case "allValuesFrom":
+ //nothing to do
+ break;
+ case "oneOf":
+ if (value == "someValuesFrom") {
+ this.nullable = false;
+ }
+
+ for (String rangeValue: this.valuesFromDataRestrictions_ranges) {
+ base.addEnumItemObject(rangeValue);
+ }
+
+ break;
+ default:
+ }
+ }
+
+ return base;
+ }
}
diff --git a/src/main/java/edu/isi/oba/MapperObjectProperty.java b/src/main/java/edu/isi/oba/MapperObjectProperty.java
index 9ddc74c..52bbaf5 100644
--- a/src/main/java/edu/isi/oba/MapperObjectProperty.java
+++ b/src/main/java/edu/isi/oba/MapperObjectProperty.java
@@ -1,11 +1,13 @@
package edu.isi.oba;
-import io.swagger.v3.oas.models.media.*;
-
import static edu.isi.oba.Oba.logger;
+import io.swagger.v3.oas.models.media.*;
+
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.stream.Collectors;
class MapperObjectProperty {
final String name;
@@ -23,7 +25,7 @@ public MapperObjectProperty(String name, String description, Boolean isFunctiona
this.ref = ref;
this.array = true;
this.nullable = true;
- this.isFunctional=isFunctional;
+ this.isFunctional = isFunctional;
this.restrictions = restrictions;
}
@@ -33,148 +35,196 @@ public MapperObjectProperty(String name, String description, Boolean isFunction
this.ref = ref;
this.array = array;
this.nullable = nullable;
- this.isFunctional=isFunctional;
+ this.isFunctional = isFunctional;
this.restrictions = restrictions;
}
- public Schema getSchemaByObjectProperty(){
- if (this.ref.size() == 0){
- return getComposedSchemaObject(this.ref, array, nullable);
+ public Schema getSchemaByObjectProperty() {
+ if (this.ref.isEmpty()){
+ return getComposedSchemaObject(this.ref, this.array, this.nullable);
}
if (this.ref.size() > 1){
- return getComposedSchemaObject(this.ref, array, nullable);
- }
- else {
- return getObjectPropertiesByRef(this.ref.get(0), array, nullable);
+ return getComposedSchemaObject(this.ref, this.array, this.nullable);
+ } else {
+ return getObjectPropertiesByRef(this.ref.get(0), this.array, this.nullable);
}
}
- private Schema getObjectPropertiesByRef(String ref, boolean array, boolean nullable){
- Schema object = new ObjectSchema();
- object.setDescription(description);
-
- if (array) {
+ private Schema getObjectPropertiesByRef(String ref, boolean isArray, boolean isNullable) {
+ if (this.restrictions.isEmpty()) {
+ Schema object = new ObjectSchema();
object.set$ref(ref);
- ArraySchema objects = new ArraySchema();
- objects.setDescription(description);
- if (isFunctional)
+
+ if (isArray) {
+ ArraySchema objects = new ArraySchema();
+ objects.setDescription(this.description);
+ objects.setNullable(isNullable);
+ objects.setItems(object);
+
+ if (this.isFunctional) {
objects.setMaxItems(1);
-
- for (String restriction: restrictions.keySet()) {
- String value = restrictions.get(restriction);
+ }
+
+ return objects;
+ } else {
+ object.setDescription(this.description);
+ object.setNullable(isNullable);
+ object.setType("object");
+
+ if (this.isFunctional) {
+ object.setMaxItems(1);
+ }
+
+ return object;
+ }
+ }
+
+ ArraySchema objects = new ArraySchema();
+ objects.setType("array");
+
+ // For OpenAPI v3.0, "$ref" cannot be used as a sibling with "default".
+ // see: https://swagger.io/docs/specification/using-ref/
+ // see: https://stackoverflow.com/a/77189463
+ // A workaround is to include both within "items" and as separate entries under "allOf".
+ // TODO: version check here (and elsewhere?) to differentiate the schema structure. For v3.1+, it can support "$ref" and "default" as siblings.
+ ArraySchema allOfItems = new ArraySchema();
+ allOfItems.setType(null);
+
+ for (String restriction: this.restrictions.keySet()) {
+ String value = this.restrictions.get(restriction);
+
switch (restriction) {
- case "maxCardinality":
- objects.setMaxItems(Integer.parseInt(value));
- break ;
- case "minCardinality":
- objects.setMinItems(Integer.parseInt(value));
- break ;
- case "exactCardinality":
- objects.setMaxItems(Integer.parseInt(value));
- objects.setMinItems(Integer.parseInt(value));
- break ;
- case "someValuesFrom":
- nullable=false;
- break ;
- case "allValuesFrom":
- //nothing to do in the Schema
- break ;
- default:
- break ;
- }
- }
- objects.setNullable(nullable);
- objects.setItems(object);
- return objects;
+ case "maxCardinality":
+ objects.setMaxItems(Integer.parseInt(value));
+ break;
+ case "minCardinality":
+ objects.setMinItems(Integer.parseInt(value));
+ break;
+ case "exactCardinality":
+ objects.setMaxItems(Integer.parseInt(value));
+ objects.setMinItems(Integer.parseInt(value));
+ break;
+ case "someValuesFrom":
+ isNullable = false;
+ break;
+ case "allValuesFrom":
+ //nothing to do in the Schema
+ break;
+ case "objectHasReference": {
+ Schema object = new ObjectSchema();
+ object.set$ref(value);
+ object.setType(null);
+ allOfItems.addAllOfItem(object);
+ break;
+ }
+ case "objectHasValue": {
+ Schema object = new ObjectSchema();
+ object.setDefault(value);
+ object.setType("string");
+ allOfItems.addAllOfItem(object);
+ break;
+ }
+ default:
+ break;
+ }
}
- else {
- for (String restriction: restrictions.keySet()) {
- String value = restrictions.get(restriction);
- if (restriction=="objectHasValue") {
- object.setDefault(value);
- object.type("string");
- object.format("uri");
- return object;
- }
- }
- return object;
+
+ if (allOfItems.getAllOf() == null || allOfItems.getAllOf().isEmpty()) {
+ Schema object = new ObjectSchema();
+ object.set$ref(ref);
+ objects.items(object);
+ } else {
+ objects.items(allOfItems);
}
-
+ if (this.isFunctional) {
+ objects.setMaxItems(1);
+ }
+
+ objects.setNullable(isNullable);
+
+ return objects;
}
- private Schema getComposedSchemaObject(List refs, boolean array, boolean nullable){
+
+ private Schema getComposedSchemaObject(List refs, boolean array, boolean nullable) {
Schema object = new ObjectSchema();
- ComposedSchema composedSchema = new ComposedSchema() ;
+ ComposedSchema composedSchema = new ComposedSchema();
object.setType("object");
- object.setDescription(description);
+ object.setDescription(this.description);
- if (array) {
+ if (array && !this.restrictions.isEmpty()) {
ArraySchema objects = new ArraySchema();
- objects.setDescription(description);
+ objects.setDescription(this.description);
- if (isFunctional)
+ if (this.isFunctional) {
objects.setMaxItems(1);
+ }
+
+ for (String restriction: this.restrictions.keySet()) {
+ String value = this.restrictions.get(restriction);
- for (String restriction: restrictions.keySet()) {
- String value = restrictions.get(restriction);
+ // In some cases, the duplicate reference may have been added to the list. We only need to create one $ref item to it.
+ LinkedHashSet uniqueRefs = refs.stream().collect(Collectors.toCollection(LinkedHashSet::new));
- for (String item:refs) {
+ for (String item: uniqueRefs) {
Schema objectRange = new ObjectSchema();
objectRange.setType("object");
objectRange.set$ref(item);
+
switch (restriction) {
case "unionOf":
- if (value=="someValuesFrom")
- nullable=false;
+ if ("someValuesFrom".equals(value)) {
+ nullable=false;
+ }
+
composedSchema.addAnyOfItem(objectRange);
objects.setItems(composedSchema);
- break ;
+ break;
case "intersectionOf":
- if (value=="someValuesFrom")
- nullable=false;
+ if ("someValuesFrom".equals(value)) {
+ nullable = false;
+ }
+
composedSchema.addAllOfItem(objectRange);
objects.setItems(composedSchema);
- break ;
- case "someValuesFrom":
+ break;
+ case "someValuesFrom":
nullable=false;
+ composedSchema.addAnyOfItem(objectRange);
+ objects.setItems(composedSchema);
break;
- case "allValuesFrom":
+ case "allValuesFrom":
//nothing to do in the Schema
- break ;
- case "oneOf":
- if (value=="someValuesFrom")
- nullable=false;
- composedSchema.addEnumItemObject(item);
- composedSchema.setType("string");
- composedSchema.setFormat("uri");
- objects.setItems(composedSchema);
- break;
+ break;
+ case "oneOf":
+ if (value=="someValuesFrom") {
+ nullable=false;
+ }
+
+ composedSchema.addEnumItemObject(item);
+ composedSchema.setType("string");
+ composedSchema.setFormat("uri");
+ objects.setItems(composedSchema);
+ break;
default:
//if the property range is complex it will be omitted
- logger.warning("omitted complex restriction");
- objects.setItems(object);
- }
+ logger.warning("omitted complex restriction");
+ objects.setItems(object);
+ }
}
- }
- if (refs.size() == 0)
- objects.setItems(object);
- objects.setNullable(nullable);
+ }
+
+ if (refs.isEmpty()) {
+ objects.setItems(object);
+ }
+ objects.setNullable(nullable);
+
return objects;
- }
- else {
+ } else {
+ object.setNullable(nullable);
return object;
}
}
-
- private ArraySchema arraySchema(Schema base, boolean nullable) {
- ArraySchema array = new ArraySchema();
- array.setNullable(nullable);
- array.setItems(base);
- if (isFunctional)
- array.setMaxItems(1);
- return array;
- }
-
}
diff --git a/src/main/java/edu/isi/oba/MapperOperation.java b/src/main/java/edu/isi/oba/MapperOperation.java
index 7b9d7a5..4cc4b89 100644
--- a/src/main/java/edu/isi/oba/MapperOperation.java
+++ b/src/main/java/edu/isi/oba/MapperOperation.java
@@ -2,7 +2,6 @@
import io.swagger.models.Method;
import io.swagger.v3.oas.models.Operation;
-import io.swagger.v3.oas.models.headers.Header;
import io.swagger.v3.oas.models.media.*;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.parameters.PathParameter;
@@ -30,14 +29,12 @@ class MapperOperation {
private final ApiResponses apiResponses = new ApiResponses();
private final Cardinality cardinality;
private final Schema schema;
+ private final Operation operation;
public Operation getOperation() {
return operation;
}
- private final Operation operation;
-
-
public MapperOperation(String schemaName, String schemaURI, Method method, Cardinality cardinality, Boolean auth) {
this.auth = auth;
this.cardinality = cardinality;
@@ -50,6 +47,9 @@ public MapperOperation(String schemaName, String schemaURI, Method method, Cardi
case GET:
setOperationGet();
break;
+ case PATCH:
+ setOperationPatch();
+ break;
case PUT:
setOperationPut();
break;
@@ -59,7 +59,8 @@ public MapperOperation(String schemaName, String schemaURI, Method method, Cardi
case DELETE:
setOperationDelete();
break;
-
+ default:
+ break;
}
if (cardinality == Cardinality.SINGULAR){
@@ -70,13 +71,14 @@ public MapperOperation(String schemaName, String schemaURI, Method method, Cardi
.schema(new StringSchema()));
}
- if (auth && (method == Method.PUT || method == Method.POST || method == Method.DELETE )) {
+ if (auth && Set.of(Method.PATCH, Method.PUT, Method.POST, Method.DELETE).contains(method)) {
parameters.add(new QueryParameter()
.description("Username")
.name("user")
.required(false)
.schema(new StringSchema()));
}
+
operation = new Operation()
.description(description)
.summary(summary)
@@ -84,18 +86,15 @@ public MapperOperation(String schemaName, String schemaURI, Method method, Cardi
.parameters(parameters)
.responses(apiResponses);
-
- if (method == Method.PUT || method == Method.POST ){
+ if (Set.of(Method.PATCH, Method.PUT, Method.POST).contains(method)) {
operation.setRequestBody(requestBody);
}
-
- if (method == Method.PUT || method == Method.POST || method == Method.DELETE ){
+ if (Set.of(Method.PATCH, Method.PUT, Method.POST, Method.DELETE).contains(method)) {
SecurityRequirement securityRequirement = new SecurityRequirement();
securityRequirement.addList("BearerAuth");
operation.addSecurityItem(securityRequirement);
}
-
}
private void setOperationGet() {
@@ -113,7 +112,7 @@ private void setOperationGet() {
case PLURAL:
summary = "List all instances of " + this.schemaName;
description = "Gets a list of all instances of " + this.schemaName +
- " (more information in " +this.schemaURI+")";
+ " (more information in " + this.schemaURI + ")";
responseDescriptionOk = "Successful response - returns an array with the instances of " + schemaName + ".";
//Set response
@@ -140,9 +139,9 @@ private void setOperationGet() {
.schema(new IntegerSchema()._default(100).maximum(BigDecimal.valueOf(200)).minimum(BigDecimal.valueOf(1))));
break;
case SINGULAR:
- summary = "Get a single " + this.schemaName +" by its id";
- description = "Gets the details of a given " + this.schemaName+
- " (more information in " +this.schemaURI+")";
+ summary = "Get a single " + this.schemaName + " by its id";
+ description = "Gets the details of a given " + this.schemaName +
+ " (more information in " + this.schemaURI + ")";
responseDescriptionOk = "Gets the details of a given " + schemaName;
//Set request
@@ -153,7 +152,10 @@ private void setOperationGet() {
break;
}
+ }
+ private void setOperationPatch() {
+ // TODO: implement
}
private void setOperationPost() {
@@ -177,13 +179,12 @@ private void setOperationPost() {
);
}
-
private void setOperationPut() {
- String requestDescription = "An old " + this.schemaName + "to be updated";
+ String requestDescription = "An old " + this.schemaName + " to be updated";
summary = "Update an existing " + this.schemaName;
- description = "Updates an existing " + this.schemaName+
- " (more information in " +this.schemaURI+")";
+ description = "Updates an existing " + this.schemaName +
+ " (more information in " + this.schemaURI + ")";
//Set request
MediaType mediaType = new MediaType().schema(schema);
@@ -199,14 +200,12 @@ private void setOperationPut() {
)
.addApiResponse("404", new ApiResponse()
.description("Not Found"));
-
}
-
private void setOperationDelete() {
summary = "Delete an existing " + this.schemaName;
- description = "Delete an existing " + this.schemaName+
- " (more information in " +this.schemaURI+")";
+ description = "Delete an existing " + this.schemaName +
+ " (more information in " + this.schemaURI + ")";
//Set the response
apiResponses
@@ -214,7 +213,5 @@ private void setOperationDelete() {
.description("Deleted"))
.addApiResponse("404", new ApiResponse()
.description("Not Found"));
-
}
-
}
diff --git a/src/main/java/edu/isi/oba/MapperSchema.java b/src/main/java/edu/isi/oba/MapperSchema.java
index 75d784f..681e774 100644
--- a/src/main/java/edu/isi/oba/MapperSchema.java
+++ b/src/main/java/edu/isi/oba/MapperSchema.java
@@ -1,21 +1,23 @@
package edu.isi.oba;
+import edu.isi.oba.config.CONFIG_FLAG;
+import static edu.isi.oba.Oba.logger;
import io.swagger.v3.oas.models.examples.Example;
import io.swagger.v3.oas.models.media.ObjectSchema;
import io.swagger.v3.oas.models.media.Schema;
+
+import java.util.*;
+
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.*;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import org.semanticweb.owlapi.reasoner.OWLReasonerFactory;
import org.semanticweb.owlapi.reasoner.structural.StructuralReasonerFactory;
+import org.semanticweb.owlapi.search.EntitySearcher;
import org.semanticweb.owlapi.util.IRIShortFormProvider;
import org.semanticweb.owlapi.util.SimpleIRIShortFormProvider;
-import java.util.*;
-
-import static edu.isi.oba.Oba.logger;
-
class MapperSchema {
private final OWLReasoner reasoner;
@@ -27,13 +29,16 @@ class MapperSchema {
private Map dataProperties;
private Map objectProperties;
private Map properties;
+ private List required_properties;
+ private Map> enums;
final String name;
private final Map schemaNames;
private final Schema schema;
private OWLOntology ontology_cls;
private OWLReasonerFactory reasonerFactory;
public List properties_range;
- private boolean follow_references;
+
+ private final Map configFlags = new HashMap<>();
public List propertiesFromObjectRestrictions;
public Map> propertiesFromObjectRestrictions_ranges;
@@ -42,67 +47,85 @@ class MapperSchema {
public Map> propertiesFromDataRestrictions_ranges;
public List getProperties_range() {
- return properties_range;
+ return this.properties_range;
}
- public List getPropertiesFromObjectRestrictions_ranges(){
+ public List getPropertiesFromObjectRestrictions_ranges() {
List aggregatedClasses = new ArrayList<>();
- for (List l : propertiesFromObjectRestrictions_ranges.values()){
+ for (List l: this.propertiesFromObjectRestrictions_ranges.values()) {
aggregatedClasses.addAll(l);
}
+
return aggregatedClasses;
}
public Schema getSchema() {
- return schema;
+ return this.schema;
}
- public MapperSchema(List ontologies, OWLClass cls, String clsDescription, Map schemaNames, OWLOntology class_ontology, Boolean follow_references) {
+ public MapperSchema(List ontologies, OWLClass cls, String clsDescription, Map schemaNames, OWLOntology class_ontology, Map configFlags) {
this.schemaNames = schemaNames;
- this.follow_references = follow_references;
+ this.configFlags.putAll(configFlags);
this.cls = cls;
this.cls_description = clsDescription;
this.type = "object";
this.ontologies = ontologies;
this.ontology_cls = class_ontology;
- reasonerFactory = new StructuralReasonerFactory();
+ this.reasonerFactory = new StructuralReasonerFactory();
this.reasoner = reasonerFactory.createReasoner(this.ontology_cls);
- properties_range = new ArrayList<>();
- propertiesFromObjectRestrictions_ranges= new HashMap<>();
- propertiesFromObjectRestrictions = new ArrayList<>();
- propertiesFromDataRestrictions_ranges= new HashMap<>();
- propertiesFromDataRestrictions = new ArrayList<>();
- properties = new HashMap<>();
- this.complementOf="";
+ this.properties_range = new ArrayList<>();
+ this.propertiesFromObjectRestrictions_ranges = new HashMap<>();
+ this.propertiesFromObjectRestrictions = new ArrayList<>();
+ this.propertiesFromDataRestrictions_ranges = new HashMap<>();
+ this.propertiesFromDataRestrictions = new ArrayList<>();
+ this.properties = new HashMap<>();
+ this.required_properties = new ArrayList<>();
+ this.complementOf = "";
this.getClassRestrictions(cls);
this.name = getSchemaName(cls);
this.schema = setSchema();
}
private Map setProperties() {
- dataProperties = this.getDataProperties();
- objectProperties = this.getObjectProperties();
- return properties;
+ this.dataProperties = this.getDataProperties();
+ this.objectProperties = this.getObjectProperties();
+ return this.properties;
}
private Schema setSchema() {
Schema schema = new Schema();
schema.setName(this.name);
schema.setDescription(this.cls_description);
- schema.setType(this.type);
- // if the Schema is the complement of other Schema
- if (complementOf!="") {
- Schema complement = new ObjectSchema();
- complement.set$ref(complementOf);
- schema.not(complement);
- }
- schema.setProperties(this.getProperties());
- HashMap exampleMap = new HashMap<>();
- exampleMap.put("id", "some_id");
- Example example = new Example();
- example.setValue(exampleMap);
- schema.setExample(example);
+ if (this.enums.containsKey(this.cls.getIRI())) {
+ // Only string enums allowed in RDF/OWL ??
+ schema.setType("string");
+ schema.setEnum(this.enums.get(this.cls.getIRI()));
+ } else {
+ // if the Schema is the complement of other Schema
+ if (complementOf!="") {
+ Schema complement = new ObjectSchema();
+ complement.set$ref(complementOf);
+ schema.not(complement);
+ }
+ schema.setType(this.type);
+ schema.setProperties(this.getProperties());
+
+ if (this.configFlags.containsKey(CONFIG_FLAG.REQUIRED_PROPERTIES_FROM_CARDINALITY)
+ && this.configFlags.get(CONFIG_FLAG.REQUIRED_PROPERTIES_FROM_CARDINALITY)) {
+ schema.setRequired(this.required_properties);
+ }
+
+ HashMap exampleMap = new HashMap<>();
+ exampleMap.put("id", "some_id");
+ Example example = new Example();
+ example.setValue(exampleMap);
+ schema.setExample(example);
+ ArrayList examples = new ArrayList();
+ examples.add(example);
+ schema.setExamples(examples);
+ }
+
return schema;
}
@@ -114,11 +137,12 @@ private Schema setSchema() {
* @return true or false
*/
private boolean checkDomainClass(OWLClass cls, OWLPropertyDomainAxiom dp) {
- Set superDomainClasses = reasoner.getSuperClasses(cls, false).getFlattened();
+ Set superDomainClasses = this.reasoner.getSuperClasses(cls, false).getFlattened();
Set domainClasses = dp.getDomain().getClassesInSignature();
for (OWLClass domainClass : domainClasses) {
- if (domainClass.equals(cls))
- return true;
+ if (domainClass.equals(cls)) {
+ return true;
+ }
//check super classes
for (OWLClass superClass : superDomainClasses) {
@@ -127,10 +151,10 @@ private boolean checkDomainClass(OWLClass cls, OWLPropertyDomainAxiom dp) {
}
}
}
+
return false;
}
-
-
+
/**
* Obtain a list of Codegenproperty of a OWLClass
*
@@ -145,11 +169,12 @@ private Map getDataProperties() {
Set properties_class = new HashSet<>();
Set functional;
- for (OWLOntology ontology : ontologies)
+ for (OWLOntology ontology: this.ontologies) {
properties_class.addAll(ontology.getAxioms(AxiomType.DATA_PROPERTY_DOMAIN));
+ }
for (OWLDataPropertyDomainAxiom dp : properties_class) {
- if (checkDomainClass(cls, dp)) {
+ if (checkDomainClass(this.cls, dp)) {
for (OWLDataProperty odp : dp.getDataPropertiesInSignature()) {
Boolean array = true;
Boolean nullable = true;
@@ -160,36 +185,32 @@ private Map getDataProperties() {
// the data property has been previously analyzed on the getClassRestrictions function.
// If the property was analyzed, we will change the value of inspect to false, otherwise
// the property will be inspected.
- if (propertiesFromDataRestrictions.size() != 0) {
+ if (!propertiesFromDataRestrictions.isEmpty()) {
if (propertiesFromDataRestrictions.contains(odp)) {
- inspect=false;
+ inspect = false;
}
- }
+ }
+
if (inspect) {
- Boolean isFunctional=false;
- for (OWLOntology ontology : ontologies) {
+ boolean isFunctional = EntitySearcher.isFunctional(odp, this.ontologies.stream());
+
+ for (OWLOntology ontology: this.ontologies) {
ranges.addAll(ontology.getDataPropertyRangeAxioms(odp));
- functional = ontology.getAxioms(AxiomType.FUNCTIONAL_DATA_PROPERTY);
- for (OWLFunctionalDataPropertyAxiom functionalAxiom:functional) {
- if (functionalAxiom.getProperty().equals(odp))
- isFunctional = true;
- }
}
- if (ranges.size() == 0)
+
+ if (ranges.isEmpty()) {
logger.warning("Property " + odp.getIRI() + " has range equals zero");
+ }
String propertyName = this.sfp.getShortForm(odp.getIRI());
String propertyURI = odp.getIRI().toString();
propertyNameURI.put(propertyURI, propertyName);
//obtain type using the range
- List propertyRanges = getCodeGenTypesByRangeData(ranges, odp);
- String propertyDescription = ObaUtils.getDescription(odp, ontology_cls);
List valuesFromDataRestrictions_ranges = new ArrayList();
-
- Map restrictionValues = new HashMap() ;
- for (OWLOntology ontology : ontologies) {
- RestrictionVisitor restrictionVisitor = new RestrictionVisitor(cls,ontology,owlThing,propertyName);
+ Map restrictionValues = new HashMap();
+ for (OWLOntology ontology: this.ontologies) {
+ RestrictionVisitor restrictionVisitor = new RestrictionVisitor(this.cls, ontology, owlThing, propertyName);
for (OWLDataPropertyRangeAxiom propertyRangeAxiom : ranges) {
OWLDataRange ce = propertyRangeAxiom.getRange();
ce.accept(restrictionVisitor);
@@ -205,7 +226,9 @@ private Map getDataProperties() {
}
}
- MapperDataProperty mapperProperty = new MapperDataProperty(propertyName, propertyDescription, isFunctional, restrictionValues,valuesFromDataRestrictions_ranges,propertyRanges, array, nullable);
+ List propertyRanges = getCodeGenTypesByRangeData(ranges, odp);
+ String propertyDescription = ObaUtils.getDescription(odp, this.ontology_cls, this.configFlags.get(CONFIG_FLAG.DEFAULT_DESCRIPTIONS));
+ MapperDataProperty mapperProperty = new MapperDataProperty(propertyName, propertyDescription, isFunctional, restrictionValues, valuesFromDataRestrictions_ranges, propertyRanges, array, nullable);
try {
this.properties.put(mapperProperty.name, mapperProperty.getSchemaByDataProperty());
} catch (Exception e) {
@@ -215,32 +238,45 @@ private Map getDataProperties() {
}
}
}
- addDefaultProperties(properties);
+
+ if (this.configFlags.get(CONFIG_FLAG.DEFAULT_DESCRIPTIONS)) {
+ properties.putAll(this.getDefaultProperties());
+ }
+
return properties;
}
/**
- * Add DefaultProperties
- * @param properties HashMap
+ * Get default schema properties.
+ *
+ * These can be disabled by setting `default_properties` to `false` in the `config.yaml` file.
+ *
+ * @return A HashMap key: propertyName, value: Schema of data property
*/
- private void addDefaultProperties(Map properties) {
- List defaultProperties = new ArrayList(){
- {
- add("string");
- }
- };
+ private Map getDefaultProperties() {
Map defaultRestrictionValues = new HashMap();
List valuesFromDataRestrictions_ranges = new ArrayList();
- MapperDataProperty idProperty = new MapperDataProperty("id", "identifier", true, defaultRestrictionValues,valuesFromDataRestrictions_ranges,defaultProperties, false, false);
- MapperDataProperty labelProperty = new MapperDataProperty("label", "short description of the resource", false,defaultRestrictionValues,valuesFromDataRestrictions_ranges, defaultProperties, true, true);
- MapperDataProperty typeProperty = new MapperDataProperty("type", "type of the resource", false, defaultRestrictionValues,valuesFromDataRestrictions_ranges, defaultProperties, true, true);
- MapperDataProperty descriptionProperty = new MapperDataProperty("description", "small description", false, defaultRestrictionValues,valuesFromDataRestrictions_ranges, defaultProperties, true, true);
-
- properties.put(idProperty.name, idProperty.getSchemaByDataProperty());
- properties.put(labelProperty.name, labelProperty.getSchemaByDataProperty());
- properties.put(typeProperty.name, typeProperty.getSchemaByDataProperty());
- properties.put(descriptionProperty.name, descriptionProperty.getSchemaByDataProperty());
+ // Add some typical default properties (e.g. id, lable, type, and description)
+ MapperDataProperty idProperty = new MapperDataProperty("id", "identifier", true, defaultRestrictionValues, valuesFromDataRestrictions_ranges, new ArrayList(){{add("integer");}}, false, false);
+ MapperDataProperty labelProperty = new MapperDataProperty("label", "short description of the resource", false, defaultRestrictionValues, valuesFromDataRestrictions_ranges, new ArrayList(){{add("string");}}, false, true);
+ MapperDataProperty typeProperty = new MapperDataProperty("type", "type(s) of the resource", false, defaultRestrictionValues, valuesFromDataRestrictions_ranges, new ArrayList(){{add("string");}}, true, true);
+ MapperDataProperty descriptionProperty = new MapperDataProperty("description", "small description", false, defaultRestrictionValues, valuesFromDataRestrictions_ranges, new ArrayList(){{add("string");}}, false, true);
+
+ // Also add some default property examples of different types (e.g. a date/time, a boolean, and a float)
+ MapperDataProperty eventDateTimeProperty = new MapperDataProperty("eventDateTime", "a date/time of the resource", false, defaultRestrictionValues, valuesFromDataRestrictions_ranges, new ArrayList(){{add("dateTime");}}, false, true);
+ MapperDataProperty isBoolProperty = new MapperDataProperty("isBool", "a boolean indicator of the resource", false, defaultRestrictionValues, valuesFromDataRestrictions_ranges, new ArrayList(){{add("boolean");}}, false, true);
+ MapperDataProperty quantityProperty = new MapperDataProperty("quantity", "a number quantity of the resource", false, defaultRestrictionValues, valuesFromDataRestrictions_ranges, new ArrayList(){{add("float");}}, false, true);
+
+ return Map.ofEntries(
+ Map.entry(idProperty.name, idProperty.getSchemaByDataProperty()),
+ Map.entry(labelProperty.name, labelProperty.getSchemaByDataProperty()),
+ Map.entry(typeProperty.name, typeProperty.getSchemaByDataProperty()),
+ Map.entry(descriptionProperty.name, descriptionProperty.getSchemaByDataProperty()),
+ Map.entry(eventDateTimeProperty.name, eventDateTimeProperty.getSchemaByDataProperty()),
+ Map.entry(isBoolProperty.name, isBoolProperty.getSchemaByDataProperty()),
+ Map.entry(quantityProperty.name, quantityProperty.getSchemaByDataProperty())
+ );
}
/**
@@ -254,15 +290,16 @@ private Map getObjectProperties() {
Set properties_class = new HashSet<>();
Set functional;
- for (OWLOntology ontology : ontologies)
+ for (OWLOntology ontology: this.ontologies) {
properties_class.addAll(ontology.getAxioms(AxiomType.OBJECT_PROPERTY_DOMAIN));
+ }
HashMap propertyNameURI = new HashMap<>();
Map properties = new HashMap<>();
- logger.info("Parsing class " + cls.toString());
+ logger.info("Parsing class " + this.cls.toString());
for (OWLObjectPropertyDomainAxiom dp : properties_class) {
- if (checkDomainClass(cls, dp)) {
+ if (checkDomainClass(this.cls, dp)) {
logger.info( "Parsing property " + dp.toString());
for (OWLObjectProperty odp : dp.getObjectPropertiesInSignature()) {
String propertyName = this.sfp.getShortForm(odp.getIRI());
@@ -272,36 +309,31 @@ private Map getObjectProperties() {
// the object property has been previously analyzed on the getClassRestrictions method.
// If the property was analyzed, we will change the value of inspect to false, otherwise
// the property will be inspected.
- if (propertiesFromObjectRestrictions.size() != 0) {
+ if (!propertiesFromObjectRestrictions.isEmpty()) {
if (propertiesFromObjectRestrictions.contains(odp)) {
- inspect=false;
+ inspect = false;
}
-
}
+
if (inspect) {
+ boolean isFunctional = EntitySearcher.isFunctional(odp, this.ontologies.stream());
- Boolean isFunctional=false;
Set ranges = new HashSet<>();
- for (OWLOntology ontology : ontologies) {
+ for (OWLOntology ontology: this.ontologies) {
ranges.addAll(ontology.getObjectPropertyRangeAxioms(odp));
-
- functional = ontology.getAxioms(AxiomType.FUNCTIONAL_OBJECT_PROPERTY);
- for (OWLFunctionalObjectPropertyAxiom functionalAxiom:functional) {
- if (functionalAxiom.getProperty().equals(odp)) {
- isFunctional = true;
- }
- }
}
- if (ranges.size() == 0)
+
+ if (ranges.isEmpty()) {
logger.warning("Property " + odp.getIRI() + " has range equals zero");
+ }
String propertyURI = odp.getIRI().toString();
propertyNameURI.put(propertyURI, propertyName);
- List propertyRanges = getCodeGenTypesByRangeObject(ranges, odp, owlThing, follow_references);
+ List propertyRanges = getCodeGenTypesByRangeObject(ranges, odp, owlThing);
Map restrictionValues = new HashMap() ;
- for (OWLOntology ontology : ontologies) {
- RestrictionVisitor restrictionVisitor = new RestrictionVisitor(cls,ontology,owlThing,propertyName);
+ for (OWLOntology ontology: this.ontologies) {
+ RestrictionVisitor restrictionVisitor = new RestrictionVisitor(this.cls, ontology, owlThing, propertyName);
for (OWLObjectPropertyRangeAxiom propertyRangeAxiom : ranges) {
OWLClassExpression ce = propertyRangeAxiom.getRange();
ce.accept(restrictionVisitor);
@@ -312,11 +344,13 @@ private Map getObjectProperties() {
restrictionValues=restrictionsValuesFromClass.get(j);
}
}
- if (restrictionsValuesFromClass.isEmpty() && propertyRanges.size()>1)
- propertyRanges.clear();
+ if (restrictionsValuesFromClass.isEmpty() && propertyRanges.size() > 1) {
+ propertyRanges.clear();
+ }
}
- String propertyDescription = ObaUtils.getDescription(odp, ontology_cls);
+ String propertyDescription = ObaUtils.getDescription(odp, this.ontology_cls, this.configFlags.get(CONFIG_FLAG.DEFAULT_DESCRIPTIONS));
+
MapperObjectProperty mapperObjectProperty = new MapperObjectProperty(propertyName, propertyDescription, isFunctional, restrictionValues, propertyRanges);
try {
this.properties.put(mapperObjectProperty.name, mapperObjectProperty.getSchemaByObjectProperty());
@@ -327,6 +361,7 @@ private Map getObjectProperties() {
}
}
}
+
return properties;
}
@@ -346,6 +381,7 @@ private List getCodeGenTypesByRangeData(Set r
}
}
}
+
return dataProperties;
}
@@ -354,10 +390,9 @@ private List getCodeGenTypesByRangeData(Set r
* @param ranges Represents a ObjectPropertyRange
* @param odp Represents a OWLObjectProperty
* @param owlThing
- * @param follow_references
* @return A list with the properties
*/
- private List getCodeGenTypesByRangeObject(Set ranges, OWLObjectProperty odp, OWLClass owlThing, boolean follow_references) {
+ private List getCodeGenTypesByRangeObject(Set ranges, OWLObjectProperty odp, OWLClass owlThing) {
List objectProperty = new ArrayList<>();
for (OWLObjectPropertyRangeAxiom propertyRangeAxiom : ranges) {
@@ -366,18 +401,16 @@ private List getCodeGenTypesByRangeObject(Set getCodeGenTypesByRangeObject(Set> restrictionsValuesFromClass = restrictionVisitor.getRestrictionsValuesFromClass();
-
- if (restrictionsValuesFromClass.size()!=0) {
- // When the restriction is a ObjectComplementOf it doesn't have a object property,
- // thus we need to set its value at the setSchema function
- if (restrictionsValuesFromClass.containsKey("complementOf") && restrictionsValuesFromClass.size() == 1) {
- for (String j : restrictionsValuesFromClass.keySet()) {
- Map restrictionValues=restrictionsValuesFromClass.get(j);
- for (String restriction: restrictionValues.keySet()) {
- complementOf = restrictionValues.get(restriction);
- }
- }
- } else {
+ // For equivalent (to) classes (e.g. Defined classes) we need to accept the visit to navigate it.
+ ontology.equivalentClassesAxioms(analyzedClass).forEach((eqClsAx) -> {
+ eqClsAx.accept(restrictionVisitor);
+ });
+
+ this.enums = restrictionVisitor.getAllEnums();
+ this.propertiesFromObjectRestrictions = restrictionVisitor.getPropertiesFromObjectRestrictions();
+ this.propertiesFromObjectRestrictions_ranges = restrictionVisitor.getPropertiesFromObjectRestrictions_ranges();
+ this.propertiesFromDataRestrictions = restrictionVisitor.getPropertiesFromDataRestrictions();
+ this.propertiesFromDataRestrictions_ranges = restrictionVisitor.getPropertiesFromDataRestrictions_ranges();
+ Map> restrictionsValuesFromClass = restrictionVisitor.getRestrictionsValuesFromClass();
+
+ if (!restrictionsValuesFromClass.isEmpty()) {
+ // When the restriction is a ObjectComplementOf it doesn't have a object property,
+ // thus we need to set its value at the setSchema function
+ if (restrictionsValuesFromClass.containsKey("complementOf") && restrictionsValuesFromClass.size() == 1) {
+ for (String j: restrictionsValuesFromClass.keySet()) {
+ Map restrictionValues = restrictionsValuesFromClass.get(j);
+ for (String restriction: restrictionValues.keySet()) {
+ this.complementOf = restrictionValues.get(restriction);
+ }
+ }
+ } else {
+ for (OWLObjectProperty op: this.propertiesFromObjectRestrictions) {
+ boolean isFunctional = EntitySearcher.isFunctional(op, this.ontologies.stream());
- for (OWLObjectProperty op : propertiesFromObjectRestrictions) {
MapperObjectProperty mapperObjectProperty;
- String propertyDescription = ObaUtils.getDescription(op, ontology_cls);
- if (propertiesFromObjectRestrictions_ranges.size() != 0) {
- List rangesOP = propertiesFromObjectRestrictions_ranges.get(sfp.getShortForm(op.getIRI()));
+ String propertyDescription = ObaUtils.getDescription(op, this.ontology_cls, this.configFlags.get(CONFIG_FLAG.DEFAULT_DESCRIPTIONS));
+ if (!this.propertiesFromObjectRestrictions_ranges.isEmpty()) {
+ List rangesOP = this.propertiesFromObjectRestrictions_ranges.get(this.sfp.getShortForm(op.getIRI()));
for (String j : restrictionsValuesFromClass.keySet()) {
Map restrictionValues = restrictionsValuesFromClass.get(j);
- if (j.equals(sfp.getShortForm(op.getIRI()))) {
- if (rangesOP.get(0).equals("defaultValue"))
- mapperObjectProperty = new MapperObjectProperty(sfp.getShortForm(op.getIRI()), propertyDescription, false, restrictionValues, rangesOP, false, true);
- else
- mapperObjectProperty = new MapperObjectProperty(sfp.getShortForm(op.getIRI()), propertyDescription, false, restrictionValues, rangesOP);
+ if (j.equals(this.sfp.getShortForm(op.getIRI()))) {
+ int exactCardinality = -1;
+ int minCardinality = -1;
+ int maxCardinality = -1;
+
+ if (rangesOP != null && rangesOP.get(0).equals("defaultValue")) {
+ mapperObjectProperty = new MapperObjectProperty(this.sfp.getShortForm(op.getIRI()), propertyDescription, isFunctional, restrictionValues, rangesOP, false, true);
+ } else {
+ String exactCardinalityStr = restrictionValues.get("exactCardinality");
+ exactCardinalityStr = ((exactCardinalityStr == null || exactCardinalityStr.isBlank()) ? "-1" : exactCardinalityStr);
+ exactCardinality = Integer.parseInt(exactCardinalityStr);
+
+ String minCardinalityStr = restrictionValues.get("minCardinality");
+ minCardinalityStr = ((minCardinalityStr == null || minCardinalityStr.isBlank()) ? "-1" : minCardinalityStr);
+ minCardinality = Integer.parseInt(minCardinalityStr);
+
+ String maxCardinalityStr = restrictionValues.get("maxCardinality");
+ maxCardinalityStr = ((maxCardinalityStr == null || maxCardinalityStr.isBlank()) ? "-1" : maxCardinalityStr);
+ maxCardinality = Integer.parseInt(maxCardinalityStr);
+
+ // If cardinality is present and allows for multiple values and it is not functional,
+ // then this is an array.
+ boolean isArray = !isFunctional
+ && (exactCardinality > 1
+ || minCardinality > 1
+ || maxCardinality > 1);
+
+ // If config flag to generate arrays is set, use it to override current setting.
+ isArray |= (this.configFlags.containsKey(CONFIG_FLAG.ALWAYS_GENERATE_ARRAYS) && this.configFlags.get(CONFIG_FLAG.ALWAYS_GENERATE_ARRAYS));
+
+ // If cardinality is exactly 1 OR a minimum of 1, then not nullable.
+ boolean isNullable = (exactCardinality == -1 && minCardinality == -1) ? true : exactCardinality != 1 && minCardinality < 1;
+
+ mapperObjectProperty = new MapperObjectProperty(this.sfp.getShortForm(op.getIRI()), propertyDescription, isFunctional, restrictionValues, rangesOP, isArray, isNullable);
+ }
+
try {
- this.properties.put(mapperObjectProperty.name, mapperObjectProperty.getSchemaByObjectProperty());
+ Schema opSchema = mapperObjectProperty.getSchemaByObjectProperty();
+
+ boolean is_required = false;
+
+ // If cardinality is exactly 1, then we can remove the min/max property constraints
+ // and set the property to be required for the class.
+ if (exactCardinality == 1 || (minCardinality == 1 && maxCardinality == 1)) {
+ if (this.configFlags.containsKey(CONFIG_FLAG.ALWAYS_GENERATE_ARRAYS) && !this.configFlags.get(CONFIG_FLAG.ALWAYS_GENERATE_ARRAYS)) {
+ opSchema.setMinItems(null);
+ opSchema.setMaxItems(null);
+ }
+
+ is_required = true;
+ }
+
+ // If cardinality minimum is 1, keep the min/max property constraints
+ // and set the property to be required for the class.
+ if (minCardinality > 0) {
+ is_required = true;
+ }
+
+ if (is_required) {
+ this.required_properties.add(mapperObjectProperty.name);
+ }
+
+ this.properties.put(mapperObjectProperty.name, opSchema);
} catch (Exception e) {
logger.warning("Error when parsing object property "+mapperObjectProperty.name);
}
@@ -441,17 +536,70 @@ private void getClassRestrictions(OWLClass analyzedClass){
}
}
}
- for (OWLDataProperty dp : propertiesFromDataRestrictions) {
+
+ for (OWLDataProperty dp: this.propertiesFromDataRestrictions) {
+ boolean isFunctional = EntitySearcher.isFunctional(dp, this.ontologies.stream());
+
List valuesFromDataRestrictions_ranges = new ArrayList<>();
- String propertyDescription = ObaUtils.getDescription(dp, ontology_cls);
- if (propertiesFromDataRestrictions_ranges.size() != 0) {
- List rangesDP = propertiesFromDataRestrictions_ranges.get(sfp.getShortForm(dp.getIRI()));
- for (String j : restrictionsValuesFromClass.keySet()) {
+ String propertyDescription = ObaUtils.getDescription(dp, this.ontology_cls, this.configFlags.get(CONFIG_FLAG.DEFAULT_DESCRIPTIONS));
+ if (!this.propertiesFromDataRestrictions_ranges.isEmpty()) {
+ List rangesDP = this.propertiesFromDataRestrictions_ranges.get(this.sfp.getShortForm(dp.getIRI()));
+ for (String j: restrictionsValuesFromClass.keySet()) {
Map restrictionValues = restrictionsValuesFromClass.get(j);
- if (j.equals(sfp.getShortForm(dp.getIRI()))) {
- MapperDataProperty mapperDataProperty = new MapperDataProperty(sfp.getShortForm(dp.getIRI()), propertyDescription, false, restrictionValues, valuesFromDataRestrictions_ranges, rangesDP, true, true);
+ if (j.equals(this.sfp.getShortForm(dp.getIRI()))) {
+ String exactCardinalityStr = restrictionValues.get("exactCardinality");
+ exactCardinalityStr = ((exactCardinalityStr == null || exactCardinalityStr.isBlank()) ? "-1" : exactCardinalityStr);
+ int exactCardinality = Integer.parseInt(exactCardinalityStr);
+
+ String minCardinalityStr = restrictionValues.get("minCardinality");
+ minCardinalityStr = ((minCardinalityStr == null || minCardinalityStr.isBlank()) ? "-1" : minCardinalityStr);
+ int minCardinality = Integer.parseInt(minCardinalityStr);
+
+ String maxCardinalityStr = restrictionValues.get("maxCardinality");
+ maxCardinalityStr = ((maxCardinalityStr == null || maxCardinalityStr.isBlank()) ? "-1" : maxCardinalityStr);
+ int maxCardinality = Integer.parseInt(maxCardinalityStr);
+
+ // If cardinality is present and allows for multiple values and it is not functional,
+ // then this is an array.
+ boolean isArray = !isFunctional
+ && (exactCardinality > 1
+ || minCardinality > 1
+ || maxCardinality > 1);
+
+ // If config flag to generate arrays is set, use it to override current setting.
+ isArray |= (this.configFlags.containsKey(CONFIG_FLAG.ALWAYS_GENERATE_ARRAYS) && this.configFlags.get(CONFIG_FLAG.ALWAYS_GENERATE_ARRAYS));
+
+ // If cardinality is exactly 1 OR a minimum of 1, then not nullable.
+ boolean isNullable = (exactCardinality == -1 && minCardinality == -1) ? true : exactCardinality != 1 && minCardinality < 1;
+
+ MapperDataProperty mapperDataProperty = new MapperDataProperty(this.sfp.getShortForm(dp.getIRI()), propertyDescription, isFunctional, restrictionValues, valuesFromDataRestrictions_ranges, rangesDP, isArray, isNullable);
try {
- this.properties.put(mapperDataProperty.name, mapperDataProperty.getSchemaByDataProperty());
+ Schema dpSchema = mapperDataProperty.getSchemaByDataProperty();
+
+ boolean is_required = false;
+
+ // If cardinality is exactly 1, then we can remove the min/max property constraints
+ // and set the property to be required for the class.
+ if (exactCardinality == 1 || (minCardinality == 1 && maxCardinality == 1)) {
+ if (this.configFlags.containsKey(CONFIG_FLAG.ALWAYS_GENERATE_ARRAYS) && !this.configFlags.get(CONFIG_FLAG.ALWAYS_GENERATE_ARRAYS)) {
+ dpSchema.setMinItems(null);
+ dpSchema.setMaxItems(null);
+ }
+
+ is_required = true;
+ }
+
+ // If cardinality minimum is 1, keep the min/max property constraints
+ // and set the property to be required for the class.
+ if (minCardinality > 0) {
+ is_required = true;
+ }
+
+ if (is_required) {
+ this.required_properties.add(mapperDataProperty.name);
+ }
+
+ this.properties.put(mapperDataProperty.name, dpSchema);
} catch (Exception e) {
logger.warning("Error when processing data property " + mapperDataProperty.name);
}
@@ -459,27 +607,26 @@ private void getClassRestrictions(OWLClass analyzedClass){
}
}
}
- }
- this.properties = setProperties();
- }
- else {
- this.properties = setProperties();
- }
+ }
+ }
+
+ this.properties = setProperties();
}
- addDefaultProperties(this.properties);
+
+ if (this.configFlags.get(CONFIG_FLAG.DEFAULT_PROPERTIES)) {
+ this.properties.putAll(this.getDefaultProperties());
+ }
}
private Map getProperties() {
- return properties;
+ return this.properties;
}
private String getSchemaName(OWLClass cls) {
- return schemaNames.get(cls.getIRI());
+ return this.schemaNames.get(cls.getIRI());
}
public OWLClass getCls() {
- return cls;
+ return this.cls;
}
-
-
}
diff --git a/src/main/java/edu/isi/oba/Oba.java b/src/main/java/edu/isi/oba/Oba.java
index f99fcc2..2ee7d6f 100644
--- a/src/main/java/edu/isi/oba/Oba.java
+++ b/src/main/java/edu/isi/oba/Oba.java
@@ -1,9 +1,9 @@
package edu.isi.oba;
import edu.isi.oba.config.*;
+
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.PathItem;
-import org.json.JSONObject;
import java.io.*;
import java.nio.file.Path;
@@ -14,6 +14,8 @@
import java.util.logging.LogManager;
import java.util.logging.Logger;
+import org.json.JSONObject;
+
class Oba {
public static final String SERVERS_ZIP = "/servers.zip";
public static final String SERVERS_DIRECTORY = "servers";
@@ -66,30 +68,29 @@ public static void main(String[] args) throws Exception {
} else {
config_data.setAuth(new AuthConfig());
}
+
try {
Mapper mapper = new Mapper(config_data);
- mapper.createSchemas(destination_dir, config_data);
+ mapper.createSchemas(destination_dir);
LinkedHashMap custom_paths = config_data.getCustom_paths();
OpenAPI openapi_base = config_data.getOpenapi();
String custom_queries_dir = config_data.getCustom_queries_directory();
//copy base project
- ObaUtils.unZipIt(SERVERS_ZIP, destination_dir);
+ ObaUtils.unZipIt(Oba.SERVERS_ZIP, destination_dir);
//get schema and paths
generate_openapi_spec(openapi_base, mapper, destination_dir, custom_paths);
generate_openapi_template(mapper, destination_dir, config_data, selected_language);
generate_context(config_data, destination_dir);
copy_custom_queries(custom_queries_dir, destination_dir);
- logger.info("OBA finished successfully. Output can be found at: "+destination_dir);
- }catch (Exception e){
- logger.severe("Error while creating the API specification: "+e.getLocalizedMessage());
+ logger.info("OBA finished successfully. Output can be found at: " + destination_dir);
+ } catch (Exception e) {
+ logger.severe("Error while creating the API specification: " + e.getLocalizedMessage());
e.printStackTrace();
System.exit(1);
}
}
-
-
private static void generate_context(YamlConfig config_data, String destination_dir) {
List ontologies = config_data.getOntologies();
@@ -106,12 +107,12 @@ private static void generate_context(YamlConfig config_data, String destination_
try {
ObaUtils.write_file(file_path, context_json_object.toString(4));
ObaUtils.write_file(file_path_class, context_json_object_class.toString(4));
- }catch(Exception e){
+ } catch(Exception e) {
logger.severe("Could not generate the context files: "+e.getMessage());
}
}
- private static void copy_custom_queries(String source, String destination){
+ private static void copy_custom_queries(String source, String destination) {
if (source != null) {
try {
ObaUtils.copyFolder(new File(source), new File(destination + File.separator + "queries" + File.separator + "custom"));
@@ -140,10 +141,8 @@ private static void generate_openapi_spec(OpenAPI openapi_base,
String dir,
LinkedHashMap custom_paths
) throws Exception {
- String destinationProjectDirectory = dir + File.separator + SERVERS_DIRECTORY;
+ String destinationProjectDirectory = dir + File.separator + Oba.SERVERS_DIRECTORY;
Path destinationProject = Paths.get(destinationProjectDirectory);
new Serializer(mapper, destinationProject, openapi_base, custom_paths);
}
-
-
}
diff --git a/src/main/java/edu/isi/oba/ObaUtils.java b/src/main/java/edu/isi/oba/ObaUtils.java
index 6088281..0e55940 100644
--- a/src/main/java/edu/isi/oba/ObaUtils.java
+++ b/src/main/java/edu/isi/oba/ObaUtils.java
@@ -1,36 +1,42 @@
package edu.isi.oba;
+import static edu.isi.oba.Oba.logger;
import edu.isi.oba.config.YamlConfig;
-import org.apache.commons.cli.*;
-import org.json.JSONException;
-import org.json.JSONObject;
-import org.yaml.snakeyaml.Yaml;
-import org.yaml.snakeyaml.constructor.Constructor;
import java.io.*;
-import java.nio.file.Files;
-import java.nio.file.StandardCopyOption;
-import java.util.logging.Level;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipInputStream;
-
-import static edu.isi.oba.Oba.logger;
import java.net.HttpURLConnection;
import java.net.URL;
+import java.nio.file.Files;
import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
+import java.util.logging.Level;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import org.apache.commons.cli.*;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.search.EntitySearcher;
+
+import org.yaml.snakeyaml.LoaderOptions;
+import org.yaml.snakeyaml.Yaml;
+import org.yaml.snakeyaml.constructor.Constructor;
+
import uk.ac.manchester.cs.owl.owlapi.OWLAnnotationPropertyImpl;
public class ObaUtils {
+ public static final String DEFAULT_DESCRIPTION = "Description not available";
public static final String[] POSSIBLE_VOCAB_SERIALIZATIONS = { "application/rdf+xml", "text/turtle", "text/n3",
"application/ld+json" };
private static final String RDFS_NS = "http://www.w3.org/2000/01/rdf-schema#";
@@ -180,7 +186,7 @@ public static String get_config_yaml(String[] args) {
}
public static YamlConfig get_yaml_data(String config_yaml) {
- Constructor constructor = new Constructor(YamlConfig.class);
+ Constructor constructor = new Constructor(YamlConfig.class, new LoaderOptions());
Yaml yaml = new Yaml(constructor);
InputStream config_input = null;
@@ -372,28 +378,31 @@ public static void downloadOntology(String uri, String downloadPath) {
* Method that given a class, property or data property, searches for the best description.
* @param entity entity to search.
* @param ontology ontology to be used to search descriptions.
+ * @param default_descriptions flag indicating whether default descriptions should or should not be included.
* @return Description String (prioritizes English language)
*/
- public static String getDescription(OWLEntity entity, OWLOntology ontology){
- String descriptionValue = "Description not available";
- for(String description:ObaUtils.DESCRIPTION_PROPERTIES){
- Object[] annotationsObjects = EntitySearcher.getAnnotationObjects(entity, ontology, new OWLAnnotationPropertyImpl(new IRI(description) {
- })).toArray();
- if(annotationsObjects.length!=0){
- Optional descriptionLiteral;
- for(Object annotation: annotationsObjects){
- descriptionLiteral = ((OWLAnnotation) annotation).getValue().asLiteral();
- if(descriptionLiteral.isPresent()){
- if(annotationsObjects.length == 1 || descriptionLiteral.get().getLang().equals("en")){
- descriptionValue = descriptionLiteral.get().getLiteral();
- }
- }
- }
- break;
- }
- }
- return descriptionValue;
+ public static String getDescription(OWLEntity entity, OWLOntology ontology, Boolean default_descriptions) {
+ String descriptionValue = ObaUtils.DEFAULT_DESCRIPTION;
+ for (String description: ObaUtils.DESCRIPTION_PROPERTIES) {
+ Object[] annotationsObjects = EntitySearcher.getAnnotationObjects(entity, ontology, new OWLAnnotationPropertyImpl(new IRI(description){})).toArray();
+
+ if (annotationsObjects.length != 0) {
+ Optional descriptionLiteral;
+ for (Object annotation: annotationsObjects) {
+ descriptionLiteral = ((OWLAnnotation) annotation).getValue().asLiteral();
+
+ if (descriptionLiteral.isPresent()) {
+ if (annotationsObjects.length == 1 || descriptionLiteral.get().getLang().equals("en")) {
+ descriptionValue = descriptionLiteral.get().getLiteral();
+ }
+ }
+ }
+
+ break;
+ }
+ }
+
+ return !Optional.ofNullable(default_descriptions).orElse(false) && ObaUtils.DEFAULT_DESCRIPTION.equals(descriptionValue) ? null : descriptionValue;
}
-
}
diff --git a/src/main/java/edu/isi/oba/Path.java b/src/main/java/edu/isi/oba/PathGenerator.java
similarity index 78%
rename from src/main/java/edu/isi/oba/Path.java
rename to src/main/java/edu/isi/oba/PathGenerator.java
index 72023c8..6afb52c 100644
--- a/src/main/java/edu/isi/oba/Path.java
+++ b/src/main/java/edu/isi/oba/PathGenerator.java
@@ -1,62 +1,65 @@
package edu.isi.oba;
+import edu.isi.oba.config.CONFIG_FLAG;
+
import io.swagger.models.Method;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.PathItem;
import io.swagger.v3.oas.models.headers.Header;
import io.swagger.v3.oas.models.media.*;
-import io.swagger.v3.oas.models.parameters.Parameter;
-import io.swagger.v3.oas.models.parameters.PathParameter;
import io.swagger.v3.oas.models.parameters.RequestBody;
import io.swagger.v3.oas.models.responses.ApiResponse;
import io.swagger.v3.oas.models.responses.ApiResponses;
-import java.util.ArrayList;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
-class Path {
- public Boolean enable_get_paths;
- public Boolean enable_post_paths;
- public Boolean enable_put_paths;
- public Boolean enable_delete_paths;
+class PathGenerator {
+ private final Map configFlags = new HashMap<>();
private Boolean auth;
- public Path(Boolean enable_get_paths, Boolean enable_post_paths, Boolean enable_put_paths, Boolean enable_delete_paths, Boolean auth) {
+ public PathGenerator(Map configFlags, Boolean auth) {
this.auth = auth;
- this.enable_get_paths = enable_get_paths;
- this.enable_post_paths = enable_post_paths;
- this.enable_put_paths = enable_put_paths;
- this.enable_delete_paths = enable_delete_paths;
+ this.configFlags.putAll(configFlags);
}
- public PathItem generate_singular(String schemaName, String schemaURI){
+ public PathItem generate_singular(String schemaName, String schemaURI) {
PathItem path_item = new PathItem();
- if (enable_get_paths)
+ if (this.configFlags.get(CONFIG_FLAG.PATH_GET)) {
path_item.get(new MapperOperation(schemaName, schemaURI, Method.GET, Cardinality.SINGULAR, auth).getOperation());
+ }
- if (enable_delete_paths)
+ if (this.configFlags.get(CONFIG_FLAG.PATH_DELETE)) {
path_item.delete(new MapperOperation(schemaName, schemaURI, Method.DELETE, Cardinality.SINGULAR, auth).getOperation());
+ }
+
+ if (this.configFlags.get(CONFIG_FLAG.PATH_POST)) {
+ path_item.put(new MapperOperation(schemaName, schemaURI, Method.POST, Cardinality.SINGULAR, auth).getOperation());
+ }
- if (enable_put_paths)
+ if (this.configFlags.get(CONFIG_FLAG.PATH_PUT)) {
path_item.put(new MapperOperation(schemaName, schemaURI, Method.PUT, Cardinality.SINGULAR, auth).getOperation());
+ }
return path_item;
}
- public PathItem generate_plural(String schemaName, String schemaURI){
+ public PathItem generate_plural(String schemaName, String schemaURI) {
PathItem path_item = new PathItem();
- if (enable_get_paths)
+ if (this.configFlags.get(CONFIG_FLAG.PATH_GET)) {
path_item.get(new MapperOperation(schemaName, schemaURI, Method.GET, Cardinality.PLURAL, auth).getOperation());
- if (enable_post_paths)
+ }
+
+ if (this.configFlags.get(CONFIG_FLAG.PATH_POST)) {
path_item.post(new MapperOperation(schemaName,schemaURI, Method.POST, Cardinality.PLURAL, auth).getOperation());
+ }
+
return path_item;
}
- public PathItem user_login(String schema_name) {
+ public static PathItem user_login(String schema_name) {
ApiResponses apiResponses = new ApiResponses();
final RequestBody requestBody = new RequestBody();
diff --git a/src/main/java/edu/isi/oba/RestrictionVisitor.java b/src/main/java/edu/isi/oba/RestrictionVisitor.java
index 7b6543c..406dd6d 100644
--- a/src/main/java/edu/isi/oba/RestrictionVisitor.java
+++ b/src/main/java/edu/isi/oba/RestrictionVisitor.java
@@ -8,7 +8,6 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.stream.Stream;
import org.semanticweb.owlapi.model.*;
import org.semanticweb.owlapi.util.IRIShortFormProvider;
@@ -42,7 +41,7 @@ public class RestrictionVisitor implements OWLObjectVisitor {
private final OWLClass cls;
private final OWLOntology onto;
String property_name;
- OWLClass owlThing;
+ OWLClass owlThing;
public Map> restrictionsValuesFromClass;
@@ -51,33 +50,56 @@ public class RestrictionVisitor implements OWLObjectVisitor {
public List propertiesFromDataRestrictions;
public Map> propertiesFromDataRestrictions_ranges;
public List valuesFromDataRestrictions_ranges;
-
+ public Map> enums;
RestrictionVisitor(OWLClass visitedClass, OWLOntology onto, OWLClass owlThing, String propertyName ) {
processedClasses = new HashSet();
- this.cls=visitedClass;
- this.onto=onto;
- this.property_name=propertyName;
- this.owlThing=owlThing;
+ this.cls = visitedClass;
+ this.onto = onto;
+ this.property_name = propertyName;
+ this.owlThing = owlThing;
this.propertiesFromObjectRestrictions_ranges= new HashMap<>();
this.propertiesFromObjectRestrictions = new ArrayList<>();
this.restrictionsValuesFromClass = new HashMap<>();
this.propertiesFromDataRestrictions = new ArrayList<>();
this.propertiesFromDataRestrictions_ranges= new HashMap<>();
this.valuesFromDataRestrictions_ranges = new ArrayList<>();
+ this.enums = new HashMap<>();
}
@Override
public void visit(OWLClass ce) {
- if (!processedClasses.contains(ce)) {
+ if (!this.processedClasses.contains(ce)) {
// If we are processing inherited restrictions then we recursively visit named supers.
- processedClasses.add(ce);
- for (OWLSubClassOfAxiom ax : onto.getSubClassAxiomsForSubClass(ce)) {
- ax.getSuperClass().accept(this);
+ this.processedClasses.add(ce);
+ for (OWLSubClassOfAxiom ax: this.onto.getSubClassAxiomsForSubClass(ce)) {
+ ax.getSuperClass().accept(this);
}
}
}
+ @Override
+ public void visit( OWLEquivalentClassesAxiom ce ) {
+ logger.info("Analyzing restrictions of Class: " + this.cls+ " with axiom: "+ce);
+
+ // If equivalent class axiom AND contains owl:oneOf, then we're looking at an ENUM class.
+ ce.classExpressions().filter((e) -> e instanceof OWLObjectOneOf).forEach((oneOfObj) -> {
+ var enumValues = new ArrayList();
+ ((OWLObjectOneOf) oneOfObj).getOperandsAsList().forEach((indv) -> {
+ enumValues.add(this.sfp.getShortForm(((OWLNamedIndividual) indv).getIRI()));
+ });
+
+ if (!enumValues.isEmpty()) {
+ this.enums.put(this.cls.getIRI(), enumValues);
+ }
+ });
+
+ // Loop through each expression in the equivalent classes axiom and accept visits from everything else.
+ ce.classExpressions().filter((e) -> !(e instanceof OWLObjectOneOf)).forEach((e) -> {
+ e.accept(this);
+ });
+ }
+
/**
* This method gets called when a class expression is an existential
* (someValuesFrom) restriction and it asks us to visit it
@@ -85,26 +107,33 @@ public void visit(OWLClass ce) {
@Override
public void visit(OWLObjectSomeValuesFrom ce) {
Map restrictionsValues = new HashMap<>();
- logger.info("Analyzing restrictions of Class: " + this.cls+ " with axiom: "+ce);
- for(OWLObjectProperty property:ce.getObjectPropertiesInSignature()) {
- propertiesFromObjectRestrictions.add(property);
- property_name = sfp.getShortForm(property.getIRI());
+ logger.info("Analyzing restrictions of Class: " + this.cls + " with axiom: " + ce);
+
+ for(OWLObjectProperty property: ce.getObjectPropertiesInSignature()) {
+ this.propertiesFromObjectRestrictions.add(property);
+ this.property_name = this.sfp.getShortForm(property.getIRI());
}
- if (ce.getFiller() instanceof OWLObjectUnionOf || ce.getFiller() instanceof OWLObjectIntersectionOf || ce.getFiller() instanceof OWLObjectOneOf) {
- restrictionsValues.put("someValuesFrom", "");
- restrictionsValuesFromClass.put(property_name, restrictionsValues);
+
+ OWLClassExpression ceFiller = ce.getFiller();
+ if (ceFiller instanceof OWLObjectUnionOf || ceFiller instanceof OWLObjectIntersectionOf || ceFiller instanceof OWLObjectOneOf) {
+ restrictionsValues.put("someValuesFrom", "");
+ this.restrictionsValuesFromClass.put(this.property_name, restrictionsValues);
ce.getFiller().accept(this);
- } else {
- List ranges = new ArrayList<>();
- ranges.add(sfp.getShortForm(ce.getFiller().asOWLClass().getIRI()));
- if (ce.getFiller().asOWLClass().equals(owlThing)) {
- logger.info("Ignoring owl:Thing range" + property_name);
+ } else {
+ if (ceFiller.asOWLClass().equals(owlThing)) {
+ logger.info("Ignoring owl:Thing range" + this.property_name);
+ } else {
+ if (this.propertiesFromObjectRestrictions_ranges.containsKey(this.property_name)) {
+ this.propertiesFromObjectRestrictions_ranges.get(this.property_name).add(this.sfp.getShortForm(ceFiller.asOWLClass().getIRI()));
+ } else {
+ List ranges = new ArrayList<>();
+ ranges.add(this.sfp.getShortForm(ceFiller.asOWLClass().getIRI()));
+ this.propertiesFromObjectRestrictions_ranges.put(this.property_name, ranges);
+ }
}
- else
- propertiesFromObjectRestrictions_ranges.put(property_name,ranges);
- restrictionsValues.put("someValuesFrom", "");
- restrictionsValuesFromClass.put(property_name, restrictionsValues);
+ restrictionsValues.put("someValuesFrom", "");
+ this.restrictionsValuesFromClass.put(this.property_name, restrictionsValues);
}
}
@@ -127,9 +156,9 @@ public void visit(OWLObjectAllValuesFrom ce) {
ranges.add(sfp.getShortForm(ce.getFiller().asOWLClass().getIRI()));
if (ce.getFiller().asOWLClass().equals(owlThing)) {
logger.info("Ignoring owl:Thing range" + property_name);
+ } else {
+ propertiesFromObjectRestrictions_ranges.put(property_name, ranges);
}
- else
- propertiesFromObjectRestrictions_ranges.put(property_name,ranges);
restrictionsValues.put("allValuesFrom", "");
restrictionsValuesFromClass.put(property_name, restrictionsValues);
@@ -139,16 +168,20 @@ public void visit(OWLObjectAllValuesFrom ce) {
@Override
public void visit( OWLObjectUnionOf ce ) {
logger.info("Analyzing restrictions of Class: " + this.cls+ " with axiom: "+ce);
- Set ranges = ce.getOperands();
- Set properties = ce.getObjectPropertiesInSignature();
- setBooleanCombinationProperties(ranges, properties, "unionOf");
+
+ // Loop through each item in the union and accept visits.
+ for (OWLClassExpression e : ce.getOperands()) {
+ e.accept(this);
+ }
}
@Override
public void visit( OWLObjectIntersectionOf ce ) {
- logger.info("Analyzing restrictions of Class: " + this.cls+ " with axiom: "+ce);
- Set ranges = ce.getOperands();
- Set properties = ce.getObjectPropertiesInSignature();
- setBooleanCombinationProperties(ranges, properties, "intersectionOf");
+ logger.info("Analyzing restrictions of Class: " + this.cls+ " with axiom: "+ce);
+
+ // Loop through each item in the intersection and accept visits.
+ for (OWLClassExpression e : ce.getOperands()) {
+ e.accept(this);
+ }
}
@Override
@@ -179,32 +212,49 @@ public void visit( OWLObjectComplementOf ce ) {
@Override
public void visit(OWLObjectHasValue ce) {
- logger.info("Analyzing restrictions of Class: " + this.cls+ " with axiom: "+ce);
- List ranges = new ArrayList();
- Map restrictionsValues = new HashMap();
- for(OWLObjectProperty property:ce.getObjectPropertiesInSignature()) {
- property_name = sfp.getShortForm(property.getIRI());
- restrictionsValues.put("objectHasValue",ce.getValue().toString());
- restrictionsValuesFromClass.put(property_name, restrictionsValues);
- propertiesFromObjectRestrictions.add(property);
+ logger.info("Analyzing restrictions of Class: " + this.cls + " with axiom: " + ce);
+
+ for(OWLObjectProperty property: ce.getObjectPropertiesInSignature()) {
+ List ranges = new ArrayList();
+ Map restrictionsValues = new HashMap();
+
+ this.property_name = this.sfp.getShortForm(property.getIRI());
+
+ restrictionsValues.put("objectHasValue", this.sfp.getShortForm(((OWLNamedIndividual)ce.getFiller()).getIRI()));
+
+ // If object property has object(s) in its range, we want to set references to the object class.
+ var obRangeAxioms = this.onto.getObjectPropertyRangeAxioms(property);
+ if (obRangeAxioms.isEmpty()) {
+ logger.warning("\tObject has value (named individual) but there is no associated class/reference for the value. Ontology may have errors.");
+ } else {
+ obRangeAxioms.forEach((obRangeAxiom) -> {
+ obRangeAxiom.getRange().classesInSignature().forEach((owlClass) -> {
+ restrictionsValues.put("objectHasReference", this.sfp.getShortForm(owlClass.getIRI()));
+ });
+ });
+ }
+
+ this.restrictionsValuesFromClass.put(this.property_name, restrictionsValues);
+ this.propertiesFromObjectRestrictions.add(property);
ranges.add("defaultValue");
- propertiesFromObjectRestrictions_ranges.put(property_name,ranges);
+ this.propertiesFromObjectRestrictions_ranges.put(this.property_name, ranges);
}
}
@Override
public void visit( OWLObjectOneOf ce ) {
- logger.info("Analyzing restrictions of Class: " + this.cls+ " with axiom: "+ce);
+ logger.info("Analyzing restrictions of Class: " + this.cls + " with axiom: " + ce);
List ranges = new ArrayList();
Map restrictionsValues = new HashMap();
- Stream valores=ce.objectPropertiesInSignature();
+
if (!property_name.isEmpty()) {
- for (OWLIndividual individual : ce.getIndividuals()) {
+ for (OWLIndividual individual: ce.getIndividuals()) {
ranges.add(individual.toString());
}
- restrictionsValues.put("oneOf","someValuesFrom");
- restrictionsValuesFromClass.put(property_name, restrictionsValues);
- propertiesFromObjectRestrictions_ranges.put(property_name,ranges);
+
+ restrictionsValues.put("oneOf", "someValuesFrom");
+ this.restrictionsValuesFromClass.put(this.property_name, restrictionsValues);
+ this.propertiesFromObjectRestrictions_ranges.put(this.property_name, ranges);
}
}
@@ -214,7 +264,7 @@ public void visit( OWLObjectOneOf ce ) {
*/
@Override
public void visit( OWLDataAllValuesFrom ce ) {
- logger.info( "\n Analized Class: " + this.cls+ " with axiom: "+ce);
+ logger.info( "\n Analyzed Class: " + this.cls+ " with axiom: "+ce);
Map restrictionsValues = new HashMap();
for(OWLDataProperty property:ce.getDataPropertiesInSignature()) {
propertiesFromDataRestrictions.add(property);
@@ -242,45 +292,51 @@ public void visit( OWLDataAllValuesFrom ce ) {
*/
@Override
public void visit( OWLDataSomeValuesFrom ce ) {
-
- logger.info( "\n Analized Class: " + this.cls+ " with axiom: "+ce);
+ logger.info( "\n Analyzed Class: " + this.cls + " with axiom: " + ce);
Map restrictionsValues = new HashMap();
- for(OWLDataProperty property:ce.getDataPropertiesInSignature()) {
- propertiesFromDataRestrictions.add(property);
- property_name = sfp.getShortForm(property.getIRI());
+ for(OWLDataProperty property: ce.getDataPropertiesInSignature()) {
+ this.propertiesFromDataRestrictions.add(property);
+ this.property_name = this.sfp.getShortForm(property.getIRI());
}
- if (ce.getFiller() instanceof OWLDataUnionOf || ce.getFiller() instanceof OWLDataIntersectionOf) {
+
+ OWLDataRange ceFiller = ce.getFiller();
+ if (ceFiller instanceof OWLDataUnionOf || ceFiller instanceof OWLDataIntersectionOf) {
restrictionsValues.put("someValuesFrom", "");
- restrictionsValuesFromClass.put(property_name, restrictionsValues);
+ this.restrictionsValuesFromClass.put(property_name, restrictionsValues);
ce.getFiller().accept(this);
} else {
List ranges = new ArrayList();
- ranges.add(sfp.getShortForm(ce.getFiller().asOWLDatatype().getIRI()));
- if (ce.getFiller().asOWLDatatype().equals(owlThing)) {
+ ranges.add(this.sfp.getShortForm(ceFiller.asOWLDatatype().getIRI()));
+
+ if (ceFiller.asOWLDatatype().equals(owlThing)) {
logger.info("Ignoring owl:Thing range" + property_name);
- }
- else
- propertiesFromDataRestrictions_ranges.put(property_name,ranges);
+ } else {
+ propertiesFromDataRestrictions_ranges.put(property_name, ranges);
+ }
- restrictionsValues.put("someValuesFrom", "");
- restrictionsValuesFromClass.put(property_name, restrictionsValues);
+ restrictionsValues.put("someValuesFrom", "");
+ this.restrictionsValuesFromClass.put(property_name, restrictionsValues);
}
}
@Override
public void visit( OWLDataUnionOf ce ) {
logger.info("Analyzing restrictions of Class: " + this.cls+ " with axiom: "+ce);
- Set ranges = ce.getOperands();
- Set properties = ce.getDataPropertiesInSignature();
- setBooleanCombinationDataProperties(ranges, properties, "unionOf");
+
+ // Loop through each item in the union and accept visits.
+ for (OWLDataRange e : ce.getOperands()) {
+ e.accept(this);
+ }
}
@Override
public void visit( OWLDataIntersectionOf ce ) {
logger.info("Analyzing restrictions of Class: " + this.cls+ " with axiom: "+ce);
- Set ranges = ce.getOperands();
- Set properties = ce.getDataPropertiesInSignature();
- setBooleanCombinationDataProperties(ranges, properties, "intersectionOf");
+
+ // Loop through each item in the intersection and accept visits.
+ for (OWLDataRange e : ce.getOperands()) {
+ e.accept(this);
+ }
}
@Override
@@ -303,44 +359,46 @@ public void visit( OWLDataExactCardinality ce ) {
@Override
public void visit( OWLDataOneOf ce ) {
- logger.info("Analyzing restrictions of Class: " + this.cls+ " with axiom: "+ce);
+ logger.info("Analyzing restrictions of Class: " + this.cls + " with axiom: " + ce);
List ranges = new ArrayList();
Map restrictionsValues = new HashMap();
- for (OWLLiteral value : ce.getValues()) {
- ranges.add(sfp.getShortForm(value.getDatatype().getIRI()));
- valuesFromDataRestrictions_ranges.add(value.getLiteral());
+
+ for (OWLLiteral value: ce.getValues()) {
+ ranges.add(this.sfp.getShortForm(value.getDatatype().getIRI()));
+ this.valuesFromDataRestrictions_ranges.add(value.getLiteral());
+ restrictionsValues.put("oneOf", "");
+ this.restrictionsValuesFromClass.put(this.property_name, restrictionsValues);
+ this.propertiesFromDataRestrictions_ranges.put(this.property_name, ranges);
}
- restrictionsValues.put("oneOf","");
- restrictionsValuesFromClass.put(property_name, restrictionsValues);
- propertiesFromDataRestrictions_ranges.put(property_name,ranges);
}
@Override
public void visit( OWLDataComplementOf ce ) {
- logger.info("Analyzing restrictions of Class: " + this.cls+ " with axiom: "+ce);
+ logger.info("Analyzing restrictions of Class: " + this.cls + " with axiom: " + ce);
List ranges = new ArrayList();
Map restrictionsValues = new HashMap();
- for (OWLDatatype value:ce.getDatatypesInSignature()){
- ranges.add(sfp.getShortForm(value.getIRI()));
- restrictionsValues.put("complementOf", "");
- restrictionsValuesFromClass.put(property_name, restrictionsValues);
- propertiesFromDataRestrictions_ranges.put(property_name,ranges);
+ for (OWLDatatype value: ce.getDatatypesInSignature()) {
+ ranges.add(this.sfp.getShortForm(value.getIRI()));
+ restrictionsValues.put("complementOf", "");
+ restrictionsValuesFromClass.put(this.property_name, restrictionsValues);
+ propertiesFromDataRestrictions_ranges.put(this.property_name, ranges);
}
}
@Override
public void visit( OWLDataHasValue ce ) {
- logger.info("Analyzing restrictions of Class: " + this.cls+ " with axiom: "+ce);
+ logger.info("Analyzing restrictions of Class: " + this.cls + " with axiom: " + ce);
List ranges = new ArrayList();
Map restrictionsValues = new HashMap();
- for(OWLDataProperty property:ce.getDataPropertiesInSignature()) {
- property_name = sfp.getShortForm(property.getIRI());
+ for(OWLDataProperty property: ce.getDataPropertiesInSignature()) {
+ property_name = this.sfp.getShortForm(property.getIRI());
propertiesFromDataRestrictions.add(property);
- restrictionsValues.put("dataHasValue",ce.getValue().getLiteral());
+ restrictionsValues.put("dataHasValue", ce.getFiller().getLiteral());
restrictionsValuesFromClass.put(property_name, restrictionsValues);
- for (OWLDatatype value:ce.getDatatypesInSignature()){
- ranges.add(sfp.getShortForm(value.getIRI()));
- propertiesFromDataRestrictions_ranges.put(property_name,ranges);
+
+ for (OWLDatatype value: ce.getDatatypesInSignature()) {
+ ranges.add(this.sfp.getShortForm(value.getIRI()));
+ propertiesFromDataRestrictions_ranges.put(this.property_name, ranges);
}
}
}
@@ -373,24 +431,8 @@ public void setPropertiesWithCardinality(OWLObjectCardinalityRestriction ce, Str
* @param restriction string value of restriction e.g. "unionOf"
*/
public void setBooleanCombinationProperties( Set ranges, Set properties, String restriction) {
- Boolean inspect=true;
Map restrictionsValues = new HashMap();
- for (OWLClassExpression value :ranges) {
- //if operands from boolean restriction contain complex combinations the restriction on this property
- // will be ignored
- if (value instanceof OWLObjectIntersectionOf || value instanceof OWLObjectComplementOf || value instanceof OWLObjectSomeValuesFrom || value instanceof OWLObjectAllValuesFrom
- || value instanceof OWLObjectHasValue) {
- logger.warning("Ignoring complex range restriction of property "+ property_name);
- if (property_name!="") {
- propertiesFromObjectRestrictions.remove(property_name);
- restrictionsValuesFromClass.remove(property_name);
- }
- inspect=false;
- }
- }
- // if there are not complex range restrictions inspect ce
- if (inspect) {
- //if the expression ce is not part of a composed expression (existencial or universal)
+ //if the expression ce is not part of a composed expression (existential or universal)
if (property_name.isEmpty()) {
for(OWLObjectProperty property:properties) {
propertiesFromObjectRestrictions.add(property);
@@ -410,7 +452,7 @@ public void setBooleanCombinationProperties( Set ranges, Set
}
}
- if (restrictionsValuesFromClass.size()!=0) {
+ if (!restrictionsValuesFromClass.isEmpty()) {
for (String j : restrictionsValuesFromClass.keySet()) {
if (j.equals(property_name)) {
Map value = restrictionsValuesFromClass.get(property_name);
@@ -420,13 +462,11 @@ public void setBooleanCombinationProperties( Set ranges, Set
restrictionsValuesFromClass.put(property_name, restrictionsValues);
}
}
- }
- else {
+ } else {
restrictionsValues.put(restriction, "");
restrictionsValuesFromClass.put(property_name, restrictionsValues);
}
- }
- }
+ }
}
/**
@@ -436,24 +476,8 @@ public void setBooleanCombinationProperties( Set ranges, Set
* @param restriction string value of restriction e.g. "unionOf"
*/
public void setBooleanCombinationDataProperties( Set ranges, Set properties, String restriction) {
- Boolean inspect=true;
Map restrictionsValues = new HashMap();
- for (OWLDataRange value :ranges) {
- //if operands from boolean restriction contain complex combinations the restriction on this property
- // will be ignored
- if (value instanceof OWLDataIntersectionOf || value instanceof OWLDataComplementOf || value instanceof OWLDataSomeValuesFrom || value instanceof OWLDataAllValuesFrom
- || value instanceof OWLDataHasValue) {
- logger.warning("Ignoring complex range restriction of property "+ property_name);
- if (!property_name.equals("")) {
- propertiesFromDataRestrictions.remove(property_name);
- restrictionsValuesFromClass.remove(property_name);
- }
- inspect=false;
- }
- }
- // if there are not complex range restrictions inspect ce
- if (inspect) {
- //if the expression ce is not part of a composed expression (existencial or universal)
+ //if the expression ce is not part of a composed expression (existential or universal)
if (property_name.equals("")) {
for(OWLDataProperty property:properties) {
propertiesFromDataRestrictions.add(property);
@@ -472,11 +496,11 @@ public void setBooleanCombinationDataProperties( Set ranges, Set value = restrictionsValuesFromClass.get(property_name);
- for (String i : value.keySet() ) {
+ for (String i : value.keySet()) {
restrictionsValues.put(restriction, i);
}
restrictionsValuesFromClass.put(property_name, restrictionsValues);
@@ -488,8 +512,7 @@ public void setBooleanCombinationDataProperties( Set ranges, Set> getRestrictionsValuesFromClass(){
- return restrictionsValuesFromClass;
+ public Map> getRestrictionsValuesFromClass() {
+ return this.restrictionsValuesFromClass;
}
- public List getPropertiesFromObjectRestrictions(){
- return propertiesFromObjectRestrictions;
+ public List getPropertiesFromObjectRestrictions() {
+ return this.propertiesFromObjectRestrictions;
}
- public Map> getPropertiesFromObjectRestrictions_ranges(){
- return propertiesFromObjectRestrictions_ranges;
+ public Map> getPropertiesFromObjectRestrictions_ranges() {
+ return this.propertiesFromObjectRestrictions_ranges;
}
- public List getPropertiesFromDataRestrictions(){
- return propertiesFromDataRestrictions;
+ public List getPropertiesFromDataRestrictions() {
+ return this.propertiesFromDataRestrictions;
}
- public List getValuesFromDataRestrictions_ranges(){
- return valuesFromDataRestrictions_ranges;
+ public List getValuesFromDataRestrictions_ranges() {
+ return this.valuesFromDataRestrictions_ranges;
}
- public Map> getPropertiesFromDataRestrictions_ranges(){
- return propertiesFromDataRestrictions_ranges;
+ public Map> getPropertiesFromDataRestrictions_ranges() {
+ return this.propertiesFromDataRestrictions_ranges;
+ }
+
+ public List getEnums(IRI classIRI) {
+ return this.enums.get(classIRI);
}
+ public Map> getAllEnums() {
+ return this.enums;
+ }
}
diff --git a/src/main/java/edu/isi/oba/Serializer.java b/src/main/java/edu/isi/oba/Serializer.java
index d57dc92..7d72503 100644
--- a/src/main/java/edu/isi/oba/Serializer.java
+++ b/src/main/java/edu/isi/oba/Serializer.java
@@ -1,20 +1,17 @@
package edu.isi.oba;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.util.*;
import io.swagger.parser.OpenAPIParser;
import io.swagger.v3.oas.models.*;
import io.swagger.v3.oas.models.security.SecurityScheme;
-
import io.swagger.v3.parser.core.models.ParseOptions;
import io.swagger.v3.parser.core.models.SwaggerParseResult;
-import org.openapitools.codegen.serializer.SerializerUtils;
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.nio.file.Files;
-import java.util.*;
+import org.openapitools.codegen.serializer.SerializerUtils;
class Serializer {
//TODO: validate the yaml
@@ -65,7 +62,7 @@ private void validate() throws Exception {
List messageList = result.getMessages();
Set errors = new HashSet<>(messageList);
Set warnings = new HashSet<>();
- if (errors.size() > 0) {
+ if (!errors.isEmpty()) {
throw new Exception("Error when validating the API specification. " + errors.iterator().next());
}
}
diff --git a/src/main/java/edu/isi/oba/config/CONFIG_FLAG.java b/src/main/java/edu/isi/oba/config/CONFIG_FLAG.java
new file mode 100644
index 0000000..f85e99e
--- /dev/null
+++ b/src/main/java/edu/isi/oba/config/CONFIG_FLAG.java
@@ -0,0 +1,14 @@
+package edu.isi.oba.config;
+
+public enum CONFIG_FLAG {
+ ALWAYS_GENERATE_ARRAYS,
+ DEFAULT_DESCRIPTIONS,
+ DEFAULT_PROPERTIES,
+ FOLLOW_REFERENCES,
+ PATH_DELETE,
+ PATH_GET,
+ PATH_PATCH,
+ PATH_POST,
+ PATH_PUT,
+ REQUIRED_PROPERTIES_FROM_CARDINALITY,
+}
diff --git a/src/main/java/edu/isi/oba/config/YamlConfig.java b/src/main/java/edu/isi/oba/config/YamlConfig.java
index 4573950..d0e9b31 100644
--- a/src/main/java/edu/isi/oba/config/YamlConfig.java
+++ b/src/main/java/edu/isi/oba/config/YamlConfig.java
@@ -3,66 +3,80 @@
import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.PathItem;
+import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
-
public class YamlConfig {
+ private final Map configFlags = new HashMap<>(){{
+ put(CONFIG_FLAG.ALWAYS_GENERATE_ARRAYS, true);
+ put(CONFIG_FLAG.DEFAULT_DESCRIPTIONS, true);
+ put(CONFIG_FLAG.DEFAULT_PROPERTIES, true);
+ put(CONFIG_FLAG.FOLLOW_REFERENCES, true);
+ put(CONFIG_FLAG.PATH_DELETE, false);
+ put(CONFIG_FLAG.PATH_GET, true);
+ put(CONFIG_FLAG.PATH_PATCH, false);
+ put(CONFIG_FLAG.PATH_POST, false);
+ put(CONFIG_FLAG.PATH_PUT, false);
+ put(CONFIG_FLAG.REQUIRED_PROPERTIES_FROM_CARDINALITY, false);
+ }};
+
String DEFAULT_OUTPUT_DIRECTORY = "outputs";
String DEFAULT_PROJECT_NAME = "default_project";
public OpenAPI openapi;
public String output_dir = DEFAULT_OUTPUT_DIRECTORY;
public String name = DEFAULT_PROJECT_NAME;
public List paths;
- public Boolean enable_get_paths = true;
- public Boolean enable_post_paths = false;
- public Boolean enable_put_paths = false;
- public Boolean enable_delete_paths = false;
public List ontologies;
private EndpointConfig endpoint;
-
public AuthConfig auth;
public FirebaseConfig firebase;
public Map> relations;
private LinkedHashMap custom_paths = null;
public List classes;
- public Boolean follow_references = false;
+ public String custom_queries_directory;
public Boolean getEnable_get_paths() {
- return enable_get_paths;
+ return this.configFlags.get(CONFIG_FLAG.PATH_GET);
}
public void setEnable_get_paths(Boolean enable_get_paths) {
- this.enable_get_paths = enable_get_paths;
+ this.configFlags.put(CONFIG_FLAG.PATH_GET, enable_get_paths);
+ }
+
+ public Boolean getEnable_patch_paths() {
+ return this.configFlags.get(CONFIG_FLAG.PATH_PATCH);
+ }
+
+ public void setEnable_patch_paths(Boolean enable_patch_paths) {
+ this.configFlags.put(CONFIG_FLAG.PATH_PATCH, enable_patch_paths);
}
public Boolean getEnable_post_paths() {
- return enable_post_paths;
+ return this.configFlags.get(CONFIG_FLAG.PATH_POST);
}
public void setEnable_post_paths(Boolean enable_post_paths) {
- this.enable_post_paths = enable_post_paths;
+ this.configFlags.put(CONFIG_FLAG.PATH_POST, enable_post_paths);
}
public Boolean getEnable_put_paths() {
- return enable_put_paths;
+ return this.configFlags.get(CONFIG_FLAG.PATH_PUT);
}
public void setEnable_put_paths(Boolean enable_put_paths) {
- this.enable_put_paths = enable_put_paths;
+ this.configFlags.put(CONFIG_FLAG.PATH_PUT, enable_put_paths);
}
public Boolean getEnable_delete_paths() {
- return enable_delete_paths;
+ return this.configFlags.get(CONFIG_FLAG.PATH_DELETE);
}
public void setEnable_delete_paths(Boolean enable_delete_paths) {
- this.enable_delete_paths = enable_delete_paths;
+ this.configFlags.put(CONFIG_FLAG.PATH_DELETE, enable_delete_paths);
}
- public String custom_queries_directory;
-
public String getCustom_queries_directory() {
return custom_queries_directory;
}
@@ -127,7 +141,6 @@ public void setRelations(Map> relations) {
this.relations = relations;
}
-
public LinkedHashMap getCustom_paths() {
return custom_paths;
}
@@ -144,20 +157,52 @@ public void setOpenapi(OpenAPI openapi) {
this.openapi = openapi;
}
- public List getClasses() {
- return this.classes;
- }
+ public List getClasses() {
+ return this.classes;
+ }
public void setClasses(List classes) {
this.classes = classes;
}
+ public Boolean getAlways_generate_arrays() {
+ return this.configFlags.get(CONFIG_FLAG.ALWAYS_GENERATE_ARRAYS);
+ }
+
+ public void setAlways_generate_arrays(Boolean always_generate_arrays) {
+ this.configFlags.put(CONFIG_FLAG.ALWAYS_GENERATE_ARRAYS, always_generate_arrays);
+ }
+
public Boolean getFollow_references() {
- return follow_references;
+ return this.configFlags.get(CONFIG_FLAG.FOLLOW_REFERENCES);
}
public void setFollow_references(Boolean follow_references) {
- this.follow_references = follow_references;
+ this.configFlags.put(CONFIG_FLAG.FOLLOW_REFERENCES, follow_references);
+ }
+
+ public Boolean getDefault_descriptions() {
+ return this.configFlags.get(CONFIG_FLAG.DEFAULT_DESCRIPTIONS);
+ }
+
+ public void setDefault_descriptions(Boolean default_descriptions) {
+ this.configFlags.put(CONFIG_FLAG.DEFAULT_DESCRIPTIONS, default_descriptions);
+ }
+
+ public Boolean getDefault_properties() {
+ return this.configFlags.get(CONFIG_FLAG.DEFAULT_PROPERTIES);
+ }
+
+ public void setDefault_properties(Boolean default_properties) {
+ this.configFlags.put(CONFIG_FLAG.DEFAULT_PROPERTIES, default_properties);
+ }
+
+ public Boolean getRequired_properties_from_cardinality() {
+ return this.configFlags.get(CONFIG_FLAG.REQUIRED_PROPERTIES_FROM_CARDINALITY);
+ }
+
+ public void setRequired_properties_from_cardinality(Boolean required_properties_from_cardinality) {
+ this.configFlags.put(CONFIG_FLAG.REQUIRED_PROPERTIES_FROM_CARDINALITY, required_properties_from_cardinality);
}
public AuthConfig getAuth() {
@@ -167,5 +212,23 @@ public AuthConfig getAuth() {
public void setAuth(AuthConfig auth) {
this.auth = auth;
}
-}
+ /**
+ * Get the value of a particular configuration flag.
+ *
+ * @param {flag} the configuration flag name
+ * @return The flag's value (true/false/null).
+ */
+ public Boolean getConfigFlagValue(CONFIG_FLAG flag) {
+ return this.configFlags.get(flag);
+ }
+
+ /**
+ * Get map of all config flags and their values.
+ *
+ * @return Map of CONFIG_FLAGs and their Boolean value (true/false/null).
+ */
+ public Map getConfigFlags() {
+ return this.configFlags;
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/edu/isi/oba/MapperTest.java b/src/test/java/edu/isi/oba/MapperTest.java
index 9048d5a..62c01e7 100644
--- a/src/test/java/edu/isi/oba/MapperTest.java
+++ b/src/test/java/edu/isi/oba/MapperTest.java
@@ -1,26 +1,28 @@
package edu.isi.oba;
+import static edu.isi.oba.ObaUtils.get_yaml_data;
import edu.isi.oba.config.AuthConfig;
+import edu.isi.oba.config.CONFIG_FLAG;
import edu.isi.oba.config.YamlConfig;
-import io.swagger.v3.oas.models.PathItem;
-import io.swagger.v3.oas.models.media.Schema;
-import org.junit.Assert;
-import org.junit.Test;
-import org.semanticweb.owlapi.model.OWLClass;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.LinkedHashMap;
import java.util.List;
+import java.util.Map;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
-import static edu.isi.oba.ObaUtils.get_yaml_data;
+import io.swagger.v3.oas.models.media.Schema;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import org.semanticweb.owlapi.model.OWLClass;
public class MapperTest {
@Test
@@ -36,7 +38,7 @@ public void testFilter() throws Exception{
}
Collections.sort(filter_classes);
Collections.sort(config);
- Assert.assertEquals(config, filter_classes);
+ Assertions.assertEquals(config, filter_classes);
}
@@ -49,7 +51,7 @@ public void testLocalFile() throws Exception{
String local_ontology = "src/test/config/mcat_reduced.yaml";
YamlConfig config_data = get_yaml_data(local_ontology);
Mapper mapper = new Mapper(config_data);
- Assert.assertEquals(false, mapper.ontologies.isEmpty());
+ Assertions.assertEquals(false, mapper.ontologies.isEmpty());
}
/**
@@ -61,7 +63,7 @@ public void testSpacesInPath() throws Exception{
String local_ontology = "examples/example with spaces/config.yaml";
YamlConfig config_data = get_yaml_data(local_ontology);
Mapper mapper = new Mapper(config_data);
- Assert.assertEquals(false, mapper.ontologies.isEmpty());
+ Assertions.assertEquals(false, mapper.ontologies.isEmpty());
}
/**
@@ -75,7 +77,7 @@ public void testRemoteOntology() throws Exception{
String example_remote = "src/test/config/pplan.yaml";
YamlConfig config_data = get_yaml_data(example_remote);
Mapper mapper = new Mapper(config_data);
- Assert.assertEquals(false, mapper.ontologies.isEmpty());
+ Assertions.assertEquals(false, mapper.ontologies.isEmpty());
}
@@ -87,7 +89,7 @@ public void testMissingImportOntology() throws Exception{
String example_remote = "src/test/resources/missing_import/config.yaml";
YamlConfig config_data = get_yaml_data(example_remote);
Mapper mapper = new Mapper(config_data);
- Assert.assertEquals(false, mapper.ontologies.isEmpty());
+ Assertions.assertEquals(false, mapper.ontologies.isEmpty());
}
/**
@@ -111,11 +113,11 @@ public void testComplexOntology() throws Exception{
config_data.setAuth(new AuthConfig());
Mapper mapper = new Mapper(config_data);
OWLClass cls = mapper.manager.getOWLDataFactory().getOWLClass("https://businessontology.com/ontology/Person");
- String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0));
- MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), true);
+ String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0), true);
+ MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), Map.ofEntries(Map.entry(CONFIG_FLAG.DEFAULT_DESCRIPTIONS, true), Map.entry(CONFIG_FLAG.DEFAULT_PROPERTIES, true), Map.entry(CONFIG_FLAG.FOLLOW_REFERENCES, true)));
Schema schema = mapperSchema.getSchema();
// The person schema must not be null.
- Assert.assertNotNull(schema);
- Assert.assertEquals(schema.getName(),"Person");
+ Assertions.assertNotNull(schema);
+ Assertions.assertEquals(schema.getName(),"Person");
}
}
diff --git a/src/test/java/edu/isi/oba/ObaUtilsTest.java b/src/test/java/edu/isi/oba/ObaUtilsTest.java
index 4609d09..c32f380 100644
--- a/src/test/java/edu/isi/oba/ObaUtilsTest.java
+++ b/src/test/java/edu/isi/oba/ObaUtilsTest.java
@@ -2,14 +2,14 @@
import static edu.isi.oba.ObaUtils.get_yaml_data;
import edu.isi.oba.config.YamlConfig;
-import java.io.File;
-import org.json.JSONObject;
-import org.junit.Assert;
-import org.junit.Test;
+import java.io.File;
import java.io.IOException;
-import static org.junit.Assert.*;
+import org.json.JSONObject;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
@@ -19,7 +19,7 @@ public class ObaUtilsTest {
@Test
public void read_json_file() throws IOException {
JSONObject actual = ObaUtils.read_json_file("json_one.json");
- Assert.assertNotNull(actual.get("@context"));
+ Assertions.assertNotNull(actual.get("@context"));
}
@Test
@@ -27,8 +27,8 @@ public void mergeJSONObjects() throws IOException {
JSONObject one = ObaUtils.read_json_file("json_one.json");
JSONObject two = ObaUtils.read_json_file("json_two.json");
JSONObject merge = ObaUtils.mergeJSONObjects(one, two);
- Assert.assertNotNull(merge.get("@context"));
- Assert.assertNotNull(merge.get("@context"));
+ Assertions.assertNotNull(merge.get("@context"));
+ Assertions.assertNotNull(merge.get("@context"));
}
@Test
@@ -39,9 +39,9 @@ public void concat_json_common_key() throws IOException {
JSONObject[] jsons = new JSONObject[]{ one, two, three};
JSONObject merge = ObaUtils.concat_json_common_key(jsons, "@context");
JSONObject o = (JSONObject) merge.get("@context");
- assertNotNull(o.get("Entity"));
- assertNotNull(o.get("Model"));
- assertNotNull(o.get("Setup"));
+ Assertions.assertNotNull(o.get("Entity"));
+ Assertions.assertNotNull(o.get("Model"));
+ Assertions.assertNotNull(o.get("Setup"));
}
@Test
@@ -51,10 +51,10 @@ public void getDescription () throws OWLOntologyCreationException{
try {
Mapper mapper = new Mapper(config_data);
OWLClass planClass = mapper.manager.getOWLDataFactory().getOWLClass("http://purl.org/net/p-plan#Plan");
- String desc = ObaUtils.getDescription(planClass, mapper.ontologies.get(0));
- assertNotEquals(desc, "");
+ String desc = ObaUtils.getDescription(planClass, mapper.ontologies.get(0), true);
+ Assertions.assertNotEquals(desc, "");
}catch(Exception e){
- fail();
+ Assertions.fail("Failed to get description.", e);
}
}
@@ -69,8 +69,7 @@ public void missing_file () throws OWLOntologyCreationException{
YamlConfig config_data = get_yaml_data(missing_file);
try {
Mapper mapper = new Mapper(config_data);
- //if no exception is launched, fail test
- fail();
+ Assertions.fail("Missing file: If no exception is launched, fail test");
}catch(Exception e){
//pass test if there is an exception
}
@@ -78,8 +77,8 @@ public void missing_file () throws OWLOntologyCreationException{
@Test
public void run() {
- String ontology1 = "https://mintproject.github.io/Mint-ModelCatalog-Ontology/release/1.4.0/ontology.xml";
- String ontology2 = "https://knowledgecaptureanddiscovery.github.io/SoftwareDescriptionOntology/release/1.5.0/ontology.xml";
+ String ontology1 = "https://mintproject.github.io/Mint-ModelCatalog-Ontology/release/1.8.0/ontology.owl";
+ String ontology2 = "https://knowledgecaptureanddiscovery.github.io/SoftwareDescriptionOntology/release/1.9.0/ontology.owl";
File ont1 = new File("ontology1");
File ont2 = new File("ontology2");
ObaUtils.downloadOntology(ontology1, ont1.getPath());
@@ -91,17 +90,17 @@ public void run() {
} catch (Exception e) {
e.printStackTrace();
}
+
JSONObject o = (JSONObject) context.get("@context");
- assertEquals(o.get("id"), "@id");
- assertEquals(o.get("type"), "@type");
- assertNotNull(o.get("Entity"));
- assertNotNull(o.get("Model"));
+ Assertions.assertEquals(o.get("id"), "@id");
+ Assertions.assertEquals(o.get("type"), "@type");
+ Assertions.assertNotNull(o.get("Entity"));
+ Assertions.assertNotNull(o.get("Model"));
try{
java.nio.file.Files.delete(ont1.toPath());
java.nio.file.Files.delete(ont2.toPath());
}catch(Exception e){
}
-
}
}
\ No newline at end of file
diff --git a/src/test/java/edu/isi/oba/RestrictionsTest.java b/src/test/java/edu/isi/oba/RestrictionsTest.java
index 4cdea86..ed575ea 100644
--- a/src/test/java/edu/isi/oba/RestrictionsTest.java
+++ b/src/test/java/edu/isi/oba/RestrictionsTest.java
@@ -1,25 +1,27 @@
package edu.isi.oba;
-
import static edu.isi.oba.ObaUtils.get_yaml_data;
-import static org.junit.Assert.*;
+import edu.isi.oba.config.CONFIG_FLAG;
+import edu.isi.oba.config.YamlConfig;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.logging.ConsoleHandler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
-import org.junit.Ignore;
-import org.junit.Test;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+
import org.semanticweb.owlapi.model.OWLClass;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
-
-import edu.isi.oba.config.YamlConfig;
import io.swagger.v3.oas.models.media.ArraySchema;
import io.swagger.v3.oas.models.media.ComposedSchema;
import io.swagger.v3.oas.models.media.ObjectSchema;
@@ -27,6 +29,15 @@
public class RestrictionsTest {
static Logger logger = null;
+
+ // Convenience variable so we don't need to retype this for each MapperSchema constructor.
+ private Map configFlags = new HashMap<>(){{
+ put(CONFIG_FLAG.ALWAYS_GENERATE_ARRAYS, true);
+ put(CONFIG_FLAG.DEFAULT_DESCRIPTIONS, true);
+ put(CONFIG_FLAG.DEFAULT_PROPERTIES, true);
+ put(CONFIG_FLAG.FOLLOW_REFERENCES, true);
+ put(CONFIG_FLAG.REQUIRED_PROPERTIES_FROM_CARDINALITY, false);
+ }};
/**
* This method allows you to configure the logger variable that is required to print several
@@ -56,16 +67,16 @@ public void testFunctionalObjectProperty() throws OWLOntologyCreationException,
YamlConfig config_data = get_yaml_data("examples/restrictions/config.yaml");
Mapper mapper = new Mapper(config_data);
OWLClass cls = mapper.manager.getOWLDataFactory().getOWLClass("https://w3id.org/example#University");
- String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0));
- MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), true);
- Schema schema = mapperSchema.getSchema();
- Object property= schema.getProperties().get("hasRector");
- if (property instanceof io.swagger.v3.oas.models.media.ArraySchema) {
+ String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0), true);
+ MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), this.configFlags);
+ Schema schema = mapperSchema.getSchema();
+ Object property = schema.getProperties().get("hasRector");
+ if (property instanceof io.swagger.v3.oas.models.media.ArraySchema) {
Integer maxItems = ((ArraySchema) property).getMaxItems();
- assertEquals(expectedResult,maxItems);
- }
- } catch (OWLOntologyCreationException e) {
- assertTrue("error in ontology creation", false);
+ Assertions.assertEquals(expectedResult, maxItems);
+ }
+ } catch (OWLOntologyCreationException e) {
+ Assertions.fail("Error in ontology creation: ", e);
}
}
@@ -73,32 +84,32 @@ public void testFunctionalObjectProperty() throws OWLOntologyCreationException,
* This test attempts to get the OAS representation of a ObjectUnionOf restriction.
*/
@Test
- public void testObjectUnionOf() throws OWLOntologyCreationException, Exception {
+ public void testObjectUnionOf() throws OWLOntologyCreationException, Exception {
List expectedResult = new ArrayList();
expectedResult.add("#/components/schemas/Organization");
expectedResult.add("#/components/schemas/Person");
- try {
+ try {
this.initializeLogger();
YamlConfig config_data = get_yaml_data("examples/restrictions/config.yaml");
Mapper mapper = new Mapper(config_data);
OWLClass cls = mapper.manager.getOWLDataFactory().getOWLClass("https://w3id.org/example#StudyMaterial");
- String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0));
- MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), true);
- Schema schema = mapperSchema.getSchema();
- Object property= schema.getProperties().get("author");
- if (property instanceof ArraySchema) {
+ String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0), true);
+ MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), this.configFlags);
+ Schema schema = mapperSchema.getSchema();
+ Object property = schema.getProperties().get("author");
+ if (property instanceof ArraySchema) {
Schema items = ((ArraySchema) property).getItems();
List itemsValue;
if (items instanceof ComposedSchema) {
- itemsValue =((ComposedSchema) items).getAnyOf();
- for (int i=0; i expectedResult = new ArrayList();
+ List expectedResult = new ArrayList();
expectedResult.add("#/components/schemas/Assignment");
expectedResult.add("#/components/schemas/Exam");
@@ -116,23 +127,23 @@ public void testObjectIntersectionOf() throws OWLOntologyCreationException, Exce
YamlConfig config_data = get_yaml_data("examples/restrictions/config.yaml");
Mapper mapper = new Mapper(config_data);
OWLClass cls = mapper.manager.getOWLDataFactory().getOWLClass("https://w3id.org/example#Course");
- String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0));
- MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), true);
- Schema schema = mapperSchema.getSchema();
- Object property= schema.getProperties().get("hasEvaluationMethod");
- if (property instanceof ArraySchema) {
+ String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0), true);
+ MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), this.configFlags);
+ Schema schema = mapperSchema.getSchema();
+ Object property = schema.getProperties().get("hasEvaluationMethod");
+ if (property instanceof ArraySchema) {
Schema items = ((ArraySchema) property).getItems();
List itemsValue;
if (items instanceof ComposedSchema) {
- itemsValue =((ComposedSchema) items).getAllOf();
- for (int i=0; i expectedResult = new ArrayList();
+ List expectedResult = new ArrayList();
expectedResult.add("#/components/schemas/BachelorProgram");
expectedResult.add("#/components/schemas/MasterProgram");
expectedResult.add("#/components/schemas/PhDProgram");
@@ -176,56 +188,105 @@ public void testObjectSomeValuesFrom_ComposedByRestriction() throws OWLOntologyC
YamlConfig config_data = get_yaml_data("examples/restrictions/config.yaml");
Mapper mapper = new Mapper(config_data);
OWLClass cls = mapper.manager.getOWLDataFactory().getOWLClass("https://w3id.org/example#Student");
- String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0));
- MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), true);
- Schema schema = mapperSchema.getSchema();
- Object property= schema.getProperties().get("enrolledIn");
- if (property instanceof ArraySchema) {
+ String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0), true);
+ MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), this.configFlags);
+ Schema schema = mapperSchema.getSchema();
+ Object property = schema.getProperties().get("enrolledIn");
+ if (property instanceof ArraySchema) {
Boolean nullable = ((ArraySchema) property).getNullable();
Schema items = ((ArraySchema) property).getItems();
List itemsValue;
if (items instanceof ComposedSchema) {
- itemsValue =((ComposedSchema) items).getAnyOf();
- for (int i=0; i"
+ // resolves to the default value of: "ArtificialIntelligenceDepartment".
+ String expectedResult = "ArtificialIntelligenceDepartment";
YamlConfig config_data = get_yaml_data("examples/restrictions/config.yaml");
Mapper mapper = new Mapper(config_data);
OWLClass cls = mapper.manager.getOWLDataFactory().getOWLClass("https://w3id.org/example#ProfessorInArtificialIntelligence");
- String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0));
- MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), true);
- Schema schema = mapperSchema.getSchema();
- Object property= schema.getProperties().get("belongsTo");
- if (((ObjectSchema) property).getDefault()!=null)
- assertEquals(((ObjectSchema) property).getDefault(),expectedResult);
- else
- assertTrue("Wrong configuration of ObjectHasValue restriction", false);
-
- } catch (OWLOntologyCreationException e) {
- assertTrue("Error in ontology creation", false);
- }
+ String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0), true);
+ MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), this.configFlags);
+ Schema schema = mapperSchema.getSchema();
+ Object property = schema.getProperties().get("belongsTo");
+
+ if (property instanceof ArraySchema) {
+ Schema items = ((ArraySchema) property).getItems();
+ if (items != null && (items.getAllOf() != null && !items.getAllOf().isEmpty())) {
+ for (var item: items.getAllOf()) {
+ if (((ObjectSchema) item).getDefault() != null) {
+ Assertions.assertEquals(expectedResult, ((ObjectSchema) item).getDefault());
+ return;
+ }
+ }
+
+ // If we reach here, then none of the items had a default value, so fail.
+ Assertions.fail("Wrong configuration of ObjectHasValue restriction.");
+ } else {
+ Assertions.fail("Wrong configuration of ObjectHasValue restriction.");
+ }
+ } else {
+ Assertions.fail("Wrong configuration of ObjectHasValue restriction.");
+ }
+ } catch (OWLOntologyCreationException e) {
+ Assertions.fail("Error in ontology creation: ", e);
+ }
}
/**
@@ -350,29 +432,27 @@ public void testObjectOneOf() throws OWLOntologyCreationException, Exception {
YamlConfig config_data = get_yaml_data("examples/restrictions/config.yaml");
Mapper mapper = new Mapper(config_data);
OWLClass cls = mapper.manager.getOWLDataFactory().getOWLClass("https://w3id.org/example#Professor");
- String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0));
- MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), true);
- Schema schema = mapperSchema.getSchema();
- Object property= schema.getProperties().get("hasDegree");
+ String desc = ObaUtils.getDescription(cls, mapper.ontologies.get(0), true);
+ MapperSchema mapperSchema = new MapperSchema(mapper.ontologies, cls, desc, mapper.schemaNames, mapper.ontologies.get(0), this.configFlags);
+ Schema schema = mapperSchema.getSchema();
+ Object property = schema.getProperties().get("hasDegree");
- if (property instanceof ArraySchema) {
+ if (property instanceof ArraySchema) {
Schema items = ((ArraySchema) property).getItems();
List