diff --git a/.gitignore b/.gitignore index 46cdc0f81..def6421af 100644 --- a/.gitignore +++ b/.gitignore @@ -22,40 +22,19 @@ ### VS Code ### .vscode/ wrapper -/authorization/target -/core-common/target -/eventhandler/target -/gatekeeper/target -/gateway/target +/target +/**/target /mvnw /mvnw.cmd -/orchestrator/target -/serviceregistry/target /.settings -/authorization/.settings -/core-common/.settings -/eventhandler/.settings/*.prefs -/eventhandler/.settings +/**/.settings *.prefs -/gatekeeper/.settings -/gateway/.settings -/orchestrator/.settings -/serviceregistry/.settings +/*.log +/**/*.log -/serviceregistry/*.log -/authorization/*.log /.metadata/ -gatekeeper/gatekeeper\.log -/eventhandler/*.log -/orchestrator/*.log -/choreographer/*.log -choreographer.log -serviceregistry.log -authorization.log -/choreographer/target - -*.log -/target /deb-installer/.classpath /deb-installer/.project /deb-installer/.settings +/qos-monitor/.settings +/qos-monitor/target diff --git a/README.md b/README.md index ba608b505..b5634e984 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,4 @@ + # Arrowhead Framework 4.1.3 [Arrowhead](http://www.arrowhead.eu/) (and its continuation, [Productive4.0](https://productive40.eu/)) is an ambitious holistic innovation project, @@ -10,7 +11,10 @@ Please be aware, that 4.1.3 is __NOT__ backwards compatible with 4.1.2. If you h ## Table of Contents 1. [Quick Start Guide](#quickstart) 1. [Docker](#quickstart_docker) - * [Handy Docker Commands](#quickstart_dockercommands) + * [System Requirements](#quickstart_dockersysreqs) + * [Examples](#quickstart_examples) + * [Guide](#quickstart_dockerguide) + * [Cheat-Sheet](#quickstart_dockercommands) * [Troubleshooting](#quickstart_dockertroubleshooting) 2. [Debian Installer](#quickstart_debian) 3. [Compile Code](#quickstart_compile) @@ -70,6 +74,41 @@ Please be aware, that 4.1.3 is __NOT__ backwards compatible with 4.1.2. If you h * [Client](#gateway_endpoints_client) * [Private](#gateway_endpoints_private) * [Management](#gateway_endpoints_mgmt) + 7. [Certificate Authority](#ca) + * [System Design Description Overview](#ca_sdd) + * [Services and Use Cases](#ca_usecases) + * [Endpoints](#ca_endpoints) + * [Client](#ca_endpoints_client) + * [Private](#ca_endpoints_private) + * [Management](#ca_endpoints_mgmt) + 8. [QoS Monitor (Quality of Service Monitor)](#qos_monitor) + * [System Design Description Overview](#qos_monitor_sdd) + * [Services and Use Cases](#qos_monitor_usecases) + * [Endpoints](#qos_monitor_endpoints) + * [Client](#qos_monitor_endpoints_client) + * [Private](#qos_monitor_endpoints_private) + * [Management](#qos_monitor_endpoints_mgmt) + 9. [Onboarding Controller](#onboardingcontroller) + * [System Design Description Overview](#onboardingcontroller_sdd) + * [Services and Use Cases](#onboardingcontroller_usecases) + * [Security](#onboardingcontroller_security) + * [Endpoints](#onboardingcontroller_endpoints) + * [Onboarding](#onboardingcontroller_endpoints_onboarding) + 9. [Device Registry](#deviceregistry) + * [System Design Description Overview](#deviceregistry_sdd) + * [Services and Use Cases](#deviceregistry_usecases) + * [Security](#deviceregistry_security) + * [Endpoints](#deviceregistry_endpoints) + * [Onboarding](#deviceregistry_endpoints_onboarding) + * [Client](#deviceregistry_endpoints_client) + 9. [System Registry](#systemregistry) + * [System Design Description Overview](#systemregistry_sdd) + * [Services and Use Cases](#systemregistry_usecases) + * [Security](#systemregistry_security) + * [Endpoints](#systemregistry_endpoints) + * [Onboarding](#systemregistry_endpoints_onboarding) + * [Client](#systemregistry_endpoints_client) + @@ -79,7 +118,13 @@ Please be aware, that 4.1.3 is __NOT__ backwards compatible with 4.1.2. If you h ### Docker -#### Requirements +[Docker](https://docs.docker.com/) is a container platform that can be used to package and deploy applications in server environments, among other. +In particular, the [`docker-compose`](https://docs.docker.com/compose/) utility may with advantage be used during application development to test integration with the Arrowhead Core systems. +Here, we provide brief instructions on how to install and run both Docker and container images for the Arrowhead Core systems. + + + +#### System Requirements > **Note:** A system with 4GB of RAM is advised. @@ -90,6 +135,8 @@ Please be aware, that 4.1.3 is __NOT__ backwards compatible with 4.1.2. If you h * [Windows](https://docs.docker.com/docker-for-windows/install/) * [Docker Compose](https://docs.docker.com/compose/install/) + + Don't forget to create a volume for mysql: `docker volume create --name=mysql`
Don't forget to copy the `initSQL.sh` script next to the docker-compose file and execute it! On the first run it initializes the Database!
Example copy command which does this for you, execute from the project root directory. @@ -99,17 +146,21 @@ cd docker ./initSQL.sh ``` -Inside the `docker` folder an example is provided. +#### Examples -##### Core System Config +We provide two examples of how Docker containers can be used to host Arrowhead Core systems in this repository. +The first one is located in the [`docker`](docker) folder and the second one in the [`docker-all`](docker-all) folder. +The former example shows how some prebuilt Docker images can be used to bring up networks, while the second describes how a Docker image can be constructed that contains all Arrowhead Core systems. +Please refer to those folders for more information. +In particular, each folder contains its own `README.md` file with more instructions. -Example Core System Configuration files are available in this folder. +
-> **Note:** Don't forget to set `domain.name` and `domain.port` properties! +#### Docker Guide -##### Docker Compose +> **Note:** Don't forget to set `domain.name` and `domain.port` properties! -Example Docker Compose file is located here. The interesting part is the volumes section. +Example Docker Compose file is located [here](docker/docker-compose.yml). The interesting part is the volumes section. Format is /path/on/your/local/machine:/path/inside/docker/container You may want to copy the config files elsewhere with the compose file too. If you copy them, please don't forget to change the volume mounting point, but DON'T change the volume mounting point inside the container, otherwise it will start up with default config. @@ -129,9 +180,9 @@ If you change your config you have to restart the appropriate container `docker restart ` -` + -##### Handy Docker Commands +#### Docker Cheat-Sheet | Command | Description | | ------- | ----------- | @@ -139,6 +190,7 @@ If you change your config you have to restart the appropriate container | `docker images` | List all images | | `docker-compose up -d` | Starts the Docker containers | | `docker-compose down` | Destroys the Docker containers | +| `docker restart ` | Restarts a container, making it re-read its configuration files | | `docker logs ` | Shows logs for the container | | `docker volume create --name=` | Creates a named volume | | `docker volume rm ` | Removes the specified named volume | @@ -150,7 +202,6 @@ If you change your config you have to restart the appropriate container Q: MySQL won't start. What did went wrong?
A: Probably you missed to copy the init SQL script next to the compose file, or you have a typo in its name. Solution: [https://github.com/arrowhead-f/core-java-spring/issues/105](https://github.com/arrowhead-f/core-java-spring/issues/105) -
### Debian Installers @@ -400,7 +451,7 @@ Arrowhead Framework's security is relying on SSL Certificate Trust Chains. The A 1) Master certificate: `arrowhead.eu` 2) Cloud certificate: `my_cloud.my_company.arrowhead.eu` 3) Client certificate: `my_client.my_cloud.my_company.arrowhead.eu` -The certificate naming convetion have strict rules: +The certificate naming convention have strict rules: * The different parts are delimited by dots, therefore parts are not allowed to contain any of them. * A cloud certificate name has to consist of four part and the last two part have to be 'arrowhead' and 'eu'. * A client certificate name has to consist of five part and the last two part have to be 'arrowhead' and 'eu'. @@ -423,6 +474,14 @@ Currently Arrowhead community have the possibility to create only "self signed" * [Create Arrowhead Client Self Signed Certificate](documentation/certificates/create_client_certificate.pdf) * [Create Trust Store](documentation/certificates/create_trust_store.pdf) +If you wish to generate all Certificates by a script, you can use the scripts in the [scripts/certificate_generation](scripts/certificate_generation) folder. + +> **Note:** Basic scripting knowledge is required! + +* lib_certs.sh - Certificate generation code +* mk_certs.sh - Usage example +* rm_certs.sh - Delete generated certs + ### System Operator Certificate The System Operator Certificate is a special client certificate with the naming convention of `sysop.my_cloud.my_company.arrowhead.eu`. @@ -431,6 +490,14 @@ SysOp certificate allows the client to use the management endpoints of the Arrow * [Import SysOp Certificate (macOS)](documentation/certificates/import_sysop_certificate_macos.pdf) * [Import SysOp Certificate (Linux)](documentation/certificates/import_sysop_certificate_linux.pdf) +### Include certificate in Docker container + +The following guide describes step by step, how to include your own certificates into a Docker container. + +* [How to include certificate in Docker](documentation/certificates/docker_certificate_guide.md) + + + ## Gatekeeper and Gateway Setup with ActiveMQ Relay @@ -3322,7 +3389,7 @@ __ServiceRequestForm__ is the input "string" ], "securityRequirements": [ - "NOT_SECURE", "CEERTIFICATE", "TOKEN" + "NOT_SECURE", "CERTIFICATE", "TOKEN" ], "metadataRequirements": { "additionalProp1": "string", @@ -6234,3 +6301,1176 @@ __ActiveSession__ is the output. | `responseControlQueue` | control queue of response messaging through the the Relay | | `sessionStartedAt` | Time stamp of session start | + + +# Certificate Authority + + + +## System Design Description Overview + +The purpose of the Certificate Authority supporting core system is issuing signed certificates to be used in the local cloud. + + + +## Provided services + +The Certificate Authority provides the following services: +* [Echo](#ca_endpoints_get_echo) +* [Certificate signing](#ca_endpoints_sign) + + + +## Use cases + +The main use case of the Certificate Authority is to issue signed certificates to new consumers coming via the Onboarding Controller. + + + +## Endpoints + + + +### Client endpoint description
+ +| Function | URL subpath | Method | Input | Output | +| -------- | ----------- | ------ | ----- | ------ | +| [Echo](#ca_endpoints_get_echo) | /echo | GET | - | OK | + +
+ +### Private endpoint description
+ +| Function | URL subpath | Method | Input | Output | +| -------- | ----------- | ------ | ----- | ------ | +| [Sign CSR with the Cloud Certificate](#ca_endpoints_sign) | /sign | POST | CertificateSigningRequest | [CertificateSigningResponse](#ca_certificate_signing_response) | + +
+ +### Echo +``` +GET /certificate-authority/echo +``` + +Returns a "Got it" message with the purpose of testing the core service availability. + + + +### Sign CSR with the Cloud Certificate + +``` +POST /certificate-authority/sign +``` + +Returns the whole certificate chain beginning with the newly generated leaf certificate and ending with the root certificate. + +Each certificate's issuer is the same as the subject of the following one. The issuer of the root certificate is the same as the subject. + +__Sign CSR with the Cloud Certificate__ inputs: + +`https://ca_ip:ca_port/certificate-authority/sign` + +| __Sign CSR with the Cloud Certificate__ query parameters | +| ------------------------------------------------------- | + +| Parameter | Description | Necessity | Format/Limitations | +| --------- | ----------- | --------- | ----------- | +| `encodedCSR` | PKCS #10 Certificate Signing Request | mandatory | Base64 encoded CSR | + + + +__Sign CSR with the Cloud Certificate__ output : + +```json +{ + "certificateChain": [ + "", + "", + "" + ] +} +``` + +| Field | Description | +| ----- | ----------- | +| `certificateChain` | The whole certificate chain in an array of PEM encoded strings | + + + +### Management endpoint description
+ +The Certificate Authority does not have management endpoints. + +
+ +# QOS MONITOR (QUALITY OF SERVICE MONITOR) + + + +## System Design Description Overview + +The purpose of QoS Monitor supporting core system is providing QoS (Quality of Service) measurements to the QoS Manager (which is part of the Orchestrator core system). + +![#1589F0](https://placehold.it/15/1589F0/000000?text=+) `AH Service Registry` +![#f03c15](https://placehold.it/15/f03c15/000000?text=+) `AH Authorization` +![#c5f015](https://placehold.it/15/c5f015/000000?text=+) `AH Orchestrator / QoS Manager` +![#ffcc44](https://placehold.it/15/a33c00/000000?text=+) `AH QoS Monitor` +![Alt text](/documentation/qos_monitor/sdd/overview.png) + + + +## System Design Overview +![Alt text](/documentation/qos_monitor/sysd/qos_monitor_sys_d.jpg) + + + +## Provided services + +The QoS Monitor provides the following services: +* [Echo](#qos_monitor_endpoints_get_echo) +* [Ping Measurement](#qos_monitor_endpoints_ping_measurement_by_system_id) + + + +## Consumed services + +The QoS Monitor consumes the following service: +* QueryAll private service from the ServiceRegistry core system + + + +## Use cases + +The QoS Monitor has the following use cases: +* [Ping Measurement](documentation/qos_monitor/use_cases/QoSMonitor_use_case_1.md) +![Alt text](/documentation/qos_monitor/use_cases/PingMeasurement.png) +* [Reset Counter](documentation/qos_monitor/use_cases/QoSMonitor_use_case_2.md) +![Alt text](/documentation/qos_monitor/use_cases/Reset_Counter.png) +* [Get Measurements](documentation/qos_monitor/use_cases/QoSMonitor_use_case_3.md) +![Alt text](/documentation/qos_monitor/use_cases/GetMeaurements.png) + + + +## Endpoints + + + +### Client endpoint description
+ +| Function | URL subpath | Method | Input | Output | +| -------- | ----------- | ------ | ----- | ------ | +| [Echo](#qos_monitor_endpoints_get_echo) | /echo | GET | - | OK | + +
+ +### Management endpoint description
+ +| Function | URL subpath | Method | Input | Output | +| -------- | ----------- | ------ | ----- | ------ | +| [Get ping measurements mgmt](#qos_monitor_endpoints_get_ping_measurements_list) | /mgmt/ping/measurements | GET | direction && item_per_page && page && sort_field | [PingMeasurement list response](#qos_monitor_ping_measurement_list_response) | +| [Get ping measurements by system id mgmt](#qos_monitor_mgmt_endpoints_get_ping_measurement_by_system_id) | /mgmt/ping/measurements/{id} | GET | id | [Ping Measurment response](#qos_monitor_ping_measurement_response) | + +
+ +### Private endpoint description
+ +| Function | URL subpath | Method | Input | Output | +| -------- | ----------- | ------ | ----- | ------ | +| [Get ping measurements by system id](#qos_monitor_endpoints_get_ping_measurement_by_system_id) | /ping/measurements/{id} | GET | id | [Ping Measurment response](#qos_monitor_ping_measurement_response) | + +
+ +### Echo +``` +GET /qos_monitor/echo +``` + +Returns a "Got it" message with the purpose of testing the core service availability. + +### Get ping measurements mgmt + +``` +GET /mgmt/ping/measurements +``` + +__Get subscriptions query parameters__ the input : + +`https://qos_monitor_ip:qos_monitor_port/qos_monitor/mgmt/ping/measurements?dirction=`ASC`&item_per_page=`100`&page=`0`&sort_field=`id + +| __Get ping measurements mgmt__ query parameters | +| ------------------------------------------------------- | + +| Parameter | Description | Necessity | Format/Limitations | +| --------- | ----------- | --------- | ----------- | +| `direction` | Direction of sorting. | optional | valid values: "ASC", "DESC" - default: "ASC"| +| `item_per_page` | Maximum number of items returned. | optional (mandatory, if page is defined)| integer | +| `page` | Zero based page index. | optional (mandatory, if item_per_page is defined)| integer | +| `sort_field` | The field to sort the results by. | optional | valid values: "id", "updatedAt", "createdAt" - default: "id" | + + + +__PingMeasurement list response__ the output : + +```json +{ + "data": [ + { + "id": 1, + "measurement": { + "id": 1, + "system": { + "id": 5, + "systemName": "testsystem", + "address": "testsystem.ai", + "port": 12345, + "createdAt": "2020-02-04 09:38:56", + "updatedAt": "2020-02-04 09:38:56" + }, + "measurementType": "PING", + "lastMeasurementAt": "2020-02-14T10:48:10+01:00", + "createdAt": "2020-02-04T10:42:04+01:00", + "updatedAt": "2020-02-14T10:48:47+01:00" + }, + "available": true, + "lastAccessAt": "2020-02-14T10:48:10+01:00", + "minResponseTime": 15, + "maxResponseTime": 26, + "meanResponseTimeWithTimeout": 18, + "meanResponseTimeWithoutTimeout": 18, + "jitterWithTimeout": 3, + "jitterWithoutTimeout": 3, + "lostPerMeasurementPercent": 0, + "sent": 12075, + "received": 12070, + "countStartedAt": "2020-02-07T00:00:00+01:00", + "sentAll": 63175, + "receivedAll": 56721, + "createdAt": "2020-02-14T10:48:47+01:00", + "updatedAt": "2020-02-14T10:48:47+01:00" + } + ], + "count": 1 +} +``` + +| Field | Description | +| ----- | ----------- | +| `count` | Number of record found | +| `data` | Array of data | +| `id` | ID of the ping measurement | +| `measurement.id` | ID of the measurement | +| `measurement.system.id` | ID of the measured system | +| `measurement.system.systemName` | Name of the measured system | +| `measurement.system.address` | Address of the measured system | +| `measurement.system.port` | Port of the measured system | +| `measurement.system.createdAt` | Date of creation of the measured system | +| `measurement.system.updatedAt` | Date of update of the measured system | +| `measurement.measurementType` | Type of the measurement | +| `measurement.lastMeasurementAt` | Time of the last measurement | +| `measurement.createdAt` | Date of creation of the measurement | +| `measurement.updatedAt` | Date of update of the measurement | +| `available` | Boolean value of the systems calculated availability| +| `lastAccessAt` | TimeStamp value of the systems last known availability| +| `minResponseTime` | Integer value of milliseconds of the fastest returned ping| +| `maxResponseTime` | Integer value of milliseconds of the slowest returned ping| +| `meanResponseTimeWithTimeout` | Integer value of milliseconds of the calculated average of pings including timeouts| +| `meanResponseTimeWithoutTimeout` | Integer value of milliseconds of the calculated average of pings not including timeouts| +| `jitterWithTimeout` | Integer value of milliseconds of the calculated standard deviation of pings including timeouts| +| `jitterWithoutTimeout` | Integer value of milliseconds of the calculated standard deviation of pings not including timeouts| +| `lostPerMeasurementPercent` | Integer value of calculated lost ping percentage| +| `sent` | Integer value of sent pings in measurement| +| `received` | Integer value of received pings in measurement| +| `countStartedAt` | TimeSatmp value of the last reset of sent and received fields| +| `sentAll` | Integer value of sent pings since ping measurement created| +| `receivedAll` | Integer value of received pings since ping measurement created| +| `createdAt` | Date of creation of the ping measurement | +| `updatedAt` | Date of update of the ping measurement | + + + +### Get ping measurements by system id mgmt + +``` +GET /mgmt/ping/measurements/{id} +``` + +__Get ping measurements by system id mgmt path parameter__ the input : + +`https://qos_monitor_ip:qos_monitor_port/qos_monitor/mgmt/ping/measurements/`1 + +| __Get ping measurement by system id__ path parameter | +| ------------------------------------------------------- | + +| Parameter | Description | Necessity | Format/Limitations | +| --------- | ----------- | --------- | ----------- | +| `id` | Id of measured system | mandatory | integer | + + + +__Ping Measurment response by system id__ the output : + +```json +{ + "id": 1, + "measurement": { + "id": 1, + "system": { + "id": 5, + "systemName": "testsystem", + "address": "testsystem.ai", + "port": 12345, + "createdAt": "2020-02-04 09:38:56", + "updatedAt": "2020-02-04 09:38:56" + }, + "measurementType": "PING", + "lastMeasurementAt": "2020-02-14T10:48:10+01:00", + "createdAt": "2020-02-04T10:42:04+01:00", + "updatedAt": "2020-02-14T10:48:47+01:00" + }, + "available": true, + "lastAccessAt": "2020-02-14T10:48:10+01:00", + "minResponseTime": 15, + "maxResponseTime": 26, + "meanResponseTimeWithTimeout": 18, + "meanResponseTimeWithoutTimeout": 18, + "jitterWithTimeout": 3, + "jitterWithoutTimeout": 3, + "lostPerMeasurementPercent": 0, + "sent": 12075, + "received": 12070, + "countStartedAt": "2020-02-07T00:00:00+01:00", + "sentAll": 63175, + "receivedAll": 56721, + "createdAt": "2020-02-14T10:48:47+01:00", + "updatedAt": "2020-02-14T10:48:47+01:00" +} +``` + +| Field | Description | +| ----- | ----------- | +| `id` | ID of the ping measurement | +| `measurement.id` | ID of the measurement | +| `measurement.system.id` | ID of the measured system | +| `measurement.system.systemName` | Name of the measured system | +| `measurement.system.address` | Address of the measured system | +| `measurement.system.port` | Port of the measured system | +| `measurement.system.createdAt` | Date of creation of the measured system | +| `measurement.system.updatedAt` | Date of update of the measured system | +| `measurement.measurementType` | Type of the measurement | +| `measurement.lastMeasurementAt` | Time of the last measurement | +| `measurement.createdAt` | Date of creation of the measurement | +| `measurement.updatedAt` | Date of update of the measurement | +| `available` | Boolean value of the systems calculated availability| +| `lastAccessAt` | TimeStamp value of the systems last known availability| +| `minResponseTime` | Integer value of milliseconds of the fastest returned ping| +| `maxResponseTime` | Integer value of milliseconds of the slowest returned ping| +| `meanResponseTimeWithTimeout` | Integer value of milliseconds of the calculated average of pings including timeouts| +| `meanResponseTimeWithoutTimeout` | Integer value of milliseconds of the calculated average of pings not including timeouts| +| `jitterWithTimeout` | Integer value of milliseconds of the calculated standard deviation of pings including timeouts| +| `jitterWithoutTimeout` | Integer value of milliseconds of the calculated standard deviation of pings not including timeouts| +| `lostPerMeasurementPercent` | Integer value of calculated lost ping percentage| +| `sent` | Integer value of sent pings in measurement| +| `received` | Integer value of received pings in measurement| +| `countStartedAt` | TimeSatmp value of the last reset of sent and received fields| +| `sentAll` | Integer value of sent pings since ping measurement created| +| `receivedAll` | Integer value of received pings since ping measurement created| +| `createdAt` | Date of creation of the ping measurement | +| `updatedAt` | Date of update of the ping measurement | + + + +### Get ping measurements by system id + +For private endpoints no detailed description available. + + +# Onboarding Controller +

+ +The purpose of this System is to be the entry board for the onboarding procedure. The onboarding controller sits at the edge of the Arrowhead local cloud. +It is not only reachable from within the cloud by authorized systems, but also from the public through its "accept all" interfaces. +Any client may authenticate itself through an Arrowhead certificate, through an authorized manufacturer certificate, or simply through a shared secret. + +![onboarding_controller](./documentation/onboarding/onboarding_controller.png) + +## Services and Use Cases +
+ +The only use case is the onboarding procedure. + +The onboarding procedure is needed when a new device produced by any vendor (e.g. Siemens, Infineon, Bosch, etc.), containing a security controller (e.g. TPM), +wants to interact with the Arrowhead local cloud. To assure that the cloud is not compromised upon the arrival of this new device, it is important to establish +a chain of trust from the new hardware device, to its hosted application systems and their services. Thus, the onboarding procedure makes possible that +the device, systems and services are authenticated and authorized to connect to the Arrowhead local cloud. + +The use cases in which the external actor interacts with the Arrowhead local cloud during onboarding include: +* Initialize Device Onboarding (via the Onboarding Controller system) +* Register a Device in the DeviceRegistry (via the DeviceRegistry system) +* Register a System in the SystemRegistry (via the SystemRegistry system) +* Register a Service in the ServiceRegistry (via the ServiceRegistry system) +* Start normal operation (e.g., service lookup, service consumption, etc.) + +The onboarding controller can either relay a ![PKCS #10 Certificate Signing Request](https://tools.ietf.org/html/rfc2986) or generate one on behalf of the client. + + +## Security + + +This System can be secured via the HTTPS protocol. If it is started in secure mode, it verifies whether the Application System +- possesses a proper X.509 identity certificate and whether that certificate is Arrowhead compliant +- possesses a proper X.509 identity certificate and whether that certificate is trusted by the CA +- provides a shared secret through ![HTTP Basic Authentication](https://tools.ietf.org/html/rfc7617) + +## Endpoints + + +The Onboarding Controller offers two types of authentication (certificate or HTTP Basic) and two types operation (provide CSR or generate CSR), thus having four different endpoint. +No management or private endpoint exists. + +Swagger API documentation is available on: `https://:`
+The base URL for the requests: `https://:/onboarding` + +The general scheme of the URLs is `https://:/onboarding//` + +### Client endpoint description
+
+ +| Function | URL subpath | Method | Input | Output | +| -------- | ----------- | ------ | ----- | ------ | +| [Echo](#onboardingcontroller_endpoints_get_echo) | /echo | GET | - | OK | +| [Onboard with Name](#onboardingcontroller_endpoints_name) | /certificate/name | POST | [OnboardingWithNameRequest](#datastructures_onboarding_name_request) | [OnboardingWithNameResponse](#datastructures_onboarding_name_response) | +| [Onboard with Name](#onboardingcontroller_endpoints_name) | /sharedsecret/name | POST | [OnboardingWithNameRequest](#datastructures_onboarding_name_request) | [OnboardingWithNameResponse](#datastructures_onboarding_name_response) | +| [Onboard with CSR](#onboardingcontroller_endpoints_csr) | /certificate/csr | POST | [OnboardingWithCsrRequest](#datastructures_onboarding_csr_request) | [OnboardingWithCsrResponse](#datastructures_onboarding_csr_response) | +| [Onboard with CSR](#onboardingcontroller_endpoints_csr) | /sharedsecret/csr | POST | [OnboardingWithCsrRequest](#datastructures_onboarding_csr_request) | [OnboardingWithCsrResponse](#datastructures_onboarding_csr_response) | + + +### Onboard with Name + + +``` +POST /certificate/name +POST /sharedsecret/name +``` + +Creates a CSR on behalf of the client and eventually returns an onboarding certificate which may be used in the next step of the onboarding controller. + +#### Request + + +```json +{ + "creationRequestDTO": { + "commonName": "string", + "keyPairDTO": { + "keyAlgorithm": "string", + "keyFormat": "string", + "privateKey": "string", + "publicKey": "string" + } + } +} +``` + +| Field | Description | +| ----- | ----------- | +| `commonName` | The common name field for the new certificate | +| `keyAlgorithm` | The key algorithm of the provided keys | +| `keyFormat` | The key format of the provided keys | +| `privateKey` | Base64 encoded private key | +| `publicKey` | Base64 encoded public key | + +#### Response + + +```json +{ + "rootCertificate": "string", + "intermediateCertificate": "string", + "onboardingCertificate": { + "certificate": "string", + "certificateFormat": "string", + "certificateType": "AH_ONBOARDING", + "keyPairDTO": { + "keyAlgorithm": "string", + "keyFormat": "string", + "privateKey": "string", + "publicKey": "string" + } + }, + "deviceRegistry": { + "service": "DEVICE_REGISTRY_ONBOARDING_WITH_NAME_SERVICE", + "uri": "string" + }, + "systemRegistry": { + "service": "SYSTEM_REGISTRY_ONBOARDING_WITH_NAME_SERVICE", + "uri": "string" + }, + "serviceRegistry": { + "service": "SERVICE_REGISTRY_REGISTER_SERVICE", + "uri": "string" + }, + "orchestrationService": { + "service": "ORCHESTRATION_SERVICE", + "uri": "string" + } +} +``` + +| Field | Description | +| ----- | ----------- | +| `rootCertificate` | The Arrowhead master certificate | +| `intermediateCertificate` | The Arrowhead local cloud certificate | +| `onboardingCertificate` | The onboarding certificate for the next step | +| `certificateFormat` | The certificate format (usually X.509) | +| `certificateType` | The certificate type. Always AH_ONBOARDING for this operation | +| `keyAlgorithm` | The key algorithm of the provided keys | +| `keyFormat` | The key format of the provided keys | +| `privateKey` | Base64 encoded private key | +| `publicKey` | Base64 encoded public key | +| `service` | The service which is reachable under `uri` | +| `uri` | The uri under which the depicted `service` is reachable | + + +### Onboard with CSR + + +``` +POST /certificate/csr +POST /sharedsecret/csr +``` + +Creates a CSR on behalf of the client and eventually returns an onboarding certificate which may be used in the next step of the onboarding controller. + +#### Request + + +```json +{ + "certificateSigningRequest": "string" +} +``` + +| Field | Description | +| ----- | ----------- | +| `certificateSigningRequest` | Base64 encoded certificate signing request | + +#### Response + + +```json +{ + "rootCertificate": "string", + "intermediateCertificate": "string", + "onboardingCertificate": { + "certificate": "string", + "certificateFormat": "string", + "certificateType": "AH_ONBOARDING", + "keyPairDTO": { + "keyAlgorithm": "string", + "keyFormat": "string", + "privateKey": "string", + "publicKey": "string" + } + }, + "deviceRegistry": { + "service": "DEVICE_REGISTRY_ONBOARDING_WITH_CSR_SERVICE", + "uri": "string" + }, + "systemRegistry": { + "service": "SYSTEM_REGISTRY_ONBOARDING_WITH_CSR_SERVICE", + "uri": "string" + }, + "serviceRegistry": { + "service": "SERVICE_REGISTRY_REGISTER_SERVICE", + "uri": "string" + }, + "orchestrationService": { + "service": "ORCHESTRATION_SERVICE", + "uri": "string" + } +} +``` + +| Field | Description | +| ----- | ----------- | +| `rootCertificate` | The Arrowhead master certificate | +| `intermediateCertificate` | The Arrowhead local cloud certificate | +| `onboardingCertificate` | The onboarding certificate for the next step | +| `certificateFormat` | The certificate format (usually X.509) | +| `certificateType` | The certificate type. Always AH_ONBOARDING for this operation | +| `keyAlgorithm` | The key algorithm of the provided keys | +| `keyFormat` | The key format of the provided keys | +| `privateKey` | Base64 encoded private key. Always empty for this operation | +| `publicKey` | Base64 encoded public key | +| `service` | The service which is reachable under `uri` | +| `uri` | The uri under which the depicted `service` is reachable | + + +# Device Registry +
+ +## System Design Description Overview +

+ +This System provides the database, which stores information related to the Devices within the Local Cloud. + +The purpose of this System is therefore to allow: +- Devices to register themselves, making this announcement available to other Application Systems on the network. +- They are also allowed to remove or update their entries when it is necessary. +- Generate a client certificate which can be used by the Device to register its Systems + +## Services and Use Cases +
+ +This System provides two Core Service: the __device registration__ and __de-registration__. +Further it provides two Onboarding Services: the __onboarding with name__ and __onboarding with CSR__. + +The __register__ method is used to register a device. The device will contain various metadata as well as a physical endpoint. +The various parameters are representing the endpoint information that should be registered. + +The __unregister__ method is used to unregister device instances that were previously registered in the Registry. +The instance parameter is representing the endpoint information that should be removed. + +The __onboarding__ methods are used to register a device and to retrieve a device certificate which must be used on the next step of the onboarding procedure. + +## Security + + +This System can be secured via the HTTPS protocol. If it is started in secure mode, it verifies whether the Application System possesses a proper X.509 identity certificate and whether that certificate is Arrowhead compliant in its making. This certificate structure and creation guidelines ensure: +- Application System is properly bootstrapped into the Local Cloud +- The Application System indeed belongs to this Local Cloud +- The Application System then automatically has the right to register its Systems in the Registry. + +If these criteria are met, the Application System’s registration or removal message is processed. An Application System can only delete or alter entries that contain the Device as the System Provider in the entry. + + +## Endpoints + + +The System Registry offers four types of endpoints. Onboarding, Client, Management and Private. + +Swagger API documentation is available on: `https://:`
+The base URL for the requests: `http://:/deviceregistry` + +### Onboarding endpoint description
+
+ +| Function | URL subpath | Method | Input | Output | +| -------- | ----------- | ------ | ----- | ------ | +| [Onboard with Name](#deviceregistry_endpoints_onboarding_name) | /onboarding/name | POST | [DeviceOnboardingWithNameRequest](#datastructures_deviceregistry_onboarding_with_name_request) | [DeviceOnboardingWithNameResponse](#datastructures_deviceregistry_onboarding_with_name_response) | +| [Onboard with CSR](#deviceregistry_endpoints_onboarding_csr) | /onboarding/csr | POST | [DeviceOnboardingWithCsrRequest](#datastructures_deviceregistry_onboarding_with_csr_request) | [DeviceOnboardingWithCsrResponse](#datastructures_deviceregistry_onboarding_with_csr_response) | + + +### Client endpoint description
+
+ +| Function | URL subpath | Method | Input | Output | +| -------- | ----------- | ------ | ----- | ------ | +| [Echo](#deviceregistry_endpoints_get_echo) | /echo | GET | - | OK | +| [Query](#deviceregistry_endpoints_post_query) | /query | POST | [DeviceQueryForm](#datastructures_systemqueryform) | [DeviceQueryList](#datastructures_devicequerylist) | +| [Register](#deviceregistry_endpoints_post_register) | /register | POST | [DeviceRegistryEntry](#datastructures_deviceregistryentry) | [DeviceRegistryEntry](#datastructures_deviceregistryentry) | +| [Unregister](#deviceregistry_delete_unregister) | /unregister | DELETE | Device Name and Mac Address in query parameters| OK | + +### Detailed description
+ +A detailed description of management and private endpoints is available in the release notes. + +### Onboard with Name +
+ +``` +POST /onboarding/name +``` + +Creates a CSR on behalf of the client, registers the device and eventually returns a device certificate which may be used in the next step of the onboarding controller. + +#### Request + + +```json +{ + "certificateCreationRequest": { + "commonName": "string", + "keyPairDTO": { + "keyAlgorithm": "string", + "keyFormat": "string", + "privateKey": "string", + "publicKey": "string" + } + }, + "device": { + "address": "string", + "authenticationInfo": "string", + "deviceName": "string", + "macAddress": "string" + }, + "endOfValidity": "string", + "metadata": { + "additionalProp1": "string", + "additionalProp2": "string", + "additionalProp3": "string" + }, + "version": 0 +} +``` + +| Field | Description | +| ----- | ----------- | +| `commonName` | The common name field for the new certificate | +| `keyAlgorithm` | The key algorithm of the provided keys | +| `keyFormat` | The key format of the provided keys | +| `privateKey` | Base64 encoded private key | +| `publicKey` | Base64 encoded public key | +| `address` | The optional IP address of the device | +| `authenticationInfo` | Base64 encoded public key of the certificate this device | +| `deviceName` | The device name | +| `macAddress` | The MAC address of the device | +| `endOfValidity` | The validity of this entry | +| `metadata` | Various meta information as map | +| `version` | The version of this entry | + +#### Response + + +```json +{ + "certificateResponse": { + "certificate": "string", + "certificateFormat": "string", + "certificateType": "AH_DEVICE", + "keyPairDTO": { + "keyAlgorithm": "string", + "keyFormat": "string", + "privateKey": "string", + "publicKey": "string" + } + }, + "createdAt": "string", + "device": { + "address": "string", + "authenticationInfo": "string", + "createdAt": "string", + "deviceName": "string", + "id": 0, + "macAddress": "string", + "updatedAt": "string" + }, + "endOfValidity": "string", + "id": 0, + "metadata": { + "additionalProp1": "string", + "additionalProp2": "string", + "additionalProp3": "string" + }, + "updatedAt": "string", + "version": 0 +} +``` + +| Field | Description | +| ----- | ----------- | +| `certificate` | The Base64 device certificate for the next step | +| `certificateFormat` | The certificate format (usually X.509) | +| `certificateType` | The certificate type. Always AH_DEVICE for this operation | +| `keyAlgorithm` | The key algorithm of the provided keys | +| `keyFormat` | The key format of the provided keys | +| `privateKey` | Base64 encoded private key | +| `publicKey` | Base64 encoded public key | + +Additionally all fields from [DeviceRegistryEntry](#datastructures_deviceregistryentry) are returned. + +### Onboard with CSR + + +``` +POST /onboarding/csr +``` + +Signs the CSR, registers the device and eventually returns a device certificate which may be used in the next step of the onboarding controller. + +#### Request + + +```json +{ + "certificateSigningRequest": "string", + "device": { + "address": "string", + "authenticationInfo": "string", + "deviceName": "string", + "macAddress": "string" + }, + "endOfValidity": "string", + "metadata": { + "additionalProp1": "string", + "additionalProp2": "string", + "additionalProp3": "string" + }, + "version": 0 +} +``` + +| Field | Description | +| ----- | ----------- | +| `certificateSigningRequest` | Base64 encoded certificate signing request | +| `address` | The optional IP address of the device | +| `authenticationInfo` | Base64 encoded public key of the certificate this device | +| `deviceName` | The device name | +| `macAddress` | The MAC address of the device | +| `endOfValidity` | The validity of this entry | +| `metadata` | Various meta information as map | +| `version` | The version of this entry | + +#### Response + + +```json +{ + "certificateResponse": { + "certificate": "string", + "certificateFormat": "string", + "certificateType": "AH_DEVICE", + "keyPairDTO": { + "keyAlgorithm": "string", + "keyFormat": "string", + "privateKey": "string", + "publicKey": "string" + } + }, + "createdAt": "string", + "device": { + "address": "string", + "authenticationInfo": "string", + "createdAt": "string", + "deviceName": "string", + "id": 0, + "macAddress": "string", + "updatedAt": "string" + }, + "endOfValidity": "string", + "id": 0, + "metadata": { + "additionalProp1": "string", + "additionalProp2": "string", + "additionalProp3": "string" + }, + "updatedAt": "string", + "version": 0 +} +``` + +| Field | Description | +| ----- | ----------- | +| `certificate` | The Base64 device certificate for the next step | +| `certificateFormat` | The certificate format (usually X.509) | +| `certificateType` | The certificate type. Always AH_DEVICE for this operation | +| `keyAlgorithm` | The key algorithm of the provided keys | +| `keyFormat` | The key format of the provided keys | +| `privateKey` | Base64 encoded private key. Always empty for this operation | +| `publicKey` | Base64 encoded public key | + +Additionally all fields from [DeviceRegistryEntry](#datastructures_deviceregistryentry) are returned. + + +# System Registry + + + +## System Design Description Overview + + +This System provides the database, which stores information related to the System of the currently actively offered Services within the Local Cloud. + +The purpose of this System is therefore to allow: +- Devices to register which Systems they offer at the moment, making this announcement available to other Application Systems on the network. +- They are also allowed to remove or update their entries when it is necessary. +- Generate a client certificate which can be used by the System to offer Services + + +## Services and Use Cases + + +This System provides two Core Service the __system registration__ and __de-registration__ + +The __register__ method is used to register a system. The system will contain various metadata as well as a physical endpoint. +The various parameters are representing the endpoint information that should be registered. + +The __unregister__ method is used to unregister system instances that were previously registered in the Registry. +The instance parameter is representing the endpoint information that should be removed. + + +## Security + + +This System can be secured via the HTTPS protocol. If it is started in secure mode, it verifies whether the Application System possesses a proper X.509 identity certificate and whether that certificate is Arrowhead compliant in its making. This certificate structure and creation guidelines ensure: +- Application System is properly bootstrapped into the Local Cloud +- The Application System indeed belongs to this Local Cloud +- The Application System then automatically has the right to register its Services in the Registry. + +If these criteria are met, the Application System’s registration or removal message is processed. An Application System can only delete or alter entries that contain the Device as the System Provider in the entry. + + +## Endpoints + + +The System Registry offers three types of endpoints. Client, Management and Private. + +Swagger API documentation is available on: `https://:`
+The base URL for the requests: `http://:/systemregistry` + +### Onboarding endpoint description
+
+ +| Function | URL subpath | Method | Input | Output | +| -------- | ----------- | ------ | ----- | ------ | +| [Onboard with Name](#systemregistry_endpoints_onboarding_name) | /onboarding/name | POST | [SystemOnboardingWithNameRequest](#datastructures_systemregistry_onboarding_with_name_request) | [SystemOnboardingWithNameResponse](#datastructures_systemregistry_onboarding_with_name_response) | +| [Onboard with CSR](#systemregistry_endpoints_onboarding_csr) | /onboarding/csr | POST | [SystemOnboardingWithCsrRequest](#datastructures_systemregistry_onboarding_with_csr_request) | [SystemOnboardingWithCsrResponse](#datastructures_systemregistry_onboarding_with_csr_response) | + + +### Client endpoint description
+
+ +| Function | URL subpath | Method | Input | Output | +| -------- | ----------- | ------ | ----- | ------ | +| [Echo](#systemregistry_endpoints_get_echo) | /echo | GET | - | OK | +| [Query](#systemregistry_endpoints_post_query) | /query | POST | [SystemQueryForm](#datastructures_systemqueryform) | [SystemQueryList](#datastructures_systemquerylist) | +| [Register](#systemregistry_endpoints_post_register) | /register | POST | [SystenRegistryEntry](#datastructures_systemregistryentry) | [SystenRegistryEntry](#datastructures_systemregistryentry) | +| [Unregister](#systemregistry_delete_unregister) | /unregister | DELETE | System Name, Address and Port in query parameters| OK | + +### Detailed description
+ +A detailed description of public, management and private endpoints is available in the release notes. + +### Onboard with Name +
+ +``` +POST /onboarding/name +``` + +Creates a CSR on behalf of the client, registers the system and eventually returns a system certificate which is valid in the Arrowhead local cloud. + +#### Request + + +```json +{ + "certificateCreationRequest": { + "commonName": "string", + "keyPairDTO": { + "keyAlgorithm": "string", + "keyFormat": "string", + "privateKey": "string", + "publicKey": "string" + } + }, + "provider": { + "address": "string", + "authenticationInfo": "string", + "deviceName": "string", + "macAddress": "string" + }, + "system": { + "address": "string", + "authenticationInfo": "string", + "port": 0, + "systemName": "string" + }, + "endOfValidity": "string", + "metadata": { + "additionalProp1": "string", + "additionalProp2": "string", + "additionalProp3": "string" + }, + "version": 0 +} +``` + +| Field | Description | +| ----- | ----------- | +| `commonName` | The common name field for the new certificate | +| `keyAlgorithm` | The key algorithm of the provided keys | +| `keyFormat` | The key format of the provided keys | +| `privateKey` | Base64 encoded private key | +| `publicKey` | Base64 encoded public key | +| `address` | The IP address of the device/system | +| `authenticationInfo` | Base64 encoded public key of the certificate this device/system | +| `deviceName` | The device name | +| `macAddress` | The MAC address of the device | +| `systemName` | The system name | +| `port` | The port under which this system's services are available | +| `endOfValidity` | The validity of this entry | +| `metadata` | Various meta information as map | +| `version` | The version of this entry | + +#### Response + + +```json +{ + "certificateResponse": { + "certificate": "string", + "certificateFormat": "string", + "certificateType": "AH_SYSTEM", + "keyPairDTO": { + "keyAlgorithm": "string", + "keyFormat": "string", + "privateKey": "string", + "publicKey": "string" + } + }, + "createdAt": "string", + "provider": { + "address": "string", + "authenticationInfo": "string", + "createdAt": "string", + "deviceName": "string", + "id": 0, + "macAddress": "string", + "updatedAt": "string" + }, + "system": { + "address": "string", + "authenticationInfo": "string", + "createdAt": "string", + "id": 0, + "port": 0, + "systemName": "string", + "updatedAt": "string" + }, + "endOfValidity": "string", + "id": 0, + "metadata": { + "additionalProp1": "string", + "additionalProp2": "string", + "additionalProp3": "string" + }, + "updatedAt": "string", + "version": 0 +} +``` + +| Field | Description | +| ----- | ----------- | +| `certificate` | The Base64 device certificate for the next step | +| `certificateFormat` | The certificate format (usually X.509) | +| `certificateType` | The certificate type. Always AH_SYSTEM for this operation | +| `keyAlgorithm` | The key algorithm of the provided keys | +| `keyFormat` | The key format of the provided keys | +| `privateKey` | Base64 encoded private key | +| `publicKey` | Base64 encoded public key | + +Additionally all fields from [SystemRegistryEntry](#datastructures_systemregistryentry) are returned. + +### Onboard with CSR + + +``` +POST /onboarding/csr +``` + +Signs the CSR, registers the device and eventually returns a device certificate which may be used in the next step of the onboarding controller. + +#### Request + + +```json +{ + "certificateSigningRequest": "string", + "provider": { + "address": "string", + "authenticationInfo": "string", + "deviceName": "string", + "macAddress": "string" + }, + "system": { + "address": "string", + "authenticationInfo": "string", + "port": 0, + "systemName": "string" + }, + "endOfValidity": "string", + "metadata": { + "additionalProp1": "string", + "additionalProp2": "string", + "additionalProp3": "string" + }, + "version": 0 +} +``` + +| Field | Description | +| ----- | ----------- | +| `certificateSigningRequest` | Base64 encoded certificate signing request | +| `address` | The IP address of the device/system | +| `authenticationInfo` | Base64 encoded public key of the certificate this device/system | +| `deviceName` | The device name | +| `macAddress` | The MAC address of the device | +| `systemName` | The system name | +| `port` | The port under which this system's services are available | +| `endOfValidity` | The validity of this entry | +| `metadata` | Various meta information as map | +| `version` | The version of this entry | + +#### Response + + +```json +{ + "certificateResponse": { + "certificate": "string", + "certificateFormat": "string", + "certificateType": "AH_SYSTEM", + "keyPairDTO": { + "keyAlgorithm": "string", + "keyFormat": "string", + "privateKey": "string", + "publicKey": "string" + } + }, + "createdAt": "string", + "provider": { + "address": "string", + "authenticationInfo": "string", + "createdAt": "string", + "deviceName": "string", + "id": 0, + "macAddress": "string", + "updatedAt": "string" + }, + "system": { + "address": "string", + "authenticationInfo": "string", + "createdAt": "string", + "id": 0, + "port": 0, + "systemName": "string", + "updatedAt": "string" + }, + "endOfValidity": "string", + "id": 0, + "metadata": { + "additionalProp1": "string", + "additionalProp2": "string", + "additionalProp3": "string" + }, + "updatedAt": "string", + "version": 0 +} +``` + +| Field | Description | +| ----- | ----------- | +| `certificate` | The Base64 device certificate for the next step | +| `certificateFormat` | The certificate format (usually X.509) | +| `certificateType` | The certificate type. Always AH_DEVICE for this operation | +| `keyAlgorithm` | The key algorithm of the provided keys | +| `keyFormat` | The key format of the provided keys | +| `privateKey` | Base64 encoded private key. Always empty for this operation | +| `publicKey` | Base64 encoded public key | + +Additionally all fields from [SystemRegistryEntry](#datastructures_systemregistryentry) are returned. + diff --git a/authorization/.classpath b/authorization/.classpath index 01997bb0d..e210343c4 100644 --- a/authorization/.classpath +++ b/authorization/.classpath @@ -45,5 +45,19 @@ + + + + + + + + + + + + + + diff --git a/authorization/src/main/java/eu/arrowhead/core/authorization/AuthorizationController.java b/authorization/src/main/java/eu/arrowhead/core/authorization/AuthorizationController.java index f38c0adec..9d4b49e5e 100644 --- a/authorization/src/main/java/eu/arrowhead/core/authorization/AuthorizationController.java +++ b/authorization/src/main/java/eu/arrowhead/core/authorization/AuthorizationController.java @@ -597,10 +597,6 @@ public void removeAuthorizationInterCloudById(@PathVariable(value = PATH_VARIABL logger.debug("New token generation request received"); checkTokenGenerationRequest(request); - if (request.getDuration() != null && request.getDuration().intValue() <= 0) { - request.setDuration(null); - } - final TokenGenerationResponseDTO response = tokenGenerationService.generateTokensResponse(request); logger.debug("{} token(s) are generated for {}", calculateNumberOfTokens(response.getTokenData()), request.getConsumer().getSystemName()); @@ -669,6 +665,10 @@ private void checkTokenGenerationProviderDTO(final TokenGenerationProviderDTO pr throw new BadPayloadException("Specified interface name is not valid: " + intf, HttpStatus.SC_BAD_REQUEST, origin); } } + + if (provider.getTokenDuration() <= 0) { + provider.setTokenDuration(-1); + } } //------------------------------------------------------------------------------------------------- diff --git a/authorization/src/main/java/eu/arrowhead/core/authorization/database/service/AuthorizationDBService.java b/authorization/src/main/java/eu/arrowhead/core/authorization/database/service/AuthorizationDBService.java index 81ea655b3..85ccbcd41 100644 --- a/authorization/src/main/java/eu/arrowhead/core/authorization/database/service/AuthorizationDBService.java +++ b/authorization/src/main/java/eu/arrowhead/core/authorization/database/service/AuthorizationDBService.java @@ -629,7 +629,7 @@ private List createBulkAuthorizationIntraCloudWithOnePr checkConstraintsOfAuthorizationIntraCloudTable(consumer, provider, service); toBeSaved.add(new AuthorizationIntraCloud(consumer, provider, service)); } catch (final InvalidParameterException ex) { - //not throwing towards as in this bulk operation case should be only a warning + // not throwing towards as in this bulk operation case should be only a warning logger.debug(ex.getMessage()); } } else { @@ -784,7 +784,7 @@ private List createBulkAuthorizationInterCloudWithOneSe checkConstraintsOfAuthorizationInterCloudTable(cloud, provider, service); toBeSaved.add(new AuthorizationInterCloud(cloud, provider, service)); } catch (final InvalidParameterException ex) { - //not throwing towards as in this bulk operation case should be only a warning + // not throwing towards as in this bulk operation case should be only a warning logger.debug(ex.getMessage()); } } else { diff --git a/authorization/src/main/java/eu/arrowhead/core/authorization/security/AuthAccessControlFilter.java b/authorization/src/main/java/eu/arrowhead/core/authorization/security/AuthAccessControlFilter.java index ecb04cbbc..2714c3ab5 100644 --- a/authorization/src/main/java/eu/arrowhead/core/authorization/security/AuthAccessControlFilter.java +++ b/authorization/src/main/java/eu/arrowhead/core/authorization/security/AuthAccessControlFilter.java @@ -16,10 +16,11 @@ public class AuthAccessControlFilter extends CoreSystemAccessControlFilter { //================================================================================================= // members - + private static final String AUTHORIZATION_INTRA_CLOUD_MGMT_URI = CoreCommonConstants.MGMT_URI + "/intracloud"; private static final CoreSystem[] allowedCoreSystemsForChecks = { CoreSystem.ORCHESTRATOR, CoreSystem.GATEKEEPER }; private static final CoreSystem[] allowedCoreSystemsForSubscriptionChecks = { CoreSystem.EVENT_HANDLER }; - + private static final CoreSystem[] allowedCoreSystemsForRuleMgmt = { CoreSystem.ONBOARDING_CONTROLLER }; + //================================================================================================= // assistant methods @@ -31,6 +32,11 @@ protected void checkClientAuthorized(final String clientCN, final String method, final String cloudCN = getServerCloudCN(); if (requestTarget.endsWith(CommonConstants.OP_AUTH_KEY_URI) || requestTarget.endsWith(CommonConstants.ECHO_URI)) { // Everybody in the local cloud can get the Authorization public key (because it is PUBLIC) or test the server => no further check is necessary + } else if (requestTarget.endsWith(AUTHORIZATION_INTRA_CLOUD_MGMT_URI)) { + // onboarding controller may use this method + if(!checkIfClientIsAnAllowedCoreSystemNoException(clientCN, cloudCN, allowedCoreSystemsForRuleMgmt, requestTarget)) { + checkIfLocalSystemOperator(clientCN, cloudCN, requestTarget); + } } else if (requestTarget.contains(CoreCommonConstants.MGMT_URI)) { // Only the local System Operator can use these methods checkIfLocalSystemOperator(clientCN, cloudCN, requestTarget); diff --git a/authorization/src/main/java/eu/arrowhead/core/authorization/security/AuthSecurityConfig.java b/authorization/src/main/java/eu/arrowhead/core/authorization/security/AuthSecurityConfig.java index 9cfe85970..a82654572 100644 --- a/authorization/src/main/java/eu/arrowhead/core/authorization/security/AuthSecurityConfig.java +++ b/authorization/src/main/java/eu/arrowhead/core/authorization/security/AuthSecurityConfig.java @@ -8,5 +8,4 @@ @Configuration @EnableWebSecurity public class AuthSecurityConfig extends DefaultSecurityConfig { - } \ No newline at end of file diff --git a/authorization/src/main/java/eu/arrowhead/core/authorization/token/TokenGenerationService.java b/authorization/src/main/java/eu/arrowhead/core/authorization/token/TokenGenerationService.java index 86da3e05c..5a510b81a 100644 --- a/authorization/src/main/java/eu/arrowhead/core/authorization/token/TokenGenerationService.java +++ b/authorization/src/main/java/eu/arrowhead/core/authorization/token/TokenGenerationService.java @@ -44,6 +44,7 @@ public class TokenGenerationService { private final Logger logger = LogManager.getLogger(TokenGenerationService.class); + private static final String DOT = "."; private static final String JWT_CONTENT_TYPE = "JWT"; @Value(CommonConstants.$SERVER_SSL_ENABLED_WD) @@ -78,21 +79,17 @@ public Map> generateTokens(final TokenGenera final Map publicKeys = getProviderPublicKeys(request.getProviders()); final Map> result = new HashMap<>(publicKeys.size()); final String consumerInfo = generateConsumerInfo(request.getConsumer(), request.getConsumerCloud()); - final Map signedJWTs = new HashMap<>(); for (final TokenGenerationProviderDTO provider : request.getProviders()) { final SystemRequestDTO providerSystem = provider.getProvider(); if (publicKeys.containsKey(providerSystem)) { for (final String intf : provider.getServiceInterfaces()) { - String signedJWT = signedJWTs.get(intf); - if (signedJWT == null) { - try { - signedJWT = generateSignedJWT(consumerInfo, request.getService(), intf, request.getDuration()); - signedJWTs.put(intf, signedJWT); - } catch (final JoseException ex) { - logger.error("Problem occured when trying to sign JWT token", ex); - throw new ArrowheadException("Token generation failed"); // if there is a problem here, all calling cause the same problem - } + String signedJWT; + try { + signedJWT = generateSignedJWT(consumerInfo, request.getService(), intf, provider.getTokenDuration() < 0 ? null: provider.getTokenDuration()); + } catch (final JoseException ex) { + logger.error("Problem occured when trying to sign JWT token", ex); + throw new ArrowheadException("Token generation failed"); // if there is a problem here, all calling cause the same problem } try { @@ -174,7 +171,7 @@ private void checkTokenGeneratorionProviderDTO(final TokenGenerationProviderDTO for (final String intf : provider.getServiceInterfaces()) { if (!interfaceNameVerifier.isValid(intf)) { - throw new InvalidParameterException("Specified interface name is not valid: " + intf + "."); + throw new InvalidParameterException("Specified interface name is not valid: " + intf + DOT); } } } @@ -194,14 +191,14 @@ private String generateConsumerInfo(final SystemRequestDTO consumer, final Cloud final StringBuilder sb = new StringBuilder(consumer.getSystemName()); if (consumerCloud != null) { - sb.append(".").append(consumerCloud.getName().trim()).append(".").append(consumerCloud.getOperator().trim()); + sb.append(DOT).append(consumerCloud.getName().trim()).append(DOT).append(consumerCloud.getOperator().trim()); } else { // need to use own cloud information if (Utilities.isEmpty(ownCloudName)) { initOwnCloudInfo(); } - sb.append(".").append(ownCloudName).append(".").append(ownCloudOperator); + sb.append(DOT).append(ownCloudName).append(DOT).append(ownCloudOperator); } return sb.toString().toLowerCase(); @@ -284,7 +281,7 @@ private JwtClaims generateTokenPayload(final String consumerInfo, final String s claims.setIssuedAtToNow(); claims.setNotBeforeMinutesInThePast(1); if (duration != null) { - claims.setExpirationTimeMinutesInTheFuture(duration.floatValue()); + claims.setExpirationTimeMinutesInTheFuture(duration.floatValue() / CommonConstants.CONVERSION_SECOND_TO_MINUTE); } claims.setStringClaim(CommonConstants.JWT_CLAIM_CONSUMER_ID, consumerInfo); claims.setStringClaim(CommonConstants.JWT_CLAIM_SERVICE_ID, service.toLowerCase()); diff --git a/authorization/src/main/resources/application.properties b/authorization/src/main/resources/application.properties index e5921426f..ae4c9157c 100644 --- a/authorization/src/main/resources/application.properties +++ b/authorization/src/main/resources/application.properties @@ -61,6 +61,6 @@ server.ssl.trust-store-type=PKCS12 server.ssl.trust-store=classpath:certificates/truststore.p12 server.ssl.trust-store-password=123456 -#If true, http client does not check whether the hostname is match one of the server's SAN in its certificate -#Just for testing, DO NOT USE this feature in production environment +# If true, http client does not check whether the hostname is match one of the server's SAN in its certificate +# Just for testing, DO NOT USE this feature in production environment disable.hostname.verifier=false \ No newline at end of file diff --git a/authorization/src/test/java/eu/arrowhead/core/authorization/AuthorizationControllerInterCloudTest.java b/authorization/src/test/java/eu/arrowhead/core/authorization/AuthorizationControllerInterCloudTest.java index 41ac703e7..18e58e886 100644 --- a/authorization/src/test/java/eu/arrowhead/core/authorization/AuthorizationControllerInterCloudTest.java +++ b/authorization/src/test/java/eu/arrowhead/core/authorization/AuthorizationControllerInterCloudTest.java @@ -435,7 +435,7 @@ public void testCheckAuthorizationInterCloudRequestDBCall() throws Exception { //------------------------------------------------------------------------------------------------- private List createIdList(final int firstNum, final int lastNum) { - final List idList = new ArrayList<>(lastNum); + final List idList = new ArrayList<>(lastNum - firstNum + 1); for (int i = firstNum; i <= lastNum; ++i) { idList.add((long) i); } @@ -449,7 +449,7 @@ private Page createPageForMockingAuthorizationDBService final Cloud cloud = getValidTestCloud(); final System provider = new System("testSystem", "testAddr", 2000, "TOKEN"); for (int i = 1; i <= numberOfRequestedEntry; ++i) { - final ServiceDefinition serviceDefinition = new ServiceDefinition("testService"+i); + final ServiceDefinition serviceDefinition = new ServiceDefinition("testService" + i); serviceDefinition.setId(i); serviceDefinition.setCreatedAt(zdTime); serviceDefinition.setUpdatedAt(zdTime); diff --git a/authorization/src/test/java/eu/arrowhead/core/authorization/AuthorizationControllerIntraCloudTest.java b/authorization/src/test/java/eu/arrowhead/core/authorization/AuthorizationControllerIntraCloudTest.java index e4fe7b858..cc36f6f22 100644 --- a/authorization/src/test/java/eu/arrowhead/core/authorization/AuthorizationControllerIntraCloudTest.java +++ b/authorization/src/test/java/eu/arrowhead/core/authorization/AuthorizationControllerIntraCloudTest.java @@ -511,7 +511,7 @@ private Page createPageForMockingAuthorizationDBService //------------------------------------------------------------------------------------------------- private List createIdList(final int firstNum, final int lastNum) { - final List idList = new ArrayList<>(lastNum); + final List idList = new ArrayList<>(lastNum - firstNum + 1); for (int i = firstNum; i <= lastNum; ++i) { idList.add((long) i); } diff --git a/authorization/src/test/java/eu/arrowhead/core/authorization/AuthorizationControllerTokenTest.java b/authorization/src/test/java/eu/arrowhead/core/authorization/AuthorizationControllerTokenTest.java index 2b0593fec..33a528f24 100644 --- a/authorization/src/test/java/eu/arrowhead/core/authorization/AuthorizationControllerTokenTest.java +++ b/authorization/src/test/java/eu/arrowhead/core/authorization/AuthorizationControllerTokenTest.java @@ -529,8 +529,8 @@ private TokenGenerationRequestDTO getRequest() { provider.setPort(18765); provider.setAuthenticationInfo("MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1aaeuv1I4bF5dxMIvUvLMxjRn309kdJewIIH08DfL17/LSssD70ZaLz0yxNfbPPQpFK8LMK+HQHDiGZH5yp4qJDuEgfmUrqWibnBIBc/K3Ob45lQy0zdFVtFsVJYBFVymQwgxJT6th0hI3RGLbCJMzbmpDzT7g0IDsN+64tMyi08ZCPrqk99uzYgioSSWNb9bhG2Z9646b3oiY5utQWRhP/2z/t6vVJHtRYeyaXPl6Z2M/5KnjpSvpSeZQhNrw+Is1DEE5DHiEjfQFWrLwDOqPKDrvmFyIlJ7P7OCMax6dIlSB7GEQSSP+j4eIxDWgjm+Pv/c02UVDc0x3xX/UGtNwIDAQAB"); - final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(provider, List.of("HTTP-SECURE-JSON")); + final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(provider, 6000, List.of("HTTP-SECURE-JSON")); - return new TokenGenerationRequestDTO(consumer, consumerCloud, List.of(providerDTO), "aservice", null); + return new TokenGenerationRequestDTO(consumer, consumerCloud, List.of(providerDTO), "aservice"); } } \ No newline at end of file diff --git a/authorization/src/test/java/eu/arrowhead/core/authorization/StandaloneModeInAuthorizationTests.java b/authorization/src/test/java/eu/arrowhead/core/authorization/StandaloneModeInAuthorizationTests.java index 3f9dfa70e..6b0cdf6ff 100644 --- a/authorization/src/test/java/eu/arrowhead/core/authorization/StandaloneModeInAuthorizationTests.java +++ b/authorization/src/test/java/eu/arrowhead/core/authorization/StandaloneModeInAuthorizationTests.java @@ -6,5 +6,4 @@ @Component public class StandaloneModeInAuthorizationTests extends StandaloneModeInTests { - } \ No newline at end of file diff --git a/authorization/src/test/java/eu/arrowhead/core/authorization/database/service/AuthorizationDBServiceInterCloudTest.java b/authorization/src/test/java/eu/arrowhead/core/authorization/database/service/AuthorizationDBServiceInterCloudTest.java index 31a889dad..08f953943 100644 --- a/authorization/src/test/java/eu/arrowhead/core/authorization/database/service/AuthorizationDBServiceInterCloudTest.java +++ b/authorization/src/test/java/eu/arrowhead/core/authorization/database/service/AuthorizationDBServiceInterCloudTest.java @@ -73,7 +73,7 @@ public class AuthorizationDBServiceInterCloudTest { // methods //================================================================================================= - //Tests of getAuthorizationInterCloudEntries + // Tests of getAuthorizationInterCloudEntries //------------------------------------------------------------------------------------------------- @Test @@ -90,7 +90,7 @@ public void testGetAuthorizationInterCloudEntriesWithNotValidSortField() { } //================================================================================================= - //Tests of getAuthorizationInterCloudEntryById + // Tests of getAuthorizationInterCloudEntryById //------------------------------------------------------------------------------------------------- @Test(expected = InvalidParameterException.class) @@ -100,7 +100,7 @@ public void testGetAuthorizationInterCloudEntryByIdWithNotExistingId() { } //================================================================================================= - //Tests of removeAuthorizationInterCloudEntryById + // Tests of removeAuthorizationInterCloudEntryById //------------------------------------------------------------------------------------------------- @Test(expected = InvalidParameterException.class) @@ -110,7 +110,7 @@ public void testRemoveAuthorizationInterCloudEntryByIdWithNotExistingId() { } //================================================================================================= - //Tests of createBulkAuthorizationInterCloud + // Tests of createBulkAuthorizationInterCloud //------------------------------------------------------------------------------------------------- @Test(expected = InvalidParameterException.class) @@ -224,7 +224,7 @@ public void testCreateBulkAuthorizationInterCloudDBCall() { } //================================================================================================= - //Tests of checkAuthorizationInterCloudResponse + // Tests of checkAuthorizationInterCloudResponse //------------------------------------------------------------------------------------------------- @Test(expected = InvalidParameterException.class) diff --git a/authorization/src/test/java/eu/arrowhead/core/authorization/database/service/AuthorizationDBServiceIntraCloudTest.java b/authorization/src/test/java/eu/arrowhead/core/authorization/database/service/AuthorizationDBServiceIntraCloudTest.java index ce14de33c..71760a404 100644 --- a/authorization/src/test/java/eu/arrowhead/core/authorization/database/service/AuthorizationDBServiceIntraCloudTest.java +++ b/authorization/src/test/java/eu/arrowhead/core/authorization/database/service/AuthorizationDBServiceIntraCloudTest.java @@ -65,7 +65,7 @@ public class AuthorizationDBServiceIntraCloudTest { // methods //================================================================================================= - //Tests of getAuthorizationIntraCloudEntries + // Tests of getAuthorizationIntraCloudEntries //------------------------------------------------------------------------------------------------- @Test @@ -82,7 +82,7 @@ public void testGetAuthorizationIntraCloudEntriesWithNotValidSortField() { } //================================================================================================= - //Tests of getAuthorizationIntraCloudEntryById + // Tests of getAuthorizationIntraCloudEntryById //------------------------------------------------------------------------------------------------- @Test(expected = InvalidParameterException.class) @@ -92,7 +92,7 @@ public void testGetAuthorizationIntraCloudEntryByIdWithNotExistingId() { } //================================================================================================= - //Tests of removeAuthorizationIntraCloudEntryById + // Tests of removeAuthorizationIntraCloudEntryById //------------------------------------------------------------------------------------------------- @Test(expected = InvalidParameterException.class) @@ -102,7 +102,7 @@ public void testRemoveAuthorizationIntraCloudEntryByIdWithNotExistingId() { } //================================================================================================= - //Tests of createBulkAuthorizationIntraCloud + // Tests of createBulkAuthorizationIntraCloud //------------------------------------------------------------------------------------------------- @Test(expected = InvalidParameterException.class) diff --git a/authorization/src/test/java/eu/arrowhead/core/authorization/token/TokenGenerationServiceTest.java b/authorization/src/test/java/eu/arrowhead/core/authorization/token/TokenGenerationServiceTest.java index 948994922..2f910d121 100644 --- a/authorization/src/test/java/eu/arrowhead/core/authorization/token/TokenGenerationServiceTest.java +++ b/authorization/src/test/java/eu/arrowhead/core/authorization/token/TokenGenerationServiceTest.java @@ -91,7 +91,7 @@ public void testGenerateTokenNullConsumer() { @Test(expected = InvalidParameterException.class) public void testGenerateTokenConsumerNameNull() { final SystemRequestDTO consumer = new SystemRequestDTO(); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(new TokenGenerationProviderDTO()), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(new TokenGenerationProviderDTO()), "testService"); tokenGenerationService.generateTokens(request); } @@ -100,7 +100,7 @@ public void testGenerateTokenConsumerNameNull() { public void testGenerateTokenConsumerNameEmpty() { final SystemRequestDTO consumer = new SystemRequestDTO(); consumer.setSystemName(" "); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(new TokenGenerationProviderDTO()), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(new TokenGenerationProviderDTO()), "testService"); tokenGenerationService.generateTokens(request); } @@ -109,7 +109,7 @@ public void testGenerateTokenConsumerNameEmpty() { public void testGenerateTokenConsumerCloudOperatorNull() { final SystemRequestDTO consumer = new SystemRequestDTO(); consumer.setSystemName("consumer"); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, new CloudRequestDTO(), List.of(new TokenGenerationProviderDTO()), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, new CloudRequestDTO(), List.of(new TokenGenerationProviderDTO()), "testService"); tokenGenerationService.generateTokens(request); } @@ -120,7 +120,7 @@ public void testGenerateTokenConsumerCloudOperatorEmpty() { consumer.setSystemName("consumer"); final CloudRequestDTO consumerCloud = new CloudRequestDTO(); consumerCloud.setOperator(" "); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, consumerCloud, List.of(new TokenGenerationProviderDTO()), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, consumerCloud, List.of(new TokenGenerationProviderDTO()), "testService"); tokenGenerationService.generateTokens(request); } @@ -131,7 +131,7 @@ public void testGenerateTokenConsumerCloudNameNull() { consumer.setSystemName("consumer"); final CloudRequestDTO consumerCloud = new CloudRequestDTO(); consumerCloud.setOperator("aitia"); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, consumerCloud, List.of(new TokenGenerationProviderDTO()), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, consumerCloud, List.of(new TokenGenerationProviderDTO()), "testService"); tokenGenerationService.generateTokens(request); } @@ -143,7 +143,7 @@ public void testGenerateTokenConsumerCloudNameEmpty() { final CloudRequestDTO consumerCloud = new CloudRequestDTO(); consumerCloud.setOperator("aitia"); consumerCloud.setName(" "); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, consumerCloud, List.of(new TokenGenerationProviderDTO()), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, consumerCloud, List.of(new TokenGenerationProviderDTO()), "testService"); tokenGenerationService.generateTokens(request); } @@ -152,7 +152,7 @@ public void testGenerateTokenConsumerCloudNameEmpty() { public void testGenerateTokenProvidersListNull() { final SystemRequestDTO consumer = new SystemRequestDTO(); consumer.setSystemName("consumer"); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(new TokenGenerationProviderDTO()), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(new TokenGenerationProviderDTO()), "testService"); request.setProviders(null); tokenGenerationService.generateTokens(request); } @@ -162,7 +162,7 @@ public void testGenerateTokenProvidersListNull() { public void testGenerateTokenProvidersListEmpty() { final SystemRequestDTO consumer = new SystemRequestDTO(); consumer.setSystemName("consumer"); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(new TokenGenerationProviderDTO()), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(new TokenGenerationProviderDTO()), "testService"); request.setProviders(List.of()); tokenGenerationService.generateTokens(request); } @@ -172,7 +172,7 @@ public void testGenerateTokenProvidersListEmpty() { public void testGenerateTokenProviderNull() { final SystemRequestDTO consumer = new SystemRequestDTO(); consumer.setSystemName("consumer"); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(new TokenGenerationProviderDTO()), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(new TokenGenerationProviderDTO()), "testService"); tokenGenerationService.generateTokens(request); } @@ -183,7 +183,7 @@ public void testGenerateTokenProviderNameNull() { consumer.setSystemName("consumer"); final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(); providerDTO.setProvider(new SystemRequestDTO()); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService"); tokenGenerationService.generateTokens(request); } @@ -196,7 +196,7 @@ public void testGenerateTokenProviderNameEmpty() { provider.setSystemName(" "); final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(); providerDTO.setProvider(provider); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService"); tokenGenerationService.generateTokens(request); } @@ -209,7 +209,7 @@ public void testGenerateTokenServiceInterfacesNull() { provider.setSystemName("provider"); final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(); providerDTO.setProvider(provider); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService"); tokenGenerationService.generateTokens(request); } @@ -223,7 +223,7 @@ public void testGenerateTokenServiceInterfacesEmpty() { final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(); providerDTO.setProvider(provider); providerDTO.setServiceInterfaces(List.of()); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService"); tokenGenerationService.generateTokens(request); } @@ -237,7 +237,7 @@ public void testGenerateTokenServiceInterfaceInvalid() { final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(); providerDTO.setProvider(provider); providerDTO.setServiceInterfaces(List.of("INVALID")); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService"); tokenGenerationService.generateTokens(request); } @@ -251,7 +251,7 @@ public void testGenerateTokenServiceNull() { final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(); providerDTO.setProvider(provider); providerDTO.setServiceInterfaces(List.of("HTTP-SECURE-JSON")); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService"); request.setService(null); tokenGenerationService.generateTokens(request); } @@ -266,7 +266,7 @@ public void testGenerateTokenServiceEmpty() { final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(); providerDTO.setProvider(provider); providerDTO.setServiceInterfaces(List.of("HTTP-SECURE-JSON")); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService"); request.setService(" \t"); tokenGenerationService.generateTokens(request); } @@ -281,7 +281,7 @@ public void testGenerateTokenProviderHasNoKey() { final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(); providerDTO.setProvider(provider); providerDTO.setServiceInterfaces(List.of("HTTP-SECURE-JSON")); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService"); tokenGenerationService.generateTokens(request); } @@ -296,7 +296,7 @@ public void testGenerateTokenProviderHasNotValidKey() { final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(); providerDTO.setProvider(provider); providerDTO.setServiceInterfaces(List.of("HTTP-SECURE-JSON")); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService"); tokenGenerationService.generateTokens(request); } @@ -313,7 +313,7 @@ public void testGenerateTokenProviderInitOwnCloudFromCertificateNoCommonName() { final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(); providerDTO.setProvider(provider); providerDTO.setServiceInterfaces(List.of("HTTP-SECURE-JSON")); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, null, List.of(providerDTO), "testService"); tokenGenerationService.generateTokens(request); } @@ -331,7 +331,7 @@ public void testGenerateTokenProviderNoServerPrivateKey() { final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(); providerDTO.setProvider(provider); providerDTO.setServiceInterfaces(List.of("HTTP-SECURE-JSON")); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, cloud, List.of(providerDTO), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, cloud, List.of(providerDTO), "testService"); tokenGenerationService.generateTokens(request); } @@ -351,7 +351,7 @@ public void testGenerateTokenProviderErrorWhileSigning() throws Exception { final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(); providerDTO.setProvider(provider); providerDTO.setServiceInterfaces(List.of("HTTP-SECURE-JSON")); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, cloud, List.of(providerDTO), "testService", null); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, cloud, List.of(providerDTO), "testService"); tokenGenerationService.generateTokens(request); } @@ -375,7 +375,8 @@ public void testTokenGenerationOk() throws Exception { final TokenGenerationProviderDTO providerDTO = new TokenGenerationProviderDTO(); providerDTO.setProvider(provider); providerDTO.setServiceInterfaces(List.of("HTTP-SECURE-JSON")); - final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, cloud, List.of(providerDTO), "testservice", 10); + providerDTO.setTokenDuration(600); + final TokenGenerationRequestDTO request = new TokenGenerationRequestDTO(consumer, cloud, List.of(providerDTO), "testservice"); final Map> result = tokenGenerationService.generateTokens(request); Assert.assertTrue(!result.isEmpty()); Assert.assertTrue(result.containsKey(provider)); diff --git a/certificate-authority/.classpath b/certificate-authority/.classpath new file mode 100644 index 000000000..6e0021feb --- /dev/null +++ b/certificate-authority/.classpath @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/certificate-authority/.project b/certificate-authority/.project new file mode 100644 index 000000000..9b4a8b591 --- /dev/null +++ b/certificate-authority/.project @@ -0,0 +1,23 @@ + + + arrowhead-certificate-authority + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/certificate-authority/pom.xml b/certificate-authority/pom.xml new file mode 100644 index 000000000..257563a28 --- /dev/null +++ b/certificate-authority/pom.xml @@ -0,0 +1,153 @@ + + 4.0.0 + + eu.arrowhead + core + ${revision} + + + arrowhead-certificate-authority + jar + Arrowhead Certificate Authority + Certificate Authority core service + + + + eu.arrowhead + arrowhead-core-common + ${revision} + + + + org.bouncycastle + bcprov-jdk15on + ${bouncy.castle.version} + + + + org.bouncycastle + bcpkix-jdk15on + ${bouncy.castle.version} + + + org.jetbrains + annotations + 18.0.0 + compile + + + + + + + maven-resources-plugin + ${mvn.resources.version} + + + copy-resources + + validate + + copy-resources + + + ${basedir}/target + + + src/main/resources + + application.properties + log4j2.xml + + + + + + + + + + jdeb + org.vafer + 1.8 + + + package + + jdeb + + + true + [YYMMddHHmm].${git.commit.id.abbrev} + target/${project.artifactId}_${revision}.deb + true + ${basedir}/src/deb/control + + + file + ${project.build.directory}/${project.build.finalName}.jar + + perm + /usr/share/arrowhead/certificate_authority + 755 + + + + + link + /usr/share/arrowhead/certificate_authority/${project.artifactId}.jar + /usr/share/arrowhead/certificate_authority/${project.build.finalName}.jar + + + + file + ${project.build.directory}/log4j2.xml + + perm + /etc/arrowhead/systems/certificate_authority + 644 + + + + + file + ${project.build.directory}/application.properties + + perm + /etc/arrowhead/systems/certificate_authority + 644 + + + + + link + /usr/share/arrowhead/certificate_authority/application.properties + /etc/arrowhead/systems/certificate_authority/application.properties + + + + file + ${project.basedir}/src/deb/arrowhead-certificate-authority.service + + perm + /etc/systemd/system + 644 + + + + + file + ${project.basedir}/../scripts/certificate_authority_privileges.sql + + perm + /usr/share/arrowhead/conf + + + + + + + + + + diff --git a/certificate-authority/src/deb/arrowhead-certificate-authority.service b/certificate-authority/src/deb/arrowhead-certificate-authority.service new file mode 100644 index 000000000..31d62af19 --- /dev/null +++ b/certificate-authority/src/deb/arrowhead-certificate-authority.service @@ -0,0 +1,15 @@ +[Unit] +Description=arrowhead-certificate-authority +After=network.target mysql.target + +[Service] +WorkingDirectory=/etc/arrowhead/systems/certificate_authority +ExecStart=/usr/bin/java -Dlog4j.configurationFile=file:/etc/arrowhead/systems/certificate_authority/log4j2.xml -jar /usr/share/arrowhead/certificate_authority/arrowhead-certificate-authority.jar +ExecStartPost=/bin/bash -c 'sleep 10' +TimeoutStopSec=5 +Type=simple +User=arrowhead +Group=arrowhead + +[Install] +WantedBy=default.target diff --git a/certificate-authority/src/deb/control/config b/certificate-authority/src/deb/control/config new file mode 100644 index 000000000..1c83ed2f4 --- /dev/null +++ b/certificate-authority/src/deb/control/config @@ -0,0 +1,20 @@ +#!/bin/sh -e + +. /usr/share/debconf/confmodule + +if logname 2>/dev/null; then + USER=$(logname) + HOME=$(eval echo "~$USER") +else + USER="root" + HOME="/root" +fi + +# Get installation type +db_input high arrowhead-core-common/db_host || true +db_input high arrowhead-core-common/mysql_password_ca || true +db_input high arrowhead-core-common/sr_host || true + +# Run dialogs +db_go || true + diff --git a/certificate-authority/src/deb/control/control b/certificate-authority/src/deb/control/control new file mode 100644 index 000000000..1b7ccbf25 --- /dev/null +++ b/certificate-authority/src/deb/control/control @@ -0,0 +1,10 @@ +Package: arrowhead-certificate-authority +Version: [[version]] +Section: contrib/java +Priority: optional +Architecture: all +Maintainer: Rajmund Bocsi +Homepage: http://www.arrowhead.eu +Description: Arrowhead Certificate Authority +Distribution: development +Depends: java-runtime-headless, openssl, virtual-mysql-server, arrowhead-core-common diff --git a/certificate-authority/src/deb/control/postinst b/certificate-authority/src/deb/control/postinst new file mode 100644 index 000000000..a47d9de5a --- /dev/null +++ b/certificate-authority/src/deb/control/postinst @@ -0,0 +1,82 @@ +#!/bin/sh +# postinst script for arrowhead-certificate-authority +# +# see: dh_installdeb(1) + +set -e + +. /usr/share/debconf/confmodule + +SYSTEM_NAME="certificate_authority" +PKG_NAME="arrowhead-certificate-authority" + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + +case "$1" in + configure) + . /usr/share/arrowhead/conf/ahconf.sh + SYSTEM_DIR="${AH_SYSTEMS_DIR}/${SYSTEM_NAME}" + + db_get arrowhead-core-common/mysql_password_ca; system_passwd=$RET || true + db_unregister arrowhead-core-common/mysql_password_ca + + # Generate password (if required) + if [ -z "${system_passwd}" ]; then + system_passwd="$(openssl rand -base64 12)" + fi + + echo "Configuring MySQL database..." >&2 + ah_db_tables_and_user ${SYSTEM_NAME} ${SYSTEM_NAME}_privileges.sql ${system_passwd} + + if [ ! -d "${SYSTEM_DIR}" ]; then + mkdir -p ${SYSTEM_DIR} + fi + + ah_ca_keystore ${SYSTEM_NAME} + + mv ${SYSTEM_DIR}/application.properties ${SYSTEM_DIR}/application.properties.orig + cat ${SYSTEM_DIR}/application.properties.orig | \ + sed -r -e "\#^.*spring\.datasource\.url=#s#.*\$#spring.datasource.url=jdbc:mysql://"${db_host}":3306/arrowhead?serverTimezone=Europe/Budapest#" \ + -e "\#^.*spring\.datasource\.password=#s#.*\$#spring.datasource.password=${system_passwd}#" \ + -e "\#^.*server\.address=#s#.*\$#server.address=${OWN_IP}#" \ + -e "\#^.*server\.ssl\.key-store=#s#.*\$#server.ssl.key-store=file:${SYSTEM_DIR}/${SYSTEM_NAME}.p12#" \ + -e "\#^.*server\.ssl\.key-store-password=#s#.*\$#server.ssl.key-store-password=${AH_PASS_CERT}#" \ + -e "\#^.*server\.ssl\.key-password=#s#.*\$#server.ssl.key-password=${AH_PASS_CERT}#" \ + -e "\#^.*server\.ssl\.trust-store=#s#.*\$#server.ssl.trust-store=file:${AH_CONF_DIR}/truststore.p12#" \ + -e "\#^.*server\.ssl\.trust-store-password=#s#.*\$#server.ssl.trust-store-password=${AH_PASS_CERT}#" > ${SYSTEM_DIR}/application.properties + + rm ${SYSTEM_DIR}/application.properties.orig + chown arrowhead:arrowhead ${SYSTEM_DIR}/application.properties + chmod 640 ${SYSTEM_DIR}/application.properties + + echo "Starting ${PKG_NAME}..." >&2 + systemctl daemon-reload + systemctl enable ${PKG_NAME}.service + systemctl start ${PKG_NAME}.service + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/certificate-authority/src/deb/control/postrm b/certificate-authority/src/deb/control/postrm new file mode 100644 index 000000000..5ec593529 --- /dev/null +++ b/certificate-authority/src/deb/control/postrm @@ -0,0 +1,54 @@ +#!/bin/sh +# postrm script for arrowhead-certificate-authority +# +# see: dh_installdeb(1) + +set -e + +. /usr/share/debconf/confmodule + +SYSTEM_NAME="certificate_authority" + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + purge) + AH_CONF_DIR="/etc/arrowhead" + AH_SYSTEMS_DIR="${AH_CONF_DIR}/systems" + SYSTEM_DIR="${AH_SYSTEMS_DIR}/${SYSTEM_NAME}" + + rm -f \ + /var/log/arrowhead/${SYSTEM_NAME}*.log \ + ${SYSTEM_DIR}/log4j2.xml \ + ${SYSTEM_DIR}/application.properties \ + ${SYSTEM_DIR}/${SYSTEM_NAME}.p12 \ + rmdir ${SYSTEM_DIR} 2>/dev/null || true + db_purge + ;; + remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/certificate-authority/src/deb/control/preinst b/certificate-authority/src/deb/control/preinst new file mode 100644 index 000000000..a0a30f7d9 --- /dev/null +++ b/certificate-authority/src/deb/control/preinst @@ -0,0 +1,35 @@ +#!/bin/sh +# preinst script for arrowhead-certificate-authority +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `install' +# * `install' +# * `upgrade' +# * `abort-upgrade' +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + install|upgrade) + ;; + + abort-upgrade) + ;; + + *) + echo "preinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/certificate-authority/src/deb/control/prerm b/certificate-authority/src/deb/control/prerm new file mode 100644 index 000000000..4c2d565a7 --- /dev/null +++ b/certificate-authority/src/deb/control/prerm @@ -0,0 +1,45 @@ +#!/bin/sh +# prerm script for arrowhead-certificate-authority +# +# see: dh_installdeb(1) + +set -e + +PKG_NAME="arrowhead-certificate-authority" + +# summary of how this script can be called: +# * `remove' +# * `upgrade' +# * `failed-upgrade' +# * `remove' `in-favour' +# * `deconfigure' `in-favour' +# `removing' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + remove) + systemctl stop ${PKG_NAME}.service + systemctl disable ${PKG_NAME}.service + ;; + + upgrade|deconfigure) + ;; + + failed-upgrade) + ;; + + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CAProperties.java b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CAProperties.java new file mode 100644 index 000000000..d4120006a --- /dev/null +++ b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CAProperties.java @@ -0,0 +1,24 @@ +package eu.arrowhead.core.certificate_authority; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import eu.arrowhead.common.CommonConstants; + +@Component +public class CAProperties { + + @Value(CommonConstants.$CA_CERT_VALIDITY_NEG_OFFSET_MILLIS) + private long certValidityNegativeOffsetMinutes; + + @Value(CommonConstants.$CA_CERT_VALIDITY_POS_OFFSET_MILLIS) + private long certValidityPositiveOffsetMinutes; + + public long getCertValidityNegativeOffsetMinutes() { + return certValidityNegativeOffsetMinutes; + } + + public long getCertValidityPositiveOffsetMinutes() { + return certValidityPositiveOffsetMinutes; + } +} diff --git a/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityApplicationInitListener.java b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityApplicationInitListener.java new file mode 100644 index 000000000..aa3e97061 --- /dev/null +++ b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityApplicationInitListener.java @@ -0,0 +1,20 @@ +package eu.arrowhead.core.certificate_authority; + +import java.security.Security; + +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; +import eu.arrowhead.common.ApplicationInitListener; + +@Component +public class CertificateAuthorityApplicationInitListener extends ApplicationInitListener { + + @Override + protected void customInit(ContextRefreshedEvent event) { + logger.debug("customInit started..."); + + Security.addProvider(new BouncyCastleProvider()); + } + +} diff --git a/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityController.java b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityController.java new file mode 100644 index 000000000..75608ddb3 --- /dev/null +++ b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityController.java @@ -0,0 +1,106 @@ +package eu.arrowhead.core.certificate_authority; + +import java.util.List; + +import javax.validation.Valid; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.Defaults; +import eu.arrowhead.common.dto.internal.CertificateSigningRequestDTO; +import eu.arrowhead.common.dto.internal.CertificateSigningResponseDTO; +import eu.arrowhead.common.exception.BadPayloadException; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.validation.BindingResult; +import org.springframework.validation.ObjectError; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@Api(tags = { CoreCommonConstants.SWAGGER_TAG_ALL }) +@CrossOrigin(maxAge = Defaults.CORS_MAX_AGE, allowCredentials = Defaults.CORS_ALLOW_CREDENTIALS, + allowedHeaders = { HttpHeaders.ORIGIN, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT, HttpHeaders.AUTHORIZATION } +) +@RestController +@RequestMapping(CommonConstants.CERTIFICATE_AUTHRORITY_URI) +public class CertificateAuthorityController { + + //================================================================================================= + // members + // + private static final String GET_CLOUD_COMMON_NAME_HTTP_200_MESSAGE = "Cloud Common Name returned"; + private static final String SIGN_CERTIFICATE_HTTP_200_MESSAGE = "Successful certificate signing"; + private static final String SIGN_CERTIFICATE_HTTP_400_MESSAGE = "Invalid Certificate Signing Request"; + + private final Logger logger = LogManager.getLogger(CertificateAuthorityController.class); + + @Autowired + private CertificateAuthorityService certificateAuthorityService; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return an echo message with the purpose of testing the core service availability", response = String.class, tags = { CoreCommonConstants.SWAGGER_TAG_CLIENT }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = CoreCommonConstants.SWAGGER_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = CommonConstants.ECHO_URI) + public String echoService() { + return "Got it!"; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return the cloud's Common Name", response = String.class, tags = { CoreCommonConstants.SWAGGER_TAG_CLIENT }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_CLOUD_COMMON_NAME_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = CommonConstants.OP_CA_CLOUD_COMMON_NAME_URI) + public String getCloudCommonName() { + logger.debug("getCloudCommonName started ..."); + + return certificateAuthorityService.getCloudCommonName(); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return a signed certificate", response = CertificateSigningResponseDTO.class, tags = { CoreCommonConstants.SWAGGER_TAG_CLIENT }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = SIGN_CERTIFICATE_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = SIGN_CERTIFICATE_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(path = CommonConstants.OP_CA_SIGN_CERTIFICATE_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public CertificateSigningResponseDTO signCertificate(@Valid @RequestBody final CertificateSigningRequestDTO request, BindingResult bindingResult) { + handleBindingResult(bindingResult); + return certificateAuthorityService.signCertificate(request); + } + + private void handleBindingResult(BindingResult bindingResult) { + if (bindingResult.hasErrors()) { + final List allErrors = bindingResult.getAllErrors(); + for (ObjectError error : allErrors) { + logger.debug(error.toString()); + } + throw new BadPayloadException(allErrors.get(0).getDefaultMessage()); + } + } +} diff --git a/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityMain.java b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityMain.java new file mode 100644 index 000000000..a984109d5 --- /dev/null +++ b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityMain.java @@ -0,0 +1,28 @@ +package eu.arrowhead.core.certificate_authority; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.database.repository.RefreshableRepositoryImpl; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@SpringBootApplication +@ComponentScan(CommonConstants.BASE_PACKAGE) +@EntityScan(CoreCommonConstants.DATABASE_ENTITY_PACKAGE) +@EnableJpaRepositories(basePackages = CoreCommonConstants.DATABASE_REPOSITORY_PACKAGE, repositoryBaseClass = RefreshableRepositoryImpl.class) +@EnableSwagger2 +public class CertificateAuthorityMain { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public static void main(final String[] args) { + SpringApplication.run(CertificateAuthorityMain.class, args); + } +} \ No newline at end of file diff --git a/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityService.java b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityService.java new file mode 100644 index 000000000..4c4e71d5a --- /dev/null +++ b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityService.java @@ -0,0 +1,126 @@ +package eu.arrowhead.core.certificate_authority; + +import eu.arrowhead.common.SSLProperties; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.dto.internal.CertificateSigningRequestDTO; +import eu.arrowhead.common.dto.internal.CertificateSigningResponseDTO; +import eu.arrowhead.common.exception.InvalidParameterException; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.SecureRandom; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.ServiceConfigurationError; + +@Service +public class CertificateAuthorityService { + + private static final Logger logger = LogManager.getLogger(CertificateAuthorityService.class); + + @Autowired + private SSLProperties sslProperties; + + @Autowired + private CAProperties caProperties; + + private SecureRandom random; + private KeyStore keyStore; + + private X509Certificate rootCertificate; + private X509Certificate cloudCertificate; + private String cloudCommonName; + + @PostConstruct + private void init() { + random = new SecureRandom(); + //random.reseed(); + keyStore = getKeyStore(); + + rootCertificate = Utilities.getRootCertFromKeyStore(keyStore); + cloudCertificate = Utilities.getCloudCertFromKeyStore(keyStore); + cloudCommonName = CertificateAuthorityUtils.getCloudCommonName(cloudCertificate); + } + + public String getCloudCommonName() { + return cloudCommonName; + } + + public CertificateSigningResponseDTO signCertificate(CertificateSigningRequestDTO request) { + verifyCertificateSigningRequest(request); + + final JcaPKCS10CertificationRequest csr = CertificateAuthorityUtils.decodePKCS10CSR(request); + CertificateAuthorityUtils.checkCommonName(csr, cloudCommonName); + CertificateAuthorityUtils.checkCsrSignature(csr); + + logger.info("Signing certificate for " + csr.getSubject().toString() + "..."); + + final PrivateKey cloudPrivateKey = Utilities.getCloudPrivateKey(keyStore, cloudCommonName, + sslProperties.getKeyPassword()); + + final X509Certificate clientCertificate = buildCertificate(csr, cloudPrivateKey, cloudCertificate); + final List encodedCertificateChain = buildEncodedCertificateChain(clientCertificate); + + return new CertificateSigningResponseDTO(encodedCertificateChain); + } + + private KeyStore getKeyStore() { + try { + final KeyStore keystore = KeyStore.getInstance(sslProperties.getKeyStoreType()); + keystore.load(sslProperties.getKeyStore().getInputStream(), + sslProperties.getKeyStorePassword().toCharArray()); + return keystore; + } catch (KeyStoreException | IOException | CertificateException | NoSuchAlgorithmException e) { + throw new ServiceConfigurationError("Cannot open keystore: " + e.getMessage()); + } + } + + private static void verifyCertificateSigningRequest(CertificateSigningRequestDTO request) { + if (request == null) { + logger.error("CertificateSigningRequest cannot be null"); + throw new InvalidParameterException("CertificateSigningRequest cannot be null"); + } + + final String encodedCSR = request.getEncodedCSR(); + + if (encodedCSR == null || encodedCSR.isEmpty()) { + logger.error("CertificateSigningRequest cannot be empty"); + throw new InvalidParameterException("CertificateSigningRequest cannot be empty"); + } + } + + private List buildEncodedCertificateChain(X509Certificate clientCertificate) { + final ArrayList encodedCertificateChain = new ArrayList<>(); + encodedCertificateChain.add(CertificateAuthorityUtils.encodeCertificate(clientCertificate)); + encodedCertificateChain.add(CertificateAuthorityUtils.encodeCertificate(cloudCertificate)); + encodedCertificateChain.add(CertificateAuthorityUtils.encodeCertificate(rootCertificate)); + return encodedCertificateChain; + } + + private X509Certificate buildCertificate(JcaPKCS10CertificationRequest csr, PrivateKey cloudPrivateKey, + X509Certificate cloudCertificate) { + final ZonedDateTime now = ZonedDateTime.now(); + final Date validFrom = Date.from( + now.minusMinutes(caProperties.getCertValidityNegativeOffsetMinutes()).toInstant()); + final Date validUntil = Date.from( + now.plusMinutes(caProperties.getCertValidityPositiveOffsetMinutes()).toInstant()); + + logger.debug("Setting validity from='{}' to='{}'", validFrom, validUntil); + return CertificateAuthorityUtils.buildCertificate(csr, cloudPrivateKey, cloudCertificate, validFrom, validUntil, + random); + } +} diff --git a/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityUtils.java b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityUtils.java new file mode 100644 index 000000000..3e6528319 --- /dev/null +++ b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityUtils.java @@ -0,0 +1,211 @@ +package eu.arrowhead.core.certificate_authority; + +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.dto.internal.CertificateSigningRequestDTO; +import eu.arrowhead.common.exception.AuthException; +import eu.arrowhead.common.exception.BadPayloadException; +import eu.arrowhead.common.exception.DataNotFoundException; +import eu.arrowhead.common.exception.InvalidParameterException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bouncycastle.asn1.pkcs.Attribute; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x500.RDN; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x500.style.BCStyle; +import org.bouncycastle.asn1.x500.style.IETFUtils; +import org.bouncycastle.asn1.x509.BasicConstraints; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNames; +import org.bouncycastle.cert.CertIOException; +import org.bouncycastle.cert.X509v3CertificateBuilder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.cert.jcajce.JcaX509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509ExtensionUtils; +import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder; +import org.bouncycastle.operator.ContentVerifierProvider; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.operator.jcajce.JcaContentVerifierProviderBuilder; +import org.bouncycastle.pkcs.PKCSException; +import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Base64; +import java.util.Date; +import java.util.List; +import java.util.Objects; +import java.util.ServiceConfigurationError; + +class CertificateAuthorityUtils { + + private static final Logger logger = LogManager.getLogger(CertificateAuthorityService.class); + + private static final String PROVIDER = "BC"; + private static final String SIGNATURE_ALGORITHM = "SHA256withRSA"; + + private CertificateAuthorityUtils() { + } + + static JcaPKCS10CertificationRequest decodePKCS10CSR(CertificateSigningRequestDTO csr) { + try { + final byte[] csrBytes = Base64.getDecoder().decode(csr.getEncodedCSR()); + return new JcaPKCS10CertificationRequest(csrBytes); + } catch (Exception e) { + logger.error("Failed to parse request as a PKCS10 CSR, because: " + e.getMessage()); + throw new BadPayloadException("Failed to parse request as a PKCS10 CSR", e); + } + } + + static String encodeCertificate(X509Certificate certificate) { + try { + return Base64.getEncoder().encodeToString(certificate.getEncoded()); + } catch (CertificateEncodingException | NullPointerException e) { + throw new AuthException("Certificate encoding failed! (" + e.getMessage() + ")", e); + } + } + + static String getCloudCommonName(X509Certificate cloudCertificate) { + try { + final X500Name subject = new JcaX509CertificateHolder(cloudCertificate).getSubject(); + final RDN cn = subject.getRDNs(BCStyle.CN)[0]; + return IETFUtils.valueToString(cn.getFirst().getValue()); + } catch (CertificateEncodingException | NullPointerException e) { + logger.error("Cannot get common name from cloud cert, because: " + e.getMessage()); + throw new ServiceConfigurationError("Cannot get common name from cloud cert.", e); + } + } + + static void checkCommonName(JcaPKCS10CertificationRequest csr, String cloudCN) { + if (csr == null) { + throw new BadPayloadException("CSR cannot be null"); + } + if (cloudCN == null || cloudCN.isEmpty()) { + throw new BadPayloadException("CloudCN cannot be null"); + } + final String clientCN = Objects.requireNonNull(Utilities.getCertCNFromSubject(csr.getSubject().toString())); + + if (!clientCN.endsWith(cloudCN) || clientCN.split("\\.").length > 6) { + throw new BadPayloadException( + "Certificate request does not have a valid common name! Valid common name: {systemName}." + + cloudCN); + } + } + + static void checkCsrSignature(JcaPKCS10CertificationRequest csr) { + try { + final ContentVerifierProvider verifierProvider = new JcaContentVerifierProviderBuilder() + .setProvider(PROVIDER) + .build(csr.getSubjectPublicKeyInfo()); + if (!csr.isSignatureValid(verifierProvider)) { + throw new BadPayloadException("Certificate request has invalid signature! (key pair does not match)"); + } + } catch (OperatorCreationException | PKCSException | NullPointerException e) { + throw new BadPayloadException("Encapsulated " + e.getClass().getCanonicalName() + ": " + e.getMessage(), e); + } + } + + static PublicKey getClientKey(JcaPKCS10CertificationRequest csr) { + try { + return csr.getPublicKey(); + } catch (InvalidKeyException | NoSuchAlgorithmException | NullPointerException e) { + // This should not be possible after a successful signature verification + throw new DataNotFoundException("Extracting the public key from the CSR failed (" + e.getMessage() + ")", + e); + } + } + + static X509Certificate buildCertificate(JcaPKCS10CertificationRequest csr, PrivateKey cloudPrivateKey, + X509Certificate cloudCertificate, Date validFrom, Date validUntil, SecureRandom random) { + + final BigInteger serial = new BigInteger(32, random); + + final PublicKey clientKey = getClientKey(csr); + + X509v3CertificateBuilder builder = new JcaX509v3CertificateBuilder(cloudCertificate, serial, validFrom, + validUntil, csr.getSubject(), clientKey); + + addCertificateExtensions(builder, csr, clientKey, cloudCertificate); + + JcaContentSignerBuilder signerBuilder = new JcaContentSignerBuilder(SIGNATURE_ALGORITHM).setProvider(PROVIDER); + try { + return new JcaX509CertificateConverter().setProvider(PROVIDER) + .getCertificate(builder.build(signerBuilder.build(cloudPrivateKey))); + } catch (CertificateException e) { + throw new BadPayloadException("Certificate encoding failed! (" + e.getMessage() + ")", e); + } catch (OperatorCreationException e) { + throw new BadPayloadException("Certificate signing failed! (" + e.getMessage() + ")", e); + } + } + + /** + * Adding the following extensions to the new certificate: + *
    + *
  1. The subject alternative name makes possible to use the certificate for + * accessing a host via IP address or hostname
  2. + * + *
  3. The subject key identifier provides a hashed value that should uniquely + * identify the public key
  4. + * + *
  5. The authority key identifier provides a hashed value that should uniquely + * identify the issuer of the certificate
  6. + * + *
  7. And this basic constraint is for forbidding issuing other certificates + * under this certificate
  8. + *
+ */ + static void addCertificateExtensions(X509v3CertificateBuilder builder, JcaPKCS10CertificationRequest csr, + PublicKey clientKey, X509Certificate cloudCertificate) { + try { + JcaX509ExtensionUtils extUtils = new JcaX509ExtensionUtils(); + + final List subjectAlternativeNames = getSubjectAlternativeNames(csr); + builder.addExtension(Extension.subjectAlternativeName, false, + new GeneralNames(subjectAlternativeNames.toArray(new GeneralName[]{}))); + builder.addExtension(Extension.subjectKeyIdentifier, false, extUtils.createSubjectKeyIdentifier(clientKey)); + builder.addExtension(Extension.authorityKeyIdentifier, false, + extUtils.createAuthorityKeyIdentifier(cloudCertificate)); + builder.addExtension(Extension.basicConstraints, true, new BasicConstraints(false)); + } catch (NoSuchAlgorithmException | CertIOException | CertificateEncodingException | NullPointerException e) { + throw new InvalidParameterException("Appending extensions to the certificate failed! (" + e.getMessage() + ")", e); + } + } + + static List getSubjectAlternativeNames(JcaPKCS10CertificationRequest csr) { + if (csr == null) { + throw new InvalidParameterException("CSR cannot be null"); + } + + List alternativeNames = new ArrayList<>(); + for (final Attribute attribute : csr.getAttributes()) { + if (attribute == null) { + continue; + } + if (attribute.getAttrType().equals(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest)) { + final Extensions extensions = Extensions.getInstance(attribute.getAttrValues().getObjectAt(0)); + final GeneralNames generalNames = GeneralNames.fromExtensions(extensions, + Extension.subjectAlternativeName); + if (generalNames != null && generalNames.getNames() != null && generalNames.getNames().length > 0) { + for (final GeneralName name : generalNames.getNames()) { + if (name.getTagNo() == GeneralName.dNSName || name.getTagNo() == GeneralName.iPAddress) { + alternativeNames.add(name); + } + } + } + } + } + + return alternativeNames; + } +} diff --git a/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/security/CAAccessControlFilter.java b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/security/CAAccessControlFilter.java new file mode 100644 index 000000000..0af563874 --- /dev/null +++ b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/security/CAAccessControlFilter.java @@ -0,0 +1,34 @@ +package eu.arrowhead.core.certificate_authority.security; + +import java.util.Map; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.security.CoreSystemAccessControlFilter; + +@Component +@ConditionalOnProperty(name = CommonConstants.SERVER_SSL_ENABLED, matchIfMissing = true) +public class CAAccessControlFilter extends CoreSystemAccessControlFilter { + + //================================================================================================= + // members + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + @Override + protected void checkClientAuthorized(final String clientCN, final String method, final String requestTarget, final String requestJSON, final Map queryParams) { + super.checkClientAuthorized(clientCN, method, requestTarget, requestJSON, queryParams); + + final String cloudCN = getServerCloudCN(); + + if (requestTarget.contains(CoreCommonConstants.MGMT_URI)) { + // Only the local System Operator can use these methods + checkIfLocalSystemOperator(clientCN, cloudCN, requestTarget); + } + } +} diff --git a/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/security/CASecurityConfig.java b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/security/CASecurityConfig.java new file mode 100644 index 000000000..5f129c51d --- /dev/null +++ b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/security/CASecurityConfig.java @@ -0,0 +1,12 @@ +package eu.arrowhead.core.certificate_authority.security; + +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + +import eu.arrowhead.common.security.DefaultSecurityConfig; + +@Configuration +@EnableWebSecurity +public class CASecurityConfig extends DefaultSecurityConfig { + +} \ No newline at end of file diff --git a/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/swagger/CASwaggerConfig.java b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/swagger/CASwaggerConfig.java new file mode 100644 index 000000000..ae0b4321e --- /dev/null +++ b/certificate-authority/src/main/java/eu/arrowhead/core/certificate_authority/swagger/CASwaggerConfig.java @@ -0,0 +1,28 @@ +package eu.arrowhead.core.certificate_authority.swagger; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.swagger.DefaultSwaggerConfig; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@EnableSwagger2 +@Configuration +public class CASwaggerConfig extends DefaultSwaggerConfig { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public CASwaggerConfig() { + super(CommonConstants.CORE_SYSTEM_CERTIFICATE_AUTHORITY); + } + + //------------------------------------------------------------------------------------------------- + @Bean + public Docket customizeSwagger() { + return configureSwaggerForCoreSystem(this.getClass().getPackageName()); + } +} \ No newline at end of file diff --git a/certificate-authority/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/certificate-authority/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..af4455de4 --- /dev/null +++ b/certificate-authority/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,47 @@ +{"properties": [ + { + "name": "ping_scheduled", + "type": "java.lang.Boolean", + "description": "A description for 'ping_scheduled'" + }, + { + "name": "ping_timeout", + "type": "java.lang.Long", + "description": "A description for 'ping_timeout'" + }, + { + "name": "ping_interval", + "type": "java.lang.Long", + "description": "A description for 'ping_interval'" + }, + { + "name": "ttl_scheduled", + "type": "java.lang.Boolean", + "description": "A description for 'ttl_scheduled'" + }, + { + "name": "ttl_interval", + "type": "java.lang.Long", + "description": "A description for 'ttl_interval'" + }, + { + "name": "disable.hostname.verifier", + "type": "java.lang.Boolean", + "description": "A description for 'disable.hostname.verifier'" + }, + { + "name": "log_all_request_and_response", + "type": "java.lang.Boolean", + "description": "A description for 'log_all_request_and_response'" + }, + { + "name": "use_strict_service_intf_name_verifier", + "type": "java.lang.Boolean", + "description": "A description for 'use_strict_service_intf_name_verifier'" + }, + { + "name": "core_system_name", + "type": "java.lang.String", + "description": "A description for 'core_system_name'" + } +]} \ No newline at end of file diff --git a/certificate-authority/src/main/resources/application.properties b/certificate-authority/src/main/resources/application.properties new file mode 100644 index 000000000..93f325bd4 --- /dev/null +++ b/certificate-authority/src/main/resources/application.properties @@ -0,0 +1,59 @@ +############################################ +### APPLICATION PARAMETERS ### +############################################ + +# Database connection (mandatory) +# Change the server timezone if neccessary +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/arrowhead?serverTimezone=Europe/Budapest +spring.datasource.username=certificate_authority +spring.datasource.password=FsdG6Kgf9QpPfv2 +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +# use true only for debugging +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.hibernate.ddl-auto=none + +# Certificate Authority web-server parameters +server.address=127.0.0.1 +server.port=8448 +domain.name=127.0.0.1 +domain.port=8448 + +############################################ +### CUSTOM PARAMETERS ### +############################################ + +# Name of the core system +core_system_name=certificate_authority + +# Show all request/response in debug log +log_all_request_and_response=false + +# Service Registry web-server parameters (to register the Certificate-Authority services) +sr_address=127.0.0.1 +sr_port=8443 + +############################################ +### SECURE MODE ### +############################################ + +# configure secure mode + +# Set this to false to disable https mode +server.ssl.enabled=true + +server.ssl.key-store-type=PKCS12 +server.ssl.key-store=classpath:certificates/certificate_authority.p12 +server.ssl.key-store-password=123456 +server.ssl.key-alias=certificate_authority +server.ssl.key-password=123456 +server.ssl.client-auth=need +server.ssl.trust-store-type=PKCS12 +server.ssl.trust-store=classpath:certificates/truststore.p12 +server.ssl.trust-store-password=123456 + +#If true, http client does not check whether the hostname is match one of the server's SAN in its certificate +#Just for testing, DO NOT USE this feature in production environment +disable.hostname.verifier=false diff --git a/certificate-authority/src/main/resources/certificates/certificate_authority.p12 b/certificate-authority/src/main/resources/certificates/certificate_authority.p12 new file mode 100644 index 000000000..57fba65b4 Binary files /dev/null and b/certificate-authority/src/main/resources/certificates/certificate_authority.p12 differ diff --git a/certificate-authority/src/main/resources/certificates/truststore.p12 b/certificate-authority/src/main/resources/certificates/truststore.p12 new file mode 100644 index 000000000..57c1c5f43 Binary files /dev/null and b/certificate-authority/src/main/resources/certificates/truststore.p12 differ diff --git a/certificate-authority/src/main/resources/log4j2.xml b/certificate-authority/src/main/resources/log4j2.xml new file mode 100644 index 000000000..fcce0981a --- /dev/null +++ b/certificate-authority/src/main/resources/log4j2.xml @@ -0,0 +1,46 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex + + INFO + INFO + . + + + + + + + + ${LOG_PATTERN} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/certificate-authority/src/main/resources/swagger/swagger-ui.html b/certificate-authority/src/main/resources/swagger/swagger-ui.html new file mode 100644 index 000000000..4dec726e9 --- /dev/null +++ b/certificate-authority/src/main/resources/swagger/swagger-ui.html @@ -0,0 +1,75 @@ + + + + + + Certificate Authority + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/certificate-authority/src/test/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityControllerTest.java b/certificate-authority/src/test/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityControllerTest.java new file mode 100644 index 000000000..dda6e9b0b --- /dev/null +++ b/certificate-authority/src/test/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityControllerTest.java @@ -0,0 +1,207 @@ +package eu.arrowhead.core.certificate_authority; + +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.x509; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.head; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.io.ClassPathResource; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import eu.arrowhead.common.dto.internal.CertificateSigningRequestDTO; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = CertificateAuthorityMain.class) +@AutoConfigureMockMvc +public class CertificateAuthorityControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void testEchoWithoutCert() throws Exception { + mockMvc.perform(get("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/certificate-authority/echo") + .secure(true)) + .andExpect(status().isUnauthorized()); + } + + @Test + public void testEchoWithInvalidCert() throws Exception { + mockMvc.perform(get("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/certificate-authority/echo") + .secure(true) + .with(x509("certificates/notvalid.pem"))) + .andExpect(status().isUnauthorized()); + } + + @Test + public void testEchoWithValidCert() throws Exception { + mockMvc.perform(get("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/certificate-authority/echo") + .secure(true) + .with(x509("certificates/valid.pem"))) + .andExpect(status().isOk()); + } + + @Test + public void testGetCloudCommonNameWithoutCert() throws Exception { + mockMvc.perform(get("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/certificate-authority/name") + .secure(true)) + .andExpect(status().isUnauthorized()); + } + + @Test + public void testGetCloudCommonNameWithInvalidCert() throws Exception { + mockMvc.perform(get("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/certificate-authority/name") + .secure(true) + .with(x509("certificates/notvalid.pem"))) + .andExpect(status().isUnauthorized()); + } + + @Test + public void testGetCloudCommonNameWithValidCert() throws Exception { + mockMvc.perform(get("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/certificate-authority/name") + .secure(true) + .with(x509("certificates/valid.pem"))) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_PLAIN)) + .andExpect(content().string("testcloud2.aitia.arrowhead.eu")); + } + + @Test + public void testSignWithoutCert() throws Exception { + mockMvc.perform(post("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/certificate-authority/sign") + .secure(true)) + .andExpect(status().isUnauthorized()); + } + + @Test + public void testSignWithInvalidCert() throws Exception { + mockMvc.perform(post("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/certificate-authority/sign") + .secure(true) + .with(x509("certificates/notvalid.pem"))) + .andExpect(status().isUnauthorized()); + } + + @Test + public void testSignGet() throws Exception { + mockMvc.perform(get("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/certificate-authority/sign") + .secure(true) + .with(x509("certificates/valid.pem"))) + .andExpect(status().isMethodNotAllowed()); + } + + @Test + public void testSignPut() throws Exception { + mockMvc.perform(put("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/certificate-authority/sign") + .secure(true) + .with(x509("certificates/valid.pem"))) + .andExpect(status().isMethodNotAllowed()); + } + + @Test + public void testSignPatch() throws Exception { + mockMvc.perform(patch("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/certificate-authority/sign") + .secure(true) + .with(x509("certificates/valid.pem"))) + .andExpect(status().isMethodNotAllowed()); + } + + @Test + public void testSignDelete() throws Exception { + mockMvc.perform(delete("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/certificate-authority/sign") + .secure(true) + .with(x509("certificates/valid.pem"))) + .andExpect(status().isMethodNotAllowed()); + } + + @Test + public void testSignHead() throws Exception { + mockMvc.perform(head("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/certificate-authority/sign") + .secure(true) + .with(x509("certificates/valid.pem"))) + .andExpect(status().isMethodNotAllowed()); + } + + @Test + public void testSignOptions() throws Exception { + mockMvc.perform(options("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/certificate-authority/sign") + .secure(true) + .with(x509("certificates/valid.pem"))) + .andExpect(status().isOk()); + } + + @Test + public void testSignPostInvalidContentType() throws Exception { + mockMvc.perform(post("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/certificate-authority/sign") + .secure(true) + .with(x509("certificates/valid.pem"))) + .andExpect(status().isUnsupportedMediaType()); + } + + @Test + public void testSignPostWithNullCSR() throws Exception { + mockMvc.perform(post("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/certificate-authority/sign") + .secure(true) + .with(x509("certificates/valid.pem")) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .content(asJsonString(new CertificateSigningRequestDTO(null)))) + .andExpect(status().isBadRequest()); + } + + @Test + public void testSignPostWithInvalidCSR() throws Exception { + mockMvc.perform(post("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/certificate-authority/sign") + .secure(true) + .with(x509("certificates/valid.pem")) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .content(asJsonString(new CertificateSigningRequestDTO("INVALID")))) + .andExpect(status().isBadRequest()); + } + + @Test + public void testSignPostWithValidCSR() throws Exception { + mockMvc.perform(post("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/certificate-authority/sign") + .secure(true) + .with(x509("certificates/valid.pem")) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON) + .content(asJsonString(new CertificateSigningRequestDTO(getResourceContent("certificates/valid.csr"))))) + .andExpect(status().isOk()) + .andExpect(content().contentTypeCompatibleWith(MediaType.APPLICATION_JSON)) + .andExpect(jsonPath("$.certificateChain").isArray()); + } + + private static String asJsonString(final Object obj) { + try { + return new ObjectMapper().writeValueAsString(obj); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + private static String getResourceContent(String resourcePath) throws IOException { + File resource = new ClassPathResource(resourcePath).getFile(); + return new String(Files.readAllBytes(resource.toPath())).trim(); + } +} diff --git a/certificate-authority/src/test/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityUtilsTest.java b/certificate-authority/src/test/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityUtilsTest.java new file mode 100644 index 000000000..a11fe32a8 --- /dev/null +++ b/certificate-authority/src/test/java/eu/arrowhead/core/certificate_authority/CertificateAuthorityUtilsTest.java @@ -0,0 +1,94 @@ +package eu.arrowhead.core.certificate_authority; + +import static org.junit.Assert.assertNotNull; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.Base64; +import java.util.ServiceConfigurationError; + +import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequest; +import org.hamcrest.core.IsInstanceOf; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.junit.runner.RunWith; +import org.springframework.core.io.ClassPathResource; +import org.springframework.test.context.junit4.SpringRunner; + +import eu.arrowhead.common.dto.internal.CertificateSigningRequestDTO; +import eu.arrowhead.common.exception.AuthException; +import eu.arrowhead.common.exception.BadPayloadException; +import eu.arrowhead.common.exception.DataNotFoundException; + +@RunWith(SpringRunner.class) +public class CertificateAuthorityUtilsTest { + + @Rule + public ExpectedException thrownException = ExpectedException.none(); + + @Test(expected = BadPayloadException.class) + public void testDecodePKCS10CSRNull() { + CertificateAuthorityUtils.decodePKCS10CSR(null); + } + + @Test(expected = BadPayloadException.class) + public void testDecodePKCS10CSREmpty() { + CertificateAuthorityUtils.decodePKCS10CSR(new CertificateSigningRequestDTO()); + } + + @Test(expected = BadPayloadException.class) + public void testDecodePKCS10CSRInvalidString() { + CertificateAuthorityUtils.decodePKCS10CSR(new CertificateSigningRequestDTO("Invalid CSR String")); + } + + @Test + public void testEncodeCertificateNull() { + thrownException.expect(IsInstanceOf.instanceOf(AuthException.class)); + thrownException.expectCause(IsInstanceOf.instanceOf(NullPointerException.class)); + CertificateAuthorityUtils.encodeCertificate(null); + } + + @Test(expected = ServiceConfigurationError.class) + public void testGetCloudCommonNameNullCert() { + CertificateAuthorityUtils.getCloudCommonName(null); + } + + @Test(expected = BadPayloadException.class) + public void testCheckCommonNameNullCSR() { + CertificateAuthorityUtils.checkCommonName(null, "cloudCN"); + } + + @Test(expected = BadPayloadException.class) + public void testCheckCommonNameNullCloudCN() throws NullPointerException, IOException { + final JcaPKCS10CertificationRequest csr = getResourceCSR("certificates/valid.csr"); + assertNotNull(csr); + CertificateAuthorityUtils.checkCommonName(csr, null); + } + + @Test(expected = BadPayloadException.class) + public void testCheckCsrSignatureNull() { + CertificateAuthorityUtils.checkCsrSignature(null); + } + + @Test + public void testGetClientKeyNull() { + thrownException.expect(DataNotFoundException.class); + thrownException.expectCause(IsInstanceOf.instanceOf(NullPointerException.class)); + CertificateAuthorityUtils.getClientKey(null); + } + + private static String getResourceContentAsString(final String resourcePath) throws IOException { + final File resource = new ClassPathResource(resourcePath).getFile(); + return new String(Files.readAllBytes(resource.toPath())).trim(); + } + + private static JcaPKCS10CertificationRequest getResourceCSR( + final String resourcePath) + throws IOException, NullPointerException { + final String resourceBytes = getResourceContentAsString(resourcePath); + final byte[] csrBytes = Base64.getDecoder().decode(resourceBytes); + return new JcaPKCS10CertificationRequest(csrBytes); + } +} diff --git a/certificate-authority/src/test/java/eu/arrowhead/core/certificate_authority/StandaloneModeInCertificateAuthorityTests.java b/certificate-authority/src/test/java/eu/arrowhead/core/certificate_authority/StandaloneModeInCertificateAuthorityTests.java new file mode 100644 index 000000000..552432eb5 --- /dev/null +++ b/certificate-authority/src/test/java/eu/arrowhead/core/certificate_authority/StandaloneModeInCertificateAuthorityTests.java @@ -0,0 +1,10 @@ +package eu.arrowhead.core.certificate_authority; + +import org.springframework.stereotype.Component; + +import eu.arrowhead.common.testhelper.StandaloneModeInTests; + +@Component +public class StandaloneModeInCertificateAuthorityTests extends StandaloneModeInTests { + +} \ No newline at end of file diff --git a/certificate-authority/src/test/resources/banner.txt b/certificate-authority/src/test/resources/banner.txt new file mode 100644 index 000000000..e69de29bb diff --git a/certificate-authority/src/test/resources/certificates/notvalid.pem b/certificate-authority/src/test/resources/certificates/notvalid.pem new file mode 100644 index 000000000..a70c46837 --- /dev/null +++ b/certificate-authority/src/test/resources/certificates/notvalid.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMzCCAhugAwIBAgIEXNlw3zANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxh +cnJvd2hlYWQuZXUwHhcNMTkwNTEzMTMyNzU5WhcNMjkwNTEzMTMyNzU5WjAoMSYw +JAYDVQQDDB10ZXN0Y2xvdWQxLmFpdGlhLmFycm93aGVhZC5ldTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANTIWrd0mcvxx6LfPG6RvviN5VY1n9uphoYm +CoRA47scc0duc6kIWsIydEsKD9xEd2WdClbQXVazLSF+OWGocxBuyPaAjgu4DdVY +pJLgAaeSzbcjqS+A6bB3B6i8A9RxCWwtDJ5EJsUuIOa9yqcfkmdXVOHpNlwycPeH +FEOIUdUcd+RAL0Fw4h39a3HmTDf4nb2Px/3CWvZk89woxDXURJfyDl2fJyB3kLbp +4HWBht9YZNw2ZuIT1fO5rfm2XGEaPiUseI4KEwDyhW36HWOxv3oP9lMWjCaeWFg1 +A4q6sbjm+fsEsZJavgPWANINCTxKyy/IclwmxKimS6aDBHHyW6UCAwEAAaN2MHQw +DwYDVR0TBAgwBgEB/wIBAjBCBgNVHSMEOzA5gBSaipkeMUwesuYttprtxx4xyt07 +/qEbpBkwFzEVMBMGA1UEAwwMYXJyb3doZWFkLmV1ggRc1T6tMB0GA1UdDgQWBBT0 +jA9ICBgevPSr86oEvVJ8uDamJTANBgkqhkiG9w0BAQsFAAOCAQEAiy1OVJulFL2V +HOYlERD2MJCgIaVKoN6GGxGXQ7mBAjGE+am+dKvbGZ9l5ADRKxKgd1T0hklfTZJU +j7CHBp1JJ7cj7OkFyountQcdTJ3WVLDMxfRRictRwuEUaKMry4nmcU2WpDTJ+DSV +H6qW3VlXxJKnGe1M3u14wUx5k0iXr4S2oYkq/WZ9TUkLWKmzVPDlU3x6iSsyZj/5 +1a5o2qNceezzpGhcvoiHwQ0MFm9OLDYrh61Zb4M7jhn2AocHV4f3Y0P0IfdLlXq5 +MIgOK1ds2BekemekJ3VnW/TDj8fY6sxWl8aWFYJ1RhmVWTODiN9xu9XPyzAO5ryk +zG4AOQa5rQ== +-----END CERTIFICATE----- diff --git a/certificate-authority/src/test/resources/certificates/valid.csr b/certificate-authority/src/test/resources/certificates/valid.csr new file mode 100644 index 000000000..d1d8fc393 --- /dev/null +++ b/certificate-authority/src/test/resources/certificates/valid.csr @@ -0,0 +1 @@ +MIIDKTCCAhECAQAwTDEPMA0GA1UECgwGZWlsYWJzMQswCQYDVQQGEwJodTEsMCoGA1UEAwwjc3lzb3AudGVzdGNsb3VkMi5haXRpYS5hcnJvd2hlYWQuZXUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCgKgJZOMH5QiLxYLz6bKcDAOkLvh13EIVG3W6CdNJpbYcYljnuZlGZ+38A+HLsL4fJfLOPvsrpMKSv2NfEDKSuQaHJt0nchM26WiVkiYfZXPxYduZy9wqi1069V7E2i7vYsqJEytugjEhEk+1O1rtFuGZXIitNUSUBUNYWNkc/sr3wCGgZrcAOnTFuHSorUGm4Kc8qbrgNtjnbPCvnyZJp7IvsyAT51bBYfH2vhf9Yjv/apAiKjwNO/Hfo8cYq6u3CnFpXSj6BD5DVhwPWZ9IenfG1hACdldEsiNoN3ssZYwbuPcduq6SSNOHIqtQIp+spdAUi0FQnnw8kmryxPGgvAgMBAAGggZcwFAYJKoZIhvcNAQkHMQcMBTI0NTM0MBUGCSqGSIb3DQEJAjEIDAZlaWxhYnMwaAYJKoZIhvcNAQkOMVswWTAPBgNVHREECDAGhwR/AAABMCcGA1UdIwQgMB6AFAQwTQgjkz3eZj0WWqfRyV4jppdPoQCCBFzZYhkwHQYDVR0OBBYEFAVG6MVZFFyHQXW6qlQWA4EfXWSIMA0GCSqGSIb3DQEBCwUAA4IBAQAkRvc+/O/GWx3dg6CgnpWSCFZKnaaD1l+1Rls93qZZ3jP1tukK+7xh+1AcRNnB5h5tNW0Zaa7KrYIS/RX2wsqGRIil4iTmGaa2/MPFY3GAm65891JuF4t0dk/5GcOJjZOAEV603ils9qxZ1np3asQRGiFAXbvL1tr+2iaQR2olfsn00qSw+zYICKPtBAJhUcmxavMrlZPoiCiJzWqQZMNOlYzJitim8N8rMwKZnwmDdgqgjkVrIQXKVh3Q2xw2mGlqPIRToLSgnGtLQ5caNVhBeF1OnfBxziP8SVckazTSlJ8uVm8an6Jt2R6VQf1avuclAxWAwS8CyAn5TpJNzVjL diff --git a/certificate-authority/src/test/resources/certificates/valid.pem b/certificate-authority/src/test/resources/certificates/valid.pem new file mode 100644 index 000000000..56eae293d --- /dev/null +++ b/certificate-authority/src/test/resources/certificates/valid.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDLzCCAhegAwIBAgIEXPYrATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB10 +ZXN0Y2xvdWQyLmFpdGlhLmFycm93aGVhZC5ldTAeFw0xOTA2MDQwODI1MzdaFw0y +MDA2MDMwODI1MzdaMC4xLDAqBgNVBAMMI3N5c29wLnRlc3RjbG91ZDIuYWl0aWEu +YXJyb3doZWFkLmV1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoCoC +WTjB+UIi8WC8+mynAwDpC74ddxCFRt1ugnTSaW2HGJY57mZRmft/APhy7C+HyXyz +j77K6TCkr9jXxAykrkGhybdJ3ITNulolZImH2Vz8WHbmcvcKotdOvVexNou72LKi +RMrboIxIRJPtTta7RbhmVyIrTVElAVDWFjZHP7K98AhoGa3ADp0xbh0qK1BpuCnP +Km64DbY52zwr58mSaeyL7MgE+dWwWHx9r4X/WI7/2qQIio8DTvx36PHGKurtwpxa +V0o+gQ+Q1YcD1mfSHp3xtYQAnZXRLIjaDd7LGWMG7j3HbqukkjThyKrUCKfrKXQF +ItBUJ58PJJq8sTxoLwIDAQABo1swWTAPBgNVHREECDAGhwR/AAABMCcGA1UdIwQg +MB6AFAQwTQgjkz3eZj0WWqfRyV4jppdPoQCCBFzZYhkwHQYDVR0OBBYEFAVG6MVZ +FFyHQXW6qlQWA4EfXWSIMA0GCSqGSIb3DQEBCwUAA4IBAQBUEExzkf2bH4fF/tyP +r7DxO94aqQOySGJq/25DzfZQOpuK5Ud3MPpXSlxYw+MB5rRDJu0NzGUX+ha4mG3T +dXxd3X2QaDFR0SYUD4J0hTtmYp9TzgCXnU+J7t6sku/LYFJrCl5m4o124ShZXBgR +Dj/gDVd4C6InTPhpIPHaD6D97wKyObbC3V1dGiVs5Z5/+wUJdUFUmnfAb1rbX0nV +0TTKluWTtRT4cjBeIFs7MZiThMx8bgSE4mZIC1ry4PikjAap/oEIQVxbBTbl+5q8 +xhPbPn+JhZwQp39a1oPMEQog0wQhtKvZrYx//H1o3mzRo1ZFzL+R/LCKKElMPMXx +UHKC +-----END CERTIFICATE----- diff --git a/certificate-authority/src/test/resources/log4j2.xml b/certificate-authority/src/test/resources/log4j2.xml new file mode 100644 index 000000000..931cbfebb --- /dev/null +++ b/certificate-authority/src/test/resources/log4j2.xml @@ -0,0 +1,49 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex + + OFF + OFF + + + + + + + + ${LOG_PATTERN} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/certificates/testcloud2/device_registry.p12 b/certificates/testcloud2/device_registry.p12 new file mode 100644 index 000000000..dcd55a150 Binary files /dev/null and b/certificates/testcloud2/device_registry.p12 differ diff --git a/certificates/testcloud2/onboarding_controller.p12 b/certificates/testcloud2/onboarding_controller.p12 new file mode 100644 index 000000000..cbfcb32b1 Binary files /dev/null and b/certificates/testcloud2/onboarding_controller.p12 differ diff --git a/certificates/testcloud2/qos_monitor.p12 b/certificates/testcloud2/qos_monitor.p12 new file mode 100644 index 000000000..86c68f35b Binary files /dev/null and b/certificates/testcloud2/qos_monitor.p12 differ diff --git a/certificates/testcloud2/system_registry.p12 b/certificates/testcloud2/system_registry.p12 new file mode 100644 index 000000000..1e913c7ae Binary files /dev/null and b/certificates/testcloud2/system_registry.p12 differ diff --git a/choreographer/.classpath b/choreographer/.classpath index 01997bb0d..e210343c4 100644 --- a/choreographer/.classpath +++ b/choreographer/.classpath @@ -45,5 +45,19 @@
+ + + + + + + + + + + + + + diff --git a/choreographer/src/main/java/eu/arrowhead/core/choreographer/ChoreographerController.java b/choreographer/src/main/java/eu/arrowhead/core/choreographer/ChoreographerController.java index 0bc785e7b..6882f14e3 100644 --- a/choreographer/src/main/java/eu/arrowhead/core/choreographer/ChoreographerController.java +++ b/choreographer/src/main/java/eu/arrowhead/core/choreographer/ChoreographerController.java @@ -162,7 +162,7 @@ public void removeActionPlanById(@PathVariable(value = PATH_VARIABLE_ID) final l final ValidatedPageParams validatedPageParams = CoreUtilities.validatePageParameters(page, size, direction, sortField); final List choreographerActionPlanEntriesResponse = choreographerDBService.getChoreographerActionPlanEntriesResponse(validatedPageParams.getValidatedPage(), validatedPageParams.getValidatedSize(), - validatedPageParams.getValidatedDirecion(), + validatedPageParams.getValidatedDirection(), sortField); logger.debug("ChoreographerActionPlans with page: {} and item_per page: {} retrieved successfully", page, size); diff --git a/core-common/.classpath b/core-common/.classpath index 779e9464e..660114540 100644 --- a/core-common/.classpath +++ b/core-common/.classpath @@ -40,5 +40,19 @@ + + + + + + + + + + + + + + diff --git a/core-common/pom.xml b/core-common/pom.xml index 1e5d966f4..ec10307f3 100644 --- a/core-common/pom.xml +++ b/core-common/pom.xml @@ -1,6 +1,6 @@ 4.0.0 - + eu.arrowhead core ${revision} @@ -14,8 +14,17 @@ core-client-skeleton - - + + + + org.bouncycastle + bcpkix-jdk15on + 1.64 + compile + + + + src/main/java diff --git a/core-common/src/deb/ahconf.sh b/core-common/src/deb/ahconf.sh index 1242632b7..0b2ea2cb3 100644 --- a/core-common/src/deb/ahconf.sh +++ b/core-common/src/deb/ahconf.sh @@ -190,6 +190,23 @@ ah_ip_valid () { fi } +ah_subject_alternative_names() { + host=${1} + ip=${2} + + san="IP:127.0.0.1,DNS:localhost,DNS:${host},IP:${ip}" + + if [ ! -z ${AH_DOMAIN_NAME} ]; then + if ah_ip_valid ${AH_DOMAIN_NAME}; then + san=${san},IP:${AH_DOMAIN_NAME} + else + san=${san},DNS:${AH_DOMAIN_NAME} + fi + fi + + return san +} + ah_cert_signed_system () { name=${1} passwd=${2} @@ -218,15 +235,7 @@ ah_cert_signed_system () { src_file="${AH_CLOUDS_DIR}/${AH_CLOUD_NAME}.p12" if [ ! -f "${file}" ]; then - san="IP:127.0.0.1,DNS:localhost,DNS:${host},IP:${ip}" - - if [ ! -z ${AH_DOMAIN_NAME} ]; then - if ah_ip_valid ${AH_DOMAIN_NAME}; then - san=${san},IP:${AH_DOMAIN_NAME} - else - san=${san},DNS:${AH_DOMAIN_NAME} - fi - fi + san=ah_subject_alternative_names ${host} ${ip} ah_cert ${path} ${name} "${name}.${AH_CLOUD_NAME}.${AH_OPERATOR}.arrowhead.eu" ${passwd} @@ -266,6 +275,94 @@ ah_cert_signed_system () { fi } +# Create the keystore for the CA system +# Apart from being a regular Arrowhead compliant system keystore, +# it also has to contain the private key of the cloud +ah_ca_keystore () { + ca_sys_name=${1} # name of the CA system + host=${2} # hostname of the CA system (default: `hostname`) + ip=${3} # IP address of the CA system (default: $OWN_IP) + cloud_keystore=${4} # path of the cloud keystore (default: "${AH_CLOUDS_DIR}/${AH_CLOUD_NAME}.p12") + ca_password=${5} # password used in the CA keystore (default: $AH_PASS_CERT) + cloud_password=${6} # password used in the cloud keystore (default: $AH_PASS_CERT) + cloud_alias_src=${7} # cloud cert alias in the cloud keystore (default: $AH_CLOUD_NAME) + cloud_alias_dst=${8} # cloud cert alias in the CA keystore (default: $AH_CLOUD_NAME) + + if [ -z ${host} ]; then + host=`hostname` + fi + + if [ -z ${ip} ]; then + ip=${OWN_IP} + fi + + if [ -z ${cloud_keystore} ]; then + cloud_keystore="${AH_CLOUDS_DIR}/${AH_CLOUD_NAME}.p12" + fi + + if [ -z ${ca_password} ]; then + ca_password=${AH_PASS_CERT} + fi + + if [ -z ${cloud_password} ]; then + cloud_password=${ca_password} + fi + + if [ -z ${cloud_alias_src} ]; then + cloud_alias_src=${AH_CLOUD_NAME} + fi + + if [ -z ${cloud_alias_dst} ]; then + cloud_alias_dst=${cloud_alias_src} + fi + + ca_sys_dir="${AH_SYSTEMS_DIR}/${ca_sys_name}" + ca_keystore="${ca_sys_dir}/${ca_sys_name}.p12" + + if [ ! -f "${ca_keystore}" ]; then + san=ah_subject_alternative_names ${host} ${ip} + + # generate CA system keypair + ah_cert ${ca_sys_dir} ${ca_sys_name} "${ca_sys_name}.${AH_CLOUD_NAME}.${AH_OPERATOR}.arrowhead.eu" ${ca_password} + + # import cloud keypair + # this is necessary, because CA signs system certificates with the cloud cert + keytool -importkeystore \ + -srckeypass ${cloud_password} \ + -srcstorepass ${cloud_password} \ + -destkeypass ${ca_password} \ + -deststorepass ${ca_password} \ + -srcalias ${cloud_alias_src} \ + -destalias ${cloud_alias_dst} \ + -srckeystore "${cloud_keystore}" \ + -destkeystore "${ca_keystore}" \ + -deststoretype PKCS12 + + # sign CA system cert with the cloud cert + keytool -certreq \ + -alias ${ca_sys_name} \ + -keypass ${ca_password} \ + -keystore "${ca_keystore}" \ + -storepass ${ca_password} \ + | keytool -gencert \ + -alias ${cloud_alias_dst} \ + -keypass ${ca_password} \ + -keystore "${ca_keystore}" \ + -storepass ${ca_password} \ + -validity 3650 \ + -ext SubjectAlternativeName=${san} \ + | keytool -importcert \ + -alias ${ca_sys_name} \ + -keypass ${ca_password} \ + -keystore "${ca_keystore}" \ + -storepass ${ca_password} \ + -noprompt + + # import root certificate + ah_cert_import "${AH_CONF_DIR}" "master" "${ca_sys_dir}" ${ca_sys_name} ${ca_password} + fi +} + ah_cert_trust () { dst_path=${1} src_path=${2} @@ -359,4 +456,4 @@ ah_transform_log_file () { rm ${log_path}/log4j2.xml.orig chown :arrowhead ${log_path}/log4j2.xml chmod 640 ${log_path}/log4j2.xml -} \ No newline at end of file +} diff --git a/core-common/src/deb/control/templates b/core-common/src/deb/control/templates index 83b24eab3..a7b3ab39e 100644 --- a/core-common/src/deb/control/templates +++ b/core-common/src/deb/control/templates @@ -76,6 +76,11 @@ Type: password Default: Description: MySQL password for Event Handler system (leave empty for random). +Template: arrowhead-core-common/mysql_password_qos +Type: password +Default: +Description: MySQL password for Qos Monitor system (leave empty for random). + Template: arrowhead-core-common/mysql_password_gk Type: password Default: @@ -96,6 +101,26 @@ Type: password Default: Description: MySQL password for Service Registry system (leave empty for random). +Template: arrowhead-core-common/mysql_password_sysr +Type: password +Default: +Description: MySQL password for System Registry system (leave empty for random). + +Template: arrowhead-core-common/mysql_password_dr +Type: password +Default: +Description: MySQL password for Device Registry system (leave empty for random). + +Template: arrowhead-core-common/mysql_password_onboarding +Type: password +Default: +Description: MySQL password for Onboarding Controller system (leave empty for random). + +Template: arrowhead-core-common/mysql_password_ca +Type: password +Default: +Description: MySQL password for Certificate Authority system (leave empty for random). + Template: arrowhead-core-common/sr_host Type: string Description: Enter the hostname or IP address of the Service Registry (leave empty if the SR on the same computer than the system) diff --git a/core-common/src/main/java/eu/arrowhead/common/ApplicationConfiguration.java b/core-common/src/main/java/eu/arrowhead/common/ApplicationConfiguration.java new file mode 100644 index 000000000..0c1afb1a6 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/ApplicationConfiguration.java @@ -0,0 +1,18 @@ +package eu.arrowhead.common; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +@Configuration +public class ApplicationConfiguration { + + //------------------------------------------------------------------------------------------------- + @Bean(CommonConstants.ARROWHEAD_CONTEXT) + public Map getArrowheadContext() { + return new ConcurrentHashMap<>(); + } + +} diff --git a/core-common/src/main/java/eu/arrowhead/common/ApplicationInitListener.java b/core-common/src/main/java/eu/arrowhead/common/ApplicationInitListener.java index be8b61a76..470313077 100644 --- a/core-common/src/main/java/eu/arrowhead/common/ApplicationInitListener.java +++ b/core-common/src/main/java/eu/arrowhead/common/ApplicationInitListener.java @@ -125,12 +125,6 @@ public void destroy() throws InterruptedException { customDestroy(); } - //------------------------------------------------------------------------------------------------- - @Bean(CommonConstants.ARROWHEAD_CONTEXT) - public Map getArrowheadContext() { - return new ConcurrentHashMap<>(); - } - //================================================================================================= // assistant methods @@ -187,12 +181,15 @@ private void obtainKeys(final KeyStore keyStore, final ApplicationContext appCon logger.debug("obtainKeys started..."); @SuppressWarnings("unchecked") final Map context = appContext.getBean(CommonConstants.ARROWHEAD_CONTEXT, Map.class); - - publicKey = Utilities.getFirstCertFromKeyStore(keyStore).getPublicKey(); + + final X509Certificate serverCertificate = Utilities.getFirstCertFromKeyStore(keyStore); + publicKey = serverCertificate.getPublicKey(); context.put(CommonConstants.SERVER_PUBLIC_KEY, publicKey); - + final PrivateKey privateKey = Utilities.getPrivateKey(keyStore, sslProperties.getKeyPassword()); context.put(CommonConstants.SERVER_PRIVATE_KEY, privateKey); + + context.put(CommonConstants.SERVER_CERTIFICATE, serverCertificate); } //------------------------------------------------------------------------------------------------- @@ -219,7 +216,7 @@ private void registerCoreSystemServicesToServiceRegistry(final ApplicationContex final ServiceQueryFormDTO queryForm = new ServiceQueryFormDTO.Builder(coreService.getServiceDefinition()).build(); final ResponseEntity queryResponse = httpService.sendRequest(queryUri, HttpMethod.POST, ServiceQueryResultDTO.class, queryForm); - for (final ServiceRegistryResponseDTO result : queryResponse.getBody().getServiceQueryData()) { // stucked entries + for (final ServiceRegistryResponseDTO result : queryResponse.getBody().getServiceQueryData()) { // old, possibly obsolete entries final UriComponents unregisterUri = createUnregisterUri(scheme, coreService, result.getProvider().getAddress(), result.getProvider().getPort()); httpService.sendRequest(unregisterUri, HttpMethod.DELETE, Void.class); } diff --git a/core-common/src/main/java/eu/arrowhead/common/CommonConstants.java b/core-common/src/main/java/eu/arrowhead/common/CommonConstants.java index 7ef651842..dd591fab9 100644 --- a/core-common/src/main/java/eu/arrowhead/common/CommonConstants.java +++ b/core-common/src/main/java/eu/arrowhead/common/CommonConstants.java @@ -1,12 +1,11 @@ package eu.arrowhead.common; -import java.util.List; - +import eu.arrowhead.common.core.CoreSystemService; import org.jose4j.jwe.ContentEncryptionAlgorithmIdentifiers; import org.jose4j.jwe.KeyManagementAlgorithmIdentifiers; import org.jose4j.jws.AlgorithmIdentifiers; -import eu.arrowhead.common.core.CoreSystemService; +import java.util.List; public class CommonConstants { @@ -14,15 +13,21 @@ public class CommonConstants { // members public static final String BASE_PACKAGE = "eu.arrowhead"; - + public static final String CORE_SYSTEM_AUTHORIZATION = "Authorization"; + public static final String CORE_SYSTEM_CERTIFICATE_AUTHORITY = "Certificate Authority"; public static final String CORE_SYSTEM_CHOREOGRAPHER = "Choreographer"; public static final String CORE_SYSTEM_EVENT_HANDLER = "Event Handler"; public static final String CORE_SYSTEM_GATEKEEPER = "Gatekeeper"; public static final String CORE_SYSTEM_GATEWAY = "Gateway"; public static final String CORE_SYSTEM_ORCHESTRATOR = "Orchestrator"; public static final String CORE_SYSTEM_SERVICE_REGISTRY = "Service Registry"; - + public static final String CORE_SYSTEM_QOS_MONITOR = "Quality of Service Monitor"; + + public static final String CORE_SYSTEM_SYSTEM_REGISTRY = "System Registry"; + public static final String CORE_SYSTEM_DEVICE_REGISTRY = "Device Registry"; + public static final String CORE_SYSTEM_ONBOARDING = "Onboarding Controller"; + public static final String CORE_SERVICE_AUTH_TOKEN_GENERATION = "token-generation"; public static final String CORE_SERVICE_AUTH_PUBLIC_KEY = "auth-public-key"; public static final String CORE_SERVICE_AUTH_CONTROL_INTRA = "authorization-control-intra"; @@ -41,14 +46,39 @@ public class CommonConstants { public static final String CORE_SERVICE_EVENT_HANDLER_SUBSCRIBE = "event-subscribe"; public static final String CORE_SERVICE_EVENT_HANDLER_UNSUBSCRIBE = "event-unsubscribe"; public static final String CORE_SERVICE_EVENT_HANDLER_PUBLISH_AUTH_UPDATE = "event-publish-auth-update"; - + + + public static final String CORE_SERVICE_CERTIFICATE_AUTHORITY_SIGN = "ca-sign"; + + public static final String CORE_SERVICE_QOS_MONITOR_PING_MEASUREMENT = "qos-monitor-ping-measurement"; + + + public static final String CORE_SERVICE_SERVICE_REGISTRY_REGISTER = "service-register"; + public static final String CORE_SERVICE_SERVICE_REGISTRY_UNREGISTER = "service-unregister"; + + public static final String CORE_SERVICE_SYSTEM_REGISTRY_REGISTER = "system-register"; + public static final String CORE_SERVICE_SYSTEM_REGISTRY_UNREGISTER = "system-unregister"; + public static final String CORE_SERVICE_SYSTEM_REGISTRY_ONBOARDING_WITH_NAME = "system-onboarding-with-name"; + public static final String CORE_SERVICE_SYSTEM_REGISTRY_ONBOARDING_WITH_CSR = "system-onboarding-with-csr"; + + public static final String CORE_SERVICE_DEVICE_REGISTRY_REGISTER = "device-register"; + public static final String CORE_SERVICE_DEVICE_REGISTRY_UNREGISTER = "device-unregister"; + public static final String CORE_SERVICE_DEVICE_REGISTRY_ONBOARDING_WITH_NAME = "device-onboarding-with-name"; + public static final String CORE_SERVICE_DEVICE_REGISTRY_ONBOARDING_WITH_CSR = "device-onboarding-with-csr"; + + public static final String CORE_SERVICE_ONBOARDING_WITH_CERTIFICATE_AND_NAME = "onboarding-with-certificate-and-name"; + public static final String CORE_SERVICE_ONBOARDING_WITH_CERTIFICATE_AND_CSR = "onboarding-with-certificate-and-csr"; + public static final String CORE_SERVICE_ONBOARDING_WITH_SHARED_SECRET_AND_NAME = "onboarding-with-shared-secret-and-name"; + public static final String CORE_SERVICE_ONBOARDING_WITH_SHARED_SECRET_AND_CSR = "onboarding-with-shared-secret-and-csr"; + public static final String COMMON_FIELD_NAME_ID = "id"; public static final String ARROWHEAD_CONTEXT = "arrowheadContext"; public static final String SERVER_COMMON_NAME = "server.common.name"; public static final String SERVER_PUBLIC_KEY = "server.public.key"; public static final String SERVER_PRIVATE_KEY = "server.private.key"; - + public static final String SERVER_CERTIFICATE = "server.certificate"; + public static final String HTTPS = "https"; public static final String HTTP = "http"; public static final String JSON = "JSON"; @@ -62,6 +92,16 @@ public class CommonConstants { public static final String SERVICE_REGISTRY_PORT = "sr_port"; public static final String $SERVICE_REGISTRY_PORT_WD = "${" + SERVICE_REGISTRY_PORT + ":" + Defaults.DEFAULT_SERVICE_REGISTRY_PORT + "}"; + public static final String ONBOARDING_URI = "/onboarding"; + public static final String ONBOARDING_AUTH_WITH_CERTIFICATE_URI = "/certificate"; + public static final String ONBOARDING_AUTH_WITH_SHARED_SECRET_URI = "/sharedsecret"; + public static final String ONBOARDING_WITH_NAME_URI = "/name"; + public static final String ONBOARDING_WITH_CSR_URI = "/csr"; + public static final String OP_ONBOARDING_WITH_CERTIFICATE_AND_NAME = ONBOARDING_AUTH_WITH_CERTIFICATE_URI + ONBOARDING_WITH_NAME_URI; + public static final String OP_ONBOARDING_WITH_CERTIFICATE_AND_CSR = ONBOARDING_AUTH_WITH_CERTIFICATE_URI + ONBOARDING_WITH_CSR_URI; + public static final String OP_ONBOARDING_WITH_SHARED_SECRET_AND_NAME = ONBOARDING_AUTH_WITH_SHARED_SECRET_URI + ONBOARDING_WITH_NAME_URI; + public static final String OP_ONBOARDING_WITH_SHARED_SECRET_AND_CSR = ONBOARDING_AUTH_WITH_SHARED_SECRET_URI + ONBOARDING_WITH_CSR_URI; + public static final String SERVICE_REGISTRY_URI = "/serviceregistry"; public static final String OP_SERVICE_REGISTRY_REGISTER_URI = "/register"; public static final String OP_SERVICE_REGISTRY_UNREGISTER_URI = "/unregister"; @@ -70,25 +110,48 @@ public class CommonConstants { public static final String OP_SERVICE_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_ADDRESS = "address"; public static final String OP_SERVICE_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_PORT = "port"; public static final String OP_SERVICE_REGISTRY_UNREGISTER_REQUEST_PARAM_SERVICE_DEFINITION = "service_definition"; - + + public static final String SYSTEM_REGISTRY_URI = "/systemregistry"; + public static final String OP_SYSTEM_REGISTRY_REGISTER_URI = "/register"; + public static final String OP_SYSTEM_REGISTRY_UNREGISTER_URI = "/unregister"; + public static final String OP_SYSTEM_REGISTRY_QUERY_URI = "/query"; + public static final String OP_SYSTEM_REGISTRY_ONBOARDING_WITH_NAME_URI = ONBOARDING_WITH_NAME_URI; + public static final String OP_SYSTEM_REGISTRY_ONBOARDING_WITH_CSR_URI = ONBOARDING_WITH_CSR_URI; + public static final String OP_SYSTEM_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_SYSTEM_NAME = "system_name"; + public static final String OP_SYSTEM_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_ADDRESS = "address"; + public static final String OP_SYSTEM_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_PORT = "port"; + + public static final String DEVICE_REGISTRY_URI = "/deviceregistry"; + public static final String OP_DEVICE_REGISTRY_REGISTER_URI = "/register"; + public static final String OP_DEVICE_REGISTRY_UNREGISTER_URI = "/unregister"; + public static final String OP_DEVICE_REGISTRY_QUERY_URI = "/query"; + public static final String OP_DEVICE_REGISTRY_ONBOARDING_WITH_NAME_URI = ONBOARDING_WITH_NAME_URI; + public static final String OP_DEVICE_REGISTRY_ONBOARDING_WITH_CSR_URI = ONBOARDING_WITH_CSR_URI; + public static final String OP_DEVICE_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_DEVICE_NAME = "device_name"; + public static final String OP_DEVICE_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_MAC_ADDRESS = "mac_address"; + public static final String AUTHORIZATION_URI = "/authorization"; public static final String OP_AUTH_TOKEN_URI = "/token"; public static final String OP_AUTH_KEY_URI = "/publickey"; public static final String OP_AUTH_INTRA_CHECK_URI = "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/intracloud/check"; public static final String OP_AUTH_INTER_CHECK_URI = "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/intercloud/check"; public static final String OP_AUTH_SUBSCRIPTION_CHECK_URI = "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/subscription/check"; - + + public static final String CERTIFICATE_AUTHRORITY_URI = "/certificate-authority"; + public static final String OP_CA_CLOUD_COMMON_NAME_URI = "/name"; + public static final String OP_CA_SIGN_CERTIFICATE_URI = "/sign"; + public static final String ORCHESTRATOR_URI = "/orchestrator"; public static final String OP_ORCH_PROCESS = "/orchestration"; - public static final String ORCHESTRATON_FLAG_MATCHMAKING = "matchmaking"; - public static final String ORCHESTRATON_FLAG_METADATA_SEARCH = "metadataSearch"; - public static final String ORCHESTRATON_FLAG_ONLY_PREFERRED = "onlyPreferred"; - public static final String ORCHESTRATON_FLAG_PING_PROVIDERS = "pingProviders"; - public static final String ORCHESTRATON_FLAG_OVERRIDE_STORE = "overrideStore"; - public static final String ORCHESTRATON_FLAG_TRIGGER_INTER_CLOUD = "triggerInterCloud"; - public static final String ORCHESTRATON_FLAG_EXTERNAL_SERVICE_REQUEST = "externalServiceRequest"; - public static final String ORCHESTRATON_FLAG_ENABLE_INTER_CLOUD = "enableInterCloud"; - public static final String ORCHESTRATON_FLAG_ENABLE_QOS = "enableQoS"; + public static final String ORCHESTRATION_FLAG_MATCHMAKING = "matchmaking"; + public static final String ORCHESTRATION_FLAG_METADATA_SEARCH = "metadataSearch"; + public static final String ORCHESTRATION_FLAG_ONLY_PREFERRED = "onlyPreferred"; + public static final String ORCHESTRATION_FLAG_PING_PROVIDERS = "pingProviders"; + public static final String ORCHESTRATION_FLAG_OVERRIDE_STORE = "overrideStore"; + public static final String ORCHESTRATION_FLAG_TRIGGER_INTER_CLOUD = "triggerInterCloud"; + public static final String ORCHESTRATION_FLAG_EXTERNAL_SERVICE_REQUEST = "externalServiceRequest"; + public static final String ORCHESTRATION_FLAG_ENABLE_INTER_CLOUD = "enableInterCloud"; + public static final String ORCHESTRATION_FLAG_ENABLE_QOS = "enableQoS"; public static final String GATEKEEPER_URI = "/gatekeeper"; public static final String OP_GATEKEEPER_GSD_SERVICE = "/init_gsd"; @@ -108,6 +171,10 @@ public class CommonConstants { public static final String OP_EVENT_HANDLER_UNSUBSCRIBE = "/unsubscribe"; public static final String OP_EVENT_HANDLER_PUBLISH_AUTH_UPDATE = "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/publish/authupdate"; + public static final String QOS_MONITOR_URI = "/qosmonitor"; + public static final String OP_QOS_MONITOR_PING_MEASUREMENT = "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/ping/measurement"; + public static final String OP_QOS_MONITOR_PING_MEASUREMENT_SUFFIX = "/{" + COMMON_FIELD_NAME_ID + "}"; + public static final String SWAGGER_COMMON_PACKAGE = "eu.arrowhead.common.swagger"; public static final String SWAGGER_UI_URI = "/swagger-ui.html"; public static final String SWAGGER_HTTP_200_MESSAGE = "Core service is available"; @@ -149,6 +216,11 @@ public class CommonConstants { public static final String DISABLE_HOSTNAME_VERIFIER = "disable.hostname.verifier"; public static final String $DISABLE_HOSTNAME_VERIFIER_WD = "${" + DISABLE_HOSTNAME_VERIFIER + ":" + Defaults.DEFAULT_DISABLE_HOSTNAME_VERIFIER + "}"; + public static final String CA_CERT_VALIDITY_NEG_OFFSET_MILLIS = "ca.validity.negative-offest-millis"; + public static final String $CA_CERT_VALIDITY_NEG_OFFSET_MILLIS = "${" + CA_CERT_VALIDITY_NEG_OFFSET_MILLIS + ":" + Defaults.DEFAULT_CA_CERT_VALIDITY_NEG_OFFSET_MILLIS + "}"; + public static final String CA_CERT_VALIDITY_POS_OFFSET_MILLIS = "ca.validity.positive-offest-millis"; + public static final String $CA_CERT_VALIDITY_POS_OFFSET_MILLIS = "${" + CA_CERT_VALIDITY_POS_OFFSET_MILLIS + ":" + Defaults.DEFAULT_CA_CERT_VALIDITY_POS_OFFSET_MILLIS + "}"; + public static final String JWT_CLAIM_CONSUMER_ID = "cid"; public static final String JWT_CLAIM_SERVICE_ID = "sid"; public static final String JWT_CLAIM_INTERFACE_ID = "iid"; @@ -164,6 +236,7 @@ public class CommonConstants { public static final long CONVERSION_MILLISECOND_TO_SECOND = 1000; public static final long CONVERSION_MILLISECOND_TO_MINUTE = 60000; + public static final long CONVERSION_SECOND_TO_MINUTE = 60; public static final String SORT_ORDER_ASCENDING = "ASC"; public static final String SORT_ORDER_DESCENDING = "DESC"; diff --git a/core-common/src/main/java/eu/arrowhead/common/CoreCommonConstants.java b/core-common/src/main/java/eu/arrowhead/common/CoreCommonConstants.java index 02bd3b73d..6a5e76e22 100644 --- a/core-common/src/main/java/eu/arrowhead/common/CoreCommonConstants.java +++ b/core-common/src/main/java/eu/arrowhead/common/CoreCommonConstants.java @@ -21,6 +21,7 @@ public class CoreCommonConstants { public static final String SR_QUERY_URI = "service.registry.query.uri"; public static final String SR_QUERY_BY_SYSTEM_ID_URI = "service.registry.query.by.system.id.uri"; public static final String SR_QUERY_BY_SYSTEM_DTO_URI = "service.registry.query.by.system.dto.uri"; + public static final String SR_QUERY_ALL = "service.registry.query.all.uri"; public static final String REQUIRED_URI_LIST = "required.uri.list"; public static final String URI_SUFFIX = "-uri"; @@ -33,9 +34,16 @@ public class CoreCommonConstants { public static final String SERVER_ERROR_URI = "/error"; public static final String MGMT_URI = "/mgmt"; - + + public static final String OP_DEVICE_REGISTRY_QUERY_BY_DEVICE_ID_URI = "/query/device/{" + COMMON_FIELD_NAME_ID + "}"; + public static final String OP_DEVICE_REGISTRY_QUERY_BY_DEVICE_DTO_URI = "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/query/device"; + + public static final String OP_SYSTEM_REGISTRY_QUERY_BY_SYSTEM_ID_URI = "/query/system/{" + COMMON_FIELD_NAME_ID + "}"; + public static final String OP_SYSTEM_REGISTRY_QUERY_BY_SYSTEM_DTO_URI = "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/query/system"; + public static final String OP_SERVICE_REGISTRY_QUERY_BY_SYSTEM_ID_URI = "/query/system/{" + COMMON_FIELD_NAME_ID + "}"; public static final String OP_SERVICE_REGISTRY_QUERY_BY_SYSTEM_DTO_URI = "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/query/system"; + public static final String OP_SERVICE_REGISTRY_QUERY_ALL_URI = "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/query/all"; public static final String ORCHESTRATOR_STORE_MGMT_URI = "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/mgmt/store"; @@ -48,6 +56,7 @@ public class CoreCommonConstants { public static final String SWAGGER_TAG_MGMT = "Management"; public static final String SWAGGER_TAG_CLIENT = "Client"; public static final String SWAGGER_TAG_PRIVATE = "Private"; + public static final String SWAGGER_TAG_ONBOARDING = "Onboarding"; public static final String SWAGGER_TAG_ALL = "All"; public static final String SERVER_ADDRESS = "server.address"; @@ -88,14 +97,18 @@ public class CoreCommonConstants { public static final String SERVICE_REGISTRY_PING_INTERVAL = "ping_interval"; public static final String $SERVICE_REGISTRY_PING_INTERVAL_WD = "${" + SERVICE_REGISTRY_PING_INTERVAL + ":" + CoreDefaults.DEFAULT_SERVICE_REGISTRY_PING_INTERVAL_MINUTES + "}"; public static final String SERVICE_REGISTRY_PING_TIMEOUT = "ping_timeout"; - public static final String $SERVICE_REGISTRY_PING_TIMEOUT_WD = "${" + SERVICE_REGISTRY_PING_TIMEOUT + ":" + CoreDefaults.DEFAULT_SERVICE_REGISTRY_PING_TIMEOUT_MILISECONDS + "}"; + public static final String $SERVICE_REGISTRY_PING_TIMEOUT_WD = "${" + SERVICE_REGISTRY_PING_TIMEOUT + ":" + CoreDefaults.DEFAULT_SERVICE_REGISTRY_PING_TIMEOUT_MILLISECONDS + "}"; public static final String SERVICE_REGISTRY_TTL_SCHEDULED = "ttl_scheduled"; public static final String $SERVICE_REGISTRY_TTL_SCHEDULED_WD = "${" + SERVICE_REGISTRY_TTL_SCHEDULED + ":" + CoreDefaults.DEFAULT_SERVICE_REGISTRY_TTL_SCHEDULED + "}"; public static final String SERVICE_REGISTRY_TTL_INTERVAL = "ttl_interval"; public static final String $SERVICE_REGISTRY_TTL_INTERVAL_WD = "${" + SERVICE_REGISTRY_TTL_INTERVAL + ":" + CoreDefaults.DEFAULT_SERVICE_REGISTRY_TTL_INTERVAL_MINUTES + "}"; - + + public static final String SYSTEM_REGISTRY_PING_TIMEOUT = "ping_timeout"; + public static final String $SYSTEM_REGISTRY_PING_TIMEOUT_WD = + "${" + SYSTEM_REGISTRY_PING_TIMEOUT + ":" + CoreDefaults.DEFAULT_SYSTEM_REGISTRY_PING_TIMEOUT_MILLISECONDS + "}"; + public static final String AUTHORIZATION_IS_EVENTHANDLER_PRESENT = "eventhandler_is_present"; - public static final String $AUTHORIZATION_IS_EVENTHANDLER_PRESENT_WD = "${" + AUTHORIZATION_IS_EVENTHANDLER_PRESENT + ":" +CoreDefaults.DEFAULT_AUTHORIZATION_IS_EVENTHANDLER_PRESENT + "}"; + public static final String $AUTHORIZATION_IS_EVENTHANDLER_PRESENT_WD = "${" + AUTHORIZATION_IS_EVENTHANDLER_PRESENT + ":" + CoreDefaults.DEFAULT_AUTHORIZATION_IS_EVENTHANDLER_PRESENT + "}"; public static final String ORCHESTRATOR_IS_GATEKEEPER_PRESENT = "gatekeeper_is_present"; public static final String $ORCHESTRATOR_IS_GATEKEEPER_PRESENT_WD = "${" + ORCHESTRATOR_IS_GATEKEEPER_PRESENT + ":" + CoreDefaults.DEFAULT_ORCHESTRATOR_IS_GATEKEEPER_PRESENT + "}"; @@ -116,6 +129,20 @@ public class CoreCommonConstants { public static final int TOP_PRIORITY = 1; + public static final String QOS_MANAGER = "qosManager"; + public static final String QOS_ENABLED = "enable_qos"; + public static final String $QOS_ENABLED_WD = "${" + QOS_ENABLED + ":" + CoreDefaults.DEFAULT_QOS_ENABLED + "}"; + public static final String QOS_RESERVATION_CHECK_INTERVAL = "qos_reservation_check_interval"; // in seconds + public static final String $QOS_RESERVATION_CHECK_INTERVAL_WD = "${" + QOS_RESERVATION_CHECK_INTERVAL + ":" + CoreDefaults.DEFAULT_QOS_RESERVATION_CHECK_INTERVAL + "}"; + public static final String QOS_RESERVATION_TEMP_LOCK_DURATION = "qos_reservation_temp_lock_duration"; // in seconds + public static final String $QOS_RESERVATION_TEMP_LOCK_DURATION_WD = "${" + QOS_RESERVATION_TEMP_LOCK_DURATION + ":" + CoreDefaults.DEFAULT_QOS_TEMPORARY_LOCK_DURATION + "}"; + public static final String QOS_MAX_RESERVATION_DURATION = "qos_maximum_reservation_duration"; // in seconds + public static final String $QOS_MAX_RESERVATION_DURATION_WD = "${" + QOS_MAX_RESERVATION_DURATION + ":" + CoreDefaults.DEFAULT_QOS_MAX_RESERVATION_DURATION + "}"; + public static final String QOS_PING_MEASUREMENT_CACHE_THRESHOLD = "qos_ping_measurement_cache_threshold"; // in seconds + public static final String $QOS_PING_MEASUREMENT_CACHE_THRESHOLD_WD = "${" + QOS_PING_MEASUREMENT_CACHE_THRESHOLD + ":" + CoreDefaults.DEFAULT_QOS_PING_MEASUREMENT_CACHE_THRESHOLD + "}"; + public static final String QOS_NOT_MEASURED_SYSTEM_VERIFY_RESULT = "qos_not_measured_system_verify_result"; // result of verify if a system has no measurement records + public static final String $QOS_NOT_MEASURED_SYSTEM_VERIFY_RESULT = "${" + QOS_NOT_MEASURED_SYSTEM_VERIFY_RESULT + ":" + CoreDefaults.DEFAULT_QOS_NOT_MEASURED_SYSTEM_VERIFY_RESULT + "}"; + public static final String NO_GATEKEEPER_RELAY_REQUEST_HANDLER_WORKERS = "no_gatekeeper_relay_request_handler_workers"; public static final String $NO_GATEKEEPER_RELAY_REQUEST_HANDLER_WORKERS_WD = "${" + NO_GATEKEEPER_RELAY_REQUEST_HANDLER_WORKERS + ":" + CoreDefaults.DEFAULT_NO_GATEKEEPER_RELAY_REQUEST_HANDLER_WORKERS + "}"; @@ -145,7 +172,14 @@ public class CoreCommonConstants { public static final String $EVENT_HANDLER_MAX_EXPRESS_SUBSCRIBERS_WD = "${" + EVENT_HANDLER_MAX_EXPRESS_SUBSCRIBERS + ":" + CoreDefaults.DEFAULT_EVENT_HANDLER_MAX_EXPRESS_SUBSCRIBERS + "}"; public static final String EVENT_PUBLISHING_EXPRESS_EXECUTOR = "eventPublishingExpressExecutor"; - //================================================================================================= + public static final String PING_TTL_INTERVAL = "ping_ttl_interval_minutes"; + public static final String $PING_TTL_INTERVAL_WD = "${" + PING_TTL_INTERVAL + ":" + CoreDefaults.DEFAULT_PING_TTL_INTERVAL_MINUTES + "}"; + + public static final String CLOUD_PING_TTL_INTERVAL = "cloud_ping_ttl_interval_minutes"; + public static final String $CLOUD_PING_TTL_INTERVAL_WD = "${" + CLOUD_PING_TTL_INTERVAL + ":" + CoreDefaults.DEFAULT_CLOUD_PING_TTL_INTERVAL_MINUTES + "}"; + public static final String CERTIFICATE_FORMAT = "X.509"; + + //================================================================================================= // assistant methods //------------------------------------------------------------------------------------------------- diff --git a/core-common/src/main/java/eu/arrowhead/common/CoreDefaults.java b/core-common/src/main/java/eu/arrowhead/common/CoreDefaults.java index 8ffc12b5c..c53c885fc 100644 --- a/core-common/src/main/java/eu/arrowhead/common/CoreDefaults.java +++ b/core-common/src/main/java/eu/arrowhead/common/CoreDefaults.java @@ -13,13 +13,17 @@ public class CoreDefaults { public static final boolean DEFAULT_USE_STRICT_SERVICE_INTF_NAME_VERIFIER = false; public static final int DEFAULT_URI_CRAWLER_INTERVAL = 30; public static final int DEFAULT_AUTH_TOKEN_TTL_IN_MINUTES = -1; // never expires + public static final int DEFAULT_AUTH_TOKEN_TTL_IN_MINUTES_WITH_QOS_ENABLED = 60; // when QoS enabled, we want to make sure that tokens expires eventually public static final boolean DEFAULT_SERVICE_REGISTRY_PING_SCHEDULED = false; public static final int DEFAULT_SERVICE_REGISTRY_PING_INTERVAL_MINUTES = 60; - public static final int DEFAULT_SERVICE_REGISTRY_PING_TIMEOUT_MILISECONDS = 5000; + public static final int DEFAULT_SERVICE_REGISTRY_PING_TIMEOUT_MILLISECONDS = 5000; public static final boolean DEFAULT_SERVICE_REGISTRY_TTL_SCHEDULED = false; public static final int DEFAULT_SERVICE_REGISTRY_TTL_INTERVAL_MINUTES = 13; - + + public static final int DEFAULT_SYSTEM_REGISTRY_PING_INTERVAL_MINUTES = 60; + public static final int DEFAULT_SYSTEM_REGISTRY_PING_TIMEOUT_MILLISECONDS = 5000; + public static final String DEFAULT_OWN_CLOUD_OPERATOR = "default_operator"; public static final String DEFAULT_OWN_CLOUD_NAME = "default_insecure_cloud"; @@ -45,6 +49,17 @@ public class CoreDefaults { public static final long DEFAULT_TIME_STAMP_TOLERANCE_SECONDS = 120; public static final int DEFAULT_EVENT_HANDLER_MAX_EXPRESS_SUBSCRIBERS = 10; + public static final int DEFAULT_PING_TTL_INTERVAL_MINUTES = 10; + + public static final int DEFAULT_CLOUD_PING_TTL_INTERVAL_MINUTES = 10; + + public static final boolean DEFAULT_QOS_ENABLED = false; + public static final int DEFAULT_QOS_RESERVATION_CHECK_INTERVAL = 60; // in seconds + public static final int DEFAULT_QOS_TEMPORARY_LOCK_DURATION = 60; // in seconds + public static final int DEFAULT_QOS_MAX_RESERVATION_DURATION = 3600; // in seconds + public static final int DEFAULT_QOS_PING_MEASUREMENT_CACHE_THRESHOLD = 600; // in seconds + public static final boolean DEFAULT_QOS_NOT_MEASURED_SYSTEM_VERIFY_RESULT = true; + //================================================================================================= // assistant methods diff --git a/core-common/src/main/java/eu/arrowhead/common/CoreUtilities.java b/core-common/src/main/java/eu/arrowhead/common/CoreUtilities.java index fd20c8d76..e669c98cb 100644 --- a/core-common/src/main/java/eu/arrowhead/common/CoreUtilities.java +++ b/core-common/src/main/java/eu/arrowhead/common/CoreUtilities.java @@ -73,24 +73,25 @@ public static class ValidatedPageParams { //================================================================================================= // members - + private static final int MAX_BATCH_SIZE = Integer.MAX_VALUE; + private final int validatedPage; private final int validatedSize; - private final Direction validatedDirecion; + private final Direction validatedDirection; //================================================================================================= // methods //------------------------------------------------------------------------------------------------- public ValidatedPageParams(final int validatedPage, final int validatedSize, final Direction validatedDirection) { - this.validatedPage = validatedPage; - this.validatedSize = validatedSize; - this.validatedDirecion = validatedDirection; + this.validatedPage = Math.max(validatedPage, 0); + this.validatedSize = validatedSize < 1 ? MAX_BATCH_SIZE : validatedSize; + this.validatedDirection = validatedDirection; } //------------------------------------------------------------------------------------------------- public int getValidatedPage() { return validatedPage; } public int getValidatedSize() { return validatedSize; } - public Direction getValidatedDirecion() { return validatedDirecion; } + public Direction getValidatedDirection() { return validatedDirection; } } } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/Defaults.java b/core-common/src/main/java/eu/arrowhead/common/Defaults.java index e5db9ed31..5460b30fd 100644 --- a/core-common/src/main/java/eu/arrowhead/common/Defaults.java +++ b/core-common/src/main/java/eu/arrowhead/common/Defaults.java @@ -11,27 +11,34 @@ public class Defaults { public static final int DEFAULT_URI_CRAWLER_INTERVAL = 30; public static final int DEFAULT_AUTH_TOKEN_TTL_IN_MINUTES = -1; // never expires - public static final String DEFAULT_SERVICE_REGISTRY_ADDRESS = CommonConstants.LOCALHOST; + public static final String DEFAULT_SERVICE_REGISTRY_ADDRESS = CommonConstants.LOCALHOST; + public static final int DEFAULT_ONBOARDING_PORT = 8435; + public static final int DEFAULT_SYSTEM_REGISTRY_PORT = 8437; + public static final int DEFAULT_DEVICE_REGISTRY_PORT = 8439; + public static final int DEFAULT_ORCHESTRATOR_PORT = 8441; public static final int DEFAULT_SERVICE_REGISTRY_PORT = 8443; public static final int DEFAULT_AUTHORIZATION_PORT = 8445; - public static final int DEFAULT_ORCHESTRATOR_PORT = 8441; - public static final int DEFAULT_GATEKEEPER_PORT = 8449; + public static final int DEFAULT_GATEKEEPER_PORT = 8449; + public static final int DEFAULT_QOS_MONITOR_PORT = 8451; public static final int DEFAULT_GATEWAY_PORT = 8453; public static final int DEFAULT_EVENT_HANDLER_PORT = 8455; public static final int DEFAULT_CHOREOGRAPHER_PORT = 8457; - public static final int DEFAULT_CERTIFICATE_AUTHORITY_PORT = 8459; - - // HTTP client defaults - public static final int DEFAULT_CONNECTION_TIMEOUT = 30000; - public static final int DEFAULT_SOCKET_TIMEOUT = 30000; - public static final int DEFAULT_CONNECTION_MANAGER_TIMEOUT = 10000; - - // CORS defaults - public static final long CORS_MAX_AGE = 600; - public static final String CORS_ALLOW_CREDENTIALS = "true"; - - //------------------------------------------------------------------------------------------------- - private Defaults() { - throw new UnsupportedOperationException(); - } + public static final int DEFAULT_CERTIFICATE_AUTHORITY_PORT = 8448; + + // HTTP client defaults + public static final int DEFAULT_CONNECTION_TIMEOUT = 30000; + public static final int DEFAULT_SOCKET_TIMEOUT = 30000; + public static final int DEFAULT_CONNECTION_MANAGER_TIMEOUT = 10000; + + // CORS defaults + public static final long CORS_MAX_AGE = 600; + public static final String CORS_ALLOW_CREDENTIALS = "true"; + + // CA defaults + public static final long DEFAULT_CA_CERT_VALIDITY_NEG_OFFSET_MILLIS = 5000; + public static final long DEFAULT_CA_CERT_VALIDITY_POS_OFFSET_MILLIS = 1000L * 3600 * 24 * 365; + //------------------------------------------------------------------------------------------------- + private Defaults() { + throw new UnsupportedOperationException(); + } } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/SecurityUtilities.java b/core-common/src/main/java/eu/arrowhead/common/SecurityUtilities.java new file mode 100644 index 000000000..3c371fe8a --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/SecurityUtilities.java @@ -0,0 +1,340 @@ +package eu.arrowhead.common; + +import eu.arrowhead.common.dto.shared.CertificateCreationRequestDTO; +import eu.arrowhead.common.dto.shared.CertificateCreationResponseDTO; +import eu.arrowhead.common.dto.shared.CertificateType; +import eu.arrowhead.common.dto.shared.KeyPairDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.common.exception.AuthException; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.bouncycastle.asn1.DEROctetString; +import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers; +import org.bouncycastle.asn1.x500.X500Name; +import org.bouncycastle.asn1.x509.Extension; +import org.bouncycastle.asn1.x509.Extensions; +import org.bouncycastle.asn1.x509.GeneralName; +import org.bouncycastle.asn1.x509.GeneralNamesBuilder; +import org.bouncycastle.operator.ContentSigner; +import org.bouncycastle.operator.OperatorCreationException; +import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder; +import org.bouncycastle.pkcs.PKCS10CertificationRequest; +import org.bouncycastle.pkcs.jcajce.JcaPKCS10CertificationRequestBuilder; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; +import org.springframework.util.Base64Utils; +import org.springframework.util.StringUtils; + +import javax.servlet.http.HttpServletRequest; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.security.KeyFactory; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.Principal; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.cert.Certificate; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509Certificate; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.Base64; +import java.util.Objects; + +@Component +public class SecurityUtilities { + + //================================================================================================= + // members + private final static String SIGNATURE_ALGORITHM = "SHA256WithRSA"; + + private final Logger logger = LogManager.getLogger(SecurityUtilities.class); + + private final KeyFactory keyFactory; + private final KeyPairGenerator keyPairGenerator; + private final SSLProperties sslProperties; + + //================================================================================================= + // constructors + @Autowired + public SecurityUtilities(@Value("${security.key.algorithm:RSA}") final String keyFactoryAlgorithm, + @Value("${security.key.size:2048}") final Integer keySize, + final SSLProperties sslProperties) throws NoSuchAlgorithmException { + Assert.hasText(keyFactoryAlgorithm,"keyFactoryAlgorithm must not be null"); + Assert.notNull(keySize,"keyFactoryAlgorithm keySize not be null"); + Assert.notNull(sslProperties,"sslProperties must not be null"); + this.sslProperties = sslProperties; + keyFactory = KeyFactory.getInstance(keyFactoryAlgorithm); + keyPairGenerator = KeyPairGenerator.getInstance(keyFactoryAlgorithm); + keyPairGenerator.initialize(keySize); + } + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public static String getCertificateCNFromRequest(final HttpServletRequest request) { + Assert.notNull(request,"request must not be null"); + final X509Certificate[] certificates = (X509Certificate[]) request.getAttribute(CommonConstants.ATTR_JAVAX_SERVLET_REQUEST_X509_CERTIFICATE); + if (certificates != null && certificates.length != 0) { + final X509Certificate cert = certificates[0]; + return Utilities.getCertCNFromSubject(cert.getSubjectDN().getName()); + } + + return null; + } + + //------------------------------------------------------------------------------------------------- + private static String getCommonNameFromCloudCertificate(final Principal principal) { + Assert.notNull(principal, "Principal must not be null"); + return Utilities.getCertCNFromSubject(principal.getName()); + } + + //------------------------------------------------------------------------------------------------- + private static String getOperatorNameFromCloudCertificate(final Principal principal) { + return extractCNPart(principal, 2); + } + + //------------------------------------------------------------------------------------------------- + private static String getOrganizationFromCloudCertificate(final Principal principal) { + return extractCNPart(principal, 1); + } + + //------------------------------------------------------------------------------------------------- + private static String getCountryFromCloudCertificate(final Principal principal) { + return extractCNPart(principal, 0); + } + + //------------------------------------------------------------------------------------------------- + private static String extractCNPart(final Principal principal, final int tailIndex) { + Assert.notNull(principal, "Principal must not be null"); + Assert.isTrue(tailIndex >= 0, "tailIndex must not be negative"); + final String fullCN = principal.getName(); + Assert.hasText(fullCN, "Empty common name is not allowed"); + + final String[] strings = fullCN.split("\\."); + + if (tailIndex >= strings.length) { + throw new IllegalArgumentException("Internal error: Unable to extract information from cloud certificate"); + } + + return strings[strings.length - (tailIndex + 1)]; + } + + //------------------------------------------------------------------------------------------------- + public void authenticateCertificate(final HttpServletRequest httpServletRequest, final CertificateType minimumStrength) { + Assert.notNull(httpServletRequest,"httpServletRequest must not be null"); + Assert.notNull(minimumStrength,"minimumStrength must not be null"); + + final X509Certificate[] certificates = (X509Certificate[]) httpServletRequest.getAttribute(CommonConstants.ATTR_JAVAX_SERVLET_REQUEST_X509_CERTIFICATE); + + if (sslProperties.isSslEnabled()) { + if (Objects.nonNull(certificates) && certificates.length > 0) { + + final X509Certificate cert = certificates[0]; + final String clientCN = Utilities.getCertCNFromSubject(cert.getSubjectDN().getName()); + final String requestTarget = Utilities.stripEndSlash(httpServletRequest.getRequestURL().toString()); + + authenticateCertificate(clientCN, requestTarget, minimumStrength); + } else { + logger.debug("No client certificate given!"); + throw new AuthException("Client certificate in needed!"); + } + } + } + + //------------------------------------------------------------------------------------------------- + public void authenticateCertificate(final String clientCN, final String requestTarget, final CertificateType minimumStrength) { + Assert.notNull(clientCN,"clientCN must not be null"); + Assert.notNull(requestTarget,"requestTarget must not be null"); + Assert.notNull(minimumStrength,"minimumStrength must not be null"); + + if (sslProperties.isSslEnabled()) { + + final CertificateType type = CertificateType.getTypeFromCN(clientCN); + if (!type.hasMinimumStrength(minimumStrength)) { + logger.debug("{} is not a valid common name, access denied!", clientCN); + throw new AuthException(clientCN + " is unauthorized to access " + requestTarget); + } + } + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + public String createCertificateSigningRequest(final String baseCommonName, final KeyPair keyPair, final CertificateType type, + final String host, final String address) + throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, OperatorCreationException { + Assert.hasText(baseCommonName, "baseCommonName must not be null or empty!"); + Assert.notNull(keyPair, "keyPair must not be null"); + Assert.notNull(sslProperties.getKeyStore(), "KeyStore property must not be null!"); + Assert.hasText(sslProperties.getKeyStorePassword(), "KeyStore password property must not be null or empty!"); + Assert.notNull(type, "type must not be null"); + // host and address are optional + + logger.debug("Preparing Certificate Signing Request ..."); + // get cloud certificate for cloudName and operator + final KeyStore keyStore = KeyStore.getInstance(sslProperties.getKeyStore().getFile(), sslProperties.getKeyStorePassword().toCharArray()); + final X509Certificate cloudCertFromKeyStore = Utilities.getCloudCertFromKeyStore(keyStore); + + // "CN=....arrowhead.eu, OU=, O=arrowhead, C=eu" + final String cloudName = getCommonNameFromCloudCertificate(cloudCertFromKeyStore.getSubjectDN()); + final String operator = getOperatorNameFromCloudCertificate(cloudCertFromKeyStore.getSubjectDN()); + final String organization = getOrganizationFromCloudCertificate(cloudCertFromKeyStore.getSubjectDN()); + final String country = getCountryFromCloudCertificate(cloudCertFromKeyStore.getSubjectDN()); + final String commonName = String.format("CN=%s.%s, OU=%s, O=%s, C=%s", type.appendTypeToCN(baseCommonName), cloudName, + operator, organization, country); + final X500Name x500Name = new X500Name(commonName); + + logger.debug("Building and Signing Certificate Signing Request for {}", x500Name); + // create certificate signing request + final JcaPKCS10CertificationRequestBuilder builder = new JcaPKCS10CertificationRequestBuilder(x500Name, keyPair.getPublic()); + final GeneralNamesBuilder namesBuilder = new GeneralNamesBuilder(); + + namesBuilder.addName(new GeneralName(GeneralName.dNSName, "localhost")); + namesBuilder.addName(new GeneralName(GeneralName.dNSName, baseCommonName)); + namesBuilder.addName(new GeneralName(GeneralName.iPAddress, "127.0.0.1")); + + if (StringUtils.hasText(host)) { + namesBuilder.addName(new GeneralName(GeneralName.dNSName, host)); + } + if (StringUtils.hasText(address)) { + namesBuilder.addName(new GeneralName(GeneralName.iPAddress, address)); + } + + final Extension extAlternativeNames = new Extension(Extension.subjectAlternativeName, false, new DEROctetString(namesBuilder.build())); + builder.addAttribute(PKCSObjectIdentifiers.pkcs_9_at_extensionRequest, new Extensions(extAlternativeNames)); + + final JcaContentSignerBuilder contentSignerBuilder = new JcaContentSignerBuilder(SIGNATURE_ALGORITHM); + final ContentSigner contentSigner = contentSignerBuilder.build(keyPair.getPrivate()); + final PKCS10CertificationRequest csr = builder.build(contentSigner); + + return Base64.getEncoder().encodeToString(csr.getEncoded()); + } + + //------------------------------------------------------------------------------------------------- + public void extractAndSetPublicKey(final CertificateCreationResponseDTO creationResponseDTO) { + Assert.notNull(creationResponseDTO, "creationResponseDTO must not be null"); + + try { + final byte[] certificateBytes = Base64Utils.decodeFromString(creationResponseDTO.getCertificate()); + + final Certificate certificate; + + try (ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(certificateBytes)) { + final CertificateFactory certificateFactory = CertificateFactory.getInstance(creationResponseDTO.getCertificateFormat()); + certificate = certificateFactory.generateCertificate(byteArrayInputStream); + } catch (final CertificateException e) { + logger.error("Unable to generate certificate from Base64: {}", creationResponseDTO.getCertificate()); + throw new ArrowheadException("Unable to decode signed certificate", HttpStatus.SC_INTERNAL_SERVER_ERROR); + } + + final PublicKey publicKey = certificate.getPublicKey(); + creationResponseDTO.setKeyPairDTO(encodePublicKey(publicKey)); + + } catch (final IOException e) { + logger.fatal("ByteArrayInputStream should never throw an IOException, but it just did : {}", e.getMessage()); + throw new ArrowheadException(e.getMessage()); + } + } + + //------------------------------------------------------------------------------------------------- + public KeyPair extractOrGenerateKeyPair(final CertificateCreationRequestDTO creationRequestDTO) { + Assert.notNull(creationRequestDTO, "creationRequestDTO must not be null"); + + final String commonName = creationRequestDTO.getCommonName(); + Assert.isTrue(Utilities.notEmpty(commonName), "CommonName is null or blank"); + + final KeyPairDTO keyPairDTO = creationRequestDTO.getKeyPairDTO(); + final KeyPair keyPair; + + if (Objects.nonNull(keyPairDTO) && + Objects.nonNull(keyPairDTO.getPublicKey()) && + Objects.nonNull(keyPairDTO.getPrivateKey())) { + + final String encodedPublicKey = keyPairDTO.getPublicKey(); + final String encodedPrivateKey = keyPairDTO.getPrivateKey(); + + keyPair = getKeyPairFromBase64EncodedStrings(encodedPublicKey, encodedPrivateKey); + } else { + keyPair = generateKeyPair(); + } + + return keyPair; + } + + //------------------------------------------------------------------------------------------------- + public KeyPairDTO encodePublicKey(final PublicKey publicKey) { + Assert.notNull(publicKey, "PublicKey must not be null"); + final String encodedPublicKey = Base64.getEncoder().encodeToString(publicKey.getEncoded()); + return new KeyPairDTO(publicKey.getAlgorithm(), publicKey.getFormat(), encodedPublicKey, null); + } + + //------------------------------------------------------------------------------------------------- + public KeyPairDTO encodeKeyPair(final KeyPair keyPair) { + Assert.notNull(keyPair, "KeyPair must not be null"); + final KeyPairDTO dto = encodePublicKey(keyPair.getPublic()); + if (Objects.nonNull(keyPair.getPrivate())) { dto.setPrivateKey(Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded())); } + return dto; + } + + //------------------------------------------------------------------------------------------------- + private PublicKey getPublicKeyFromBase64EncodedString(final String encodedKey) { + Assert.isTrue(Utilities.notEmpty(encodedKey), "Encoded key is null or blank"); + + final byte[] keyBytes = Base64.getDecoder().decode(encodedKey); + return generatePublicKeyFromByteArray(keyBytes); + } + + + //------------------------------------------------------------------------------------------------- + private KeyPair generateKeyPair() { + return keyPairGenerator.generateKeyPair(); + } + + //------------------------------------------------------------------------------------------------- + private KeyPair getKeyPairFromBase64EncodedStrings(final String encodedPublicKey, + final String encodedPrivateKey) { + final PublicKey publicKey = getPublicKeyFromBase64EncodedString(encodedPublicKey); + final PrivateKey privateKey = getPrivateKeyFromBase64EncodedString(encodedPrivateKey); + return new KeyPair(publicKey, privateKey); + } + + //------------------------------------------------------------------------------------------------- + private PrivateKey getPrivateKeyFromBase64EncodedString(final String encodedKey) { + Assert.isTrue(Utilities.notEmpty(encodedKey), "Encoded key is null or blank"); + + final byte[] keyBytes = Base64.getDecoder().decode(encodedKey); + return generatePrivateKeyFromByteArray(keyBytes); + } + + //------------------------------------------------------------------------------------------------- + private PublicKey generatePublicKeyFromByteArray(final byte[] keyBytes) { + try { + return keyFactory.generatePublic(new X509EncodedKeySpec(keyBytes)); + } catch (final InvalidKeySpecException ex) { + logger.error("getPublicKey: X509 keySpec could not be created from the decoded bytes."); + throw new AuthException("Public key decoding failed due wrong input key", ex); + } + } + + //------------------------------------------------------------------------------------------------- + private PrivateKey generatePrivateKeyFromByteArray(final byte[] keyBytes) { + try { + return keyFactory.generatePrivate(new X509EncodedKeySpec(keyBytes)); + } catch (final InvalidKeySpecException ex) { + logger.error("getPublicKey: X509 keySpec could not be created from the decoded bytes."); + throw new AuthException("Public key decoding failed due wrong input key", ex); + } + } + +} diff --git a/core-common/src/main/java/eu/arrowhead/common/Utilities.java b/core-common/src/main/java/eu/arrowhead/common/Utilities.java index 790ea5832..632f7a0a4 100644 --- a/core-common/src/main/java/eu/arrowhead/common/Utilities.java +++ b/core-common/src/main/java/eu/arrowhead/common/Utilities.java @@ -1,5 +1,31 @@ package eu.arrowhead.common; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import eu.arrowhead.common.dto.internal.RelayType; +import eu.arrowhead.common.dto.shared.ErrorMessageDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.common.exception.AuthException; +import eu.arrowhead.common.exception.BadPayloadException; +import eu.arrowhead.common.exception.DataNotFoundException; +import eu.arrowhead.common.exception.InvalidParameterException; +import eu.arrowhead.common.exception.TimeoutException; +import eu.arrowhead.common.exception.UnavailableServerException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.http.HttpStatus; +import org.springframework.lang.Nullable; +import org.springframework.util.Assert; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.util.StringUtils; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import javax.naming.InvalidNameException; +import javax.naming.ldap.LdapName; +import javax.naming.ldap.Rdn; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -13,6 +39,7 @@ import java.security.PrivateKey; import java.security.PublicKey; import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.security.spec.InvalidKeySpecException; import java.security.spec.X509EncodedKeySpec; @@ -31,60 +58,37 @@ import java.util.Map; import java.util.Map.Entry; import java.util.NoSuchElementException; +import java.util.Objects; import java.util.ServiceConfigurationError; +import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.naming.InvalidNameException; -import javax.naming.ldap.LdapName; -import javax.naming.ldap.Rdn; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.springframework.http.HttpStatus; -import org.springframework.lang.Nullable; -import org.springframework.util.Assert; -import org.springframework.util.LinkedMultiValueMap; -import org.springframework.util.MultiValueMap; -import org.springframework.web.util.UriComponents; -import org.springframework.web.util.UriComponentsBuilder; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; - -import eu.arrowhead.common.dto.internal.RelayType; -import eu.arrowhead.common.dto.shared.ErrorMessageDTO; -import eu.arrowhead.common.exception.ArrowheadException; -import eu.arrowhead.common.exception.AuthException; -import eu.arrowhead.common.exception.BadPayloadException; -import eu.arrowhead.common.exception.DataNotFoundException; -import eu.arrowhead.common.exception.InvalidParameterException; -import eu.arrowhead.common.exception.TimeoutException; -import eu.arrowhead.common.exception.UnavailableServerException; - public class Utilities { - + //================================================================================================= // members - + private static final int SERVICE_CN_NAME_LENGTH = 5; @SuppressWarnings("unused") private static final int CLOUD_CN_NAME_LENGTH = 4; @SuppressWarnings("unused") private static final int AH_MASTER_CN_NAME_LENGTH = 2; - + private static final String AH_MASTER_SUFFIX = "eu"; private static final String AH_MASTER_NAME = "arrowhead"; - + private static final String KEY_FACTORY_ALGORHITM_NAME = "RSA"; private static final KeyFactory keyFactory; private static final Pattern PEM_PATTERN = Pattern.compile("(?m)(?s)^---*BEGIN.*---*$(.*)^---*END.*---*$.*"); - + + private static final String MAC_ADDRESS_PATTERN_STRING = "^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$"; + public static final Pattern MAC_ADDRESS_PATTERN = Pattern.compile(MAC_ADDRESS_PATTERN_STRING); + private static final Logger logger = LogManager.getLogger(Utilities.class); private static final ObjectMapper mapper = new ObjectMapper(); private static final String dateTimePattern = "yyyy-MM-dd HH:mm:ss"; static final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(dateTimePattern); - + static { mapper.configure(SerializationFeature.INDENT_OUTPUT, true); try { @@ -94,7 +98,7 @@ public class Utilities { throw new ServiceConfigurationError("KeyFactory.getInstance(String) throws NoSuchAlgorithmException, code needs to be changed!", ex); } } - + //================================================================================================= // methods @@ -102,34 +106,39 @@ public class Utilities { public static boolean isEmpty(final String str) { return str == null || str.isBlank(); } - + + //------------------------------------------------------------------------------------------------- + public static boolean notEmpty(final String str) { + return StringUtils.hasText(str); + } + //------------------------------------------------------------------------------------------------- @Nullable public static String stripEndSlash(final String uri) { if (uri != null && uri.endsWith("/")) { return uri.substring(0, uri.length() - 1); } - + return uri; } - + //------------------------------------------------------------------------------------------------- public static String convertZonedDateTimeToUTCString(final ZonedDateTime time) { if (time == null) { return null; } - + final LocalDateTime localDateTime = LocalDateTime.ofInstant(time.toInstant(), ZoneOffset.UTC); return dateTimeFormatter.format(localDateTime); } - + //------------------------------------------------------------------------------------------------- @SuppressWarnings("squid:RedundantThrowsDeclarationCheck") public static ZonedDateTime parseUTCStringToLocalZonedDateTime(final String timeStr) throws DateTimeParseException { if (isEmpty(timeStr)) { return null; } - + final TemporalAccessor tempAcc = dateTimeFormatter.parse(timeStr); final ZonedDateTime parsedDateTime = ZonedDateTime.of(tempAcc.get(ChronoField.YEAR), tempAcc.get(ChronoField.MONTH_OF_YEAR), @@ -139,11 +148,11 @@ public static ZonedDateTime parseUTCStringToLocalZonedDateTime(final String time tempAcc.get(ChronoField.SECOND_OF_MINUTE), 0, ZoneOffset.UTC); - + final ZoneOffset offset = OffsetDateTime.now().getOffset(); return ZonedDateTime.ofInstant(parsedDateTime.toInstant(), offset); } - + //------------------------------------------------------------------------------------------------- @Nullable public static String toPrettyJson(final String jsonString) { @@ -161,45 +170,45 @@ public static String toPrettyJson(final String jsonString) { } catch (final IOException ex) { // it seems it is not a JSON string, so we just return untouched } - + return jsonString; } - + //------------------------------------------------------------------------------------------------- @Nullable public static String toJson(final Object object) { if (object == null) { return null; } - + try { return mapper.writeValueAsString(object); } catch (final JsonProcessingException ex) { throw new ArrowheadException("The specified object cannot be converted to text.", ex); } } - + //------------------------------------------------------------------------------------------------- @Nullable public static T fromJson(final String json, final Class parsedClass) { if (json == null || parsedClass == null) { return null; } - + try { return mapper.readValue(json, parsedClass); } catch (final IOException ex) { throw new ArrowheadException("The specified string cannot be converted to a(n) " + parsedClass.getSimpleName() + " object.", ex); } } - + //------------------------------------------------------------------------------------------------- @Nullable public static Map text2Map(final String text) { if (text == null) { return null; } - + final Map result = new HashMap<>(); if (!isEmpty(text.trim())) { final String[] parts = text.split(","); @@ -208,30 +217,30 @@ public static Map text2Map(final String text) { result.put(URLDecoder.decode(pair[0].trim(), StandardCharsets.UTF_8), pair.length == 1 ? "" : URLDecoder.decode(pair[1].trim(), StandardCharsets.UTF_8)); } } - + return result; } - + //------------------------------------------------------------------------------------------------- @Nullable public static String map2Text(final Map map) { if (map == null) { return null; } - + final StringBuilder sb = new StringBuilder(); for (final Entry entry : map.entrySet()) { final String key = URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8); final String value = URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8); sb.append(key).append("=").append(value).append(", "); } - + return map.isEmpty() ? "" : sb.substring(0, sb.length() - 2); } - + //------------------------------------------------------------------------------------------------- + /** - * * @param scheme default: http * @param host default: 127.0.0.1 * @param port default: 80 @@ -244,54 +253,54 @@ public static UriComponents createURI(final String scheme, final String host, fi builder.scheme(scheme == null ? CommonConstants.HTTP : scheme) .host(host == null ? CommonConstants.LOCALHOST : host) .port(port <= 0 ? CommonConstants.HTTP_PORT : port); - + if (queryParams != null) { builder.queryParams(queryParams); } - + if (pathSegments != null && pathSegments.length > 0) { builder.pathSegment(pathSegments); } - + if (!Utilities.isEmpty(path)) { builder.path(path); } - + return builder.build(); } - + //------------------------------------------------------------------------------------------------- public static UriComponents createURI(final String scheme, final String host, final int port, final String path) { return createURI(scheme, host, port, null, path, (String[]) null); } - + //------------------------------------------------------------------------------------------------- public static UriComponents createURI(final String scheme, final String host, final int port, final String path, final String... queryParams) { if (queryParams.length % 2 != 0) { throw new InvalidParameterException("queryParams variable arguments conatins a key without value"); } - - final LinkedMultiValueMap query = new LinkedMultiValueMap<>(); - + + final LinkedMultiValueMap query = new LinkedMultiValueMap<>(); + int count = 1; String key = ""; for (final String vararg : queryParams) { if (count % 2 != 0) { - query.putIfAbsent(vararg, new ArrayList<>()); + query.putIfAbsent(vararg, new ArrayList<>()); key = vararg; } else { - query.get(key).add(vararg); + query.get(key).add(vararg); } count++; } - + return createURI(scheme, host, port, query, path); } - + //------------------------------------------------------------------------------------------------- public static HttpStatus calculateHttpStatusFromArrowheadException(final ArrowheadException ex) { Assert.notNull(ex, "Exception is null."); - + HttpStatus status = HttpStatus.resolve(ex.getErrorCode()); if (status == null) { switch (ex.getExceptionType()) { @@ -313,30 +322,30 @@ public static HttpStatus calculateHttpStatusFromArrowheadException(final Arrowhe status = HttpStatus.INTERNAL_SERVER_ERROR; } } - + return status; } - + //------------------------------------------------------------------------------------------------- public static RelayType convertStringToRelayType(final String str) { if (isEmpty(str)) { return RelayType.GENERAL_RELAY; } - + try { - return RelayType.valueOf(str.toUpperCase().trim()); + return RelayType.valueOf(str.toUpperCase().trim()); } catch (final IllegalArgumentException ex) { return null; } } - + //------------------------------------------------------------------------------------------------- @Nullable public static String getCertCNFromSubject(final String subjectName) { if (subjectName == null) { return null; } - + try { // Subject is in LDAP format, we can use the LdapName object for parsing final LdapName ldapname = new LdapName(subjectName); @@ -353,92 +362,206 @@ public static String getCertCNFromSubject(final String subjectName) { return null; } - + //------------------------------------------------------------------------------------------------- public static String getCloudCommonName(final String cloudOperator, final String cloudName) { Assert.isTrue(!isEmpty(cloudOperator), "Cloud operator is null or blank."); Assert.isTrue(!isEmpty(cloudName), "Cloud name is null or blank."); - - return (cloudName.trim() + "." + cloudOperator.trim() + ".arrowhead.eu").toLowerCase(); + + return (cloudName.trim() + "." + cloudOperator.trim() + ".arrowhead.eu").toLowerCase(); } - + //------------------------------------------------------------------------------------------------- public static X509Certificate getFirstCertFromKeyStore(final KeyStore keystore) { Assert.notNull(keystore, "Key store is not defined."); - + try { + // the first certificate is not always the end certificate. java does not guarantee the order final Enumeration enumeration = keystore.aliases(); - final String alias = enumeration.nextElement(); - return (X509Certificate) keystore.getCertificate(alias); + while (enumeration.hasMoreElements()) { + final Certificate[] chain = keystore.getCertificateChain(enumeration.nextElement()); + + if(Objects.nonNull(chain) && chain.length >= 3) { + return (X509Certificate) chain[0]; + } + } + throw new ServiceConfigurationError("Getting the first cert from keystore failed..."); } catch (final KeyStoreException | NoSuchElementException ex) { logger.error("Getting the first cert from key store failed...", ex); throw new ServiceConfigurationError("Getting the first cert from keystore failed...", ex); } } - - //------------------------------------------------------------------------------------------------- - public static PrivateKey getPrivateKey(final KeyStore keystore, final String keyPass) { + +//------------------------------------------------------------------------------------------------- + public static X509Certificate getCloudCertFromKeyStore(final KeyStore keystore) { Assert.notNull(keystore, "Key store is not defined."); - Assert.notNull(keyPass, "Password is not defined."); - - PrivateKey privateKey = null; - String element; - try { - final Enumeration enumeration = keystore.aliases(); - while (enumeration.hasMoreElements()) { - element = enumeration.nextElement(); - privateKey = (PrivateKey) keystore.getKey(element, keyPass.toCharArray()); - if (privateKey != null) { - break; - } - } - } catch (final KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException ex) { - logger.error("Getting the private key from key store failed...", ex); - throw new ServiceConfigurationError("Getting the private key from key store failed...", ex); - } - if (privateKey == null) { - throw new ServiceConfigurationError("Getting the private key failed, key store aliases do not identify a key."); - } - - return privateKey; - } - - //------------------------------------------------------------------------------------------------- - public static PublicKey getPublicKeyFromBase64EncodedString(final String encodedKey) { - Assert.isTrue(!isEmpty(encodedKey), "Encoded key is null or blank"); - - final byte[] keyBytes = Base64.getDecoder().decode(encodedKey); - return generatePublicKeyFromByteArray(keyBytes); + try { + // debian installation with new certificates have a different alias + // i.e. the format is {cloudname}." + AH_MASTER_NAME + "." + AH_MASTER_SUFFIX + final Enumeration enumeration = keystore.aliases(); + while (enumeration.hasMoreElements()) { + final String alias = enumeration.nextElement(); + final X509Certificate certificate = (X509Certificate) keystore.getCertificate(alias); + + if(isCloudCertificate(certificate)) + { + return certificate; + } + } + + final String errorMsg = "Getting the cloud cert from keystore failed. " + + "Cannot find alias in the following format: {cloudname}.{cloudoperator}." + AH_MASTER_NAME + "." + AH_MASTER_SUFFIX; + logger.error(errorMsg); + throw new ServiceConfigurationError(errorMsg); + } catch (final KeyStoreException | NoSuchElementException ex) { + logger.error("Getting the cloud cert from keystore failed...", ex); + throw new ServiceConfigurationError("Getting the cloud cert from keystore failed...", ex); + } } //------------------------------------------------------------------------------------------------- - public static PublicKey getPublicKeyFromPEMFile(final InputStream is) { - Assert.notNull(is, "Input stream is null"); + public static X509Certificate getRootCertFromKeyStore(final KeyStore keystore) { + Assert.notNull(keystore, "Key store is not defined."); + try { - final ByteArrayOutputStream baos = new ByteArrayOutputStream(); - final byte[] buf = new byte[1024]; - for (int read = 0; read != -1; read = is.read(buf)) { - baos.write(buf, 0, read); + // debian installation with new certificates have a different alias + Enumeration enumeration = keystore.aliases(); + while (enumeration.hasMoreElements()) { + final String alias = enumeration.nextElement(); + final X509Certificate certificate = (X509Certificate) keystore.getCertificate(alias); + final String commonName = getCertCNFromSubject(certificate.getSubjectDN().getName()); + Assert.notNull(commonName, "Certificate without commonName is not allowed"); + final String[] cnParts = commonName.split("\\."); + if (cnParts.length == 2 && cnParts[0].equals(AH_MASTER_NAME) && cnParts[1].equals(AH_MASTER_SUFFIX)) { + return (X509Certificate) keystore.getCertificate(alias); + } } - - final String pem = new String(baos.toByteArray(), StandardCharsets.ISO_8859_1); - baos.close(); - final String encoded = PEM_PATTERN.matcher(pem).replaceFirst("$1"); - final byte[] keyBytes = Base64.getMimeDecoder().decode(encoded); - - return generatePublicKeyFromByteArray(keyBytes); - } catch (final IOException ex) { - throw new ArrowheadException("IOException occurred during PEM file loading from input stream.", ex); - } - } - - //------------------------------------------------------------------------------------------------- - public static boolean isKeyStoreCNArrowheadValid(final String commonName) { - if (isEmpty(commonName)) { - return false; + + final String errorMsg = "Getting the root cert from keystore failed. " + + "Cannot find alias in the following format: " + AH_MASTER_NAME + "." + AH_MASTER_SUFFIX; + logger.error(errorMsg); + throw new ServiceConfigurationError(errorMsg); + } catch (final KeyStoreException | NoSuchElementException ex) { + logger.error("Getting the root cert from keystore failed...", ex); + throw new ServiceConfigurationError("Getting the root cert from keystore failed...", ex); } - + } + //------------------------------------------------------------------------------------------------- + public static PrivateKey getCloudPrivateKey(final KeyStore keystore, final String keyPass) { + Assert.notNull(keystore, "Key store is not defined."); + Assert.notNull(keyPass, "Password is not defined."); + + PrivateKey privateKey = null; + String element; + try { + final Enumeration enumeration = keystore.aliases(); + while (enumeration.hasMoreElements()) { + element = enumeration.nextElement(); + + final X509Certificate certificate = (X509Certificate) keystore.getCertificate(element); + if(isCloudCertificate(certificate)) + { + privateKey = (PrivateKey) keystore.getKey(element, keyPass.toCharArray()); + if (privateKey != null) { + break; + } + } + } + } catch (final KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException ex) { + logger.error("Getting the private key from key store failed...", ex); + throw new ServiceConfigurationError("Getting the private key from key store failed...", ex); + } + + if (privateKey == null) { + throw new ServiceConfigurationError("Getting the private key failed, key store aliases do not identify a key."); + } + + return privateKey; + } + //------------------------------------------------------------------------------------------------- + public static PrivateKey getPrivateKey(final KeyStore keystore, final String keyPass) { + Assert.notNull(keystore, "Key store is not defined."); + Assert.notNull(keyPass, "Password is not defined."); + + PrivateKey privateKey = null; + String element; + try { + final Enumeration enumeration = keystore.aliases(); + while (enumeration.hasMoreElements()) { + element = enumeration.nextElement(); + + privateKey = (PrivateKey) keystore.getKey(element, keyPass.toCharArray()); + if (privateKey != null) { + break; + } + } + } catch (final KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException ex) { + logger.error("Getting the private key from key store failed...", ex); + throw new ServiceConfigurationError("Getting the private key from key store failed...", ex); + } + + if (privateKey == null) { + throw new ServiceConfigurationError("Getting the private key failed, key store aliases do not identify a key."); + } + + return privateKey; + } + //------------------------------------------------------------------------------------------------- + public static PrivateKey getCloudPrivateKey(final KeyStore keystore, final String alias, final String keyPass) { + Assert.notNull(keystore, "Key store is not defined."); + Assert.notNull(keyPass, "Password is not defined."); + + try { + // TODO issue: the cloud common name is not the alias in debian installation with own certificates + PrivateKey privateKey = (PrivateKey) keystore.getKey(alias, keyPass.toCharArray()); + if (privateKey != null) { + return privateKey; + } else { + return getCloudPrivateKey(keystore, keyPass); + // throw new ServiceConfigurationError("Getting the private key failed, key store aliases do not identify a key."); + } + } catch (final KeyStoreException | UnrecoverableKeyException | NoSuchAlgorithmException ex) { + logger.error("Getting the private key from key store failed...", ex); + throw new ServiceConfigurationError("Getting the private key from key store failed...", ex); + } + } + + //------------------------------------------------------------------------------------------------- + public static PublicKey getPublicKeyFromBase64EncodedString(final String encodedKey) { + Assert.isTrue(!isEmpty(encodedKey), "Encoded key is null or blank"); + + final byte[] keyBytes = Base64.getDecoder().decode(encodedKey); + return generatePublicKeyFromByteArray(keyBytes); + } + + //------------------------------------------------------------------------------------------------- + public static PublicKey getPublicKeyFromPEMFile(final InputStream is) { + Assert.notNull(is, "Input stream is null"); + try { + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + final byte[] buf = new byte[1024]; + for (int read = 0; read != -1; read = is.read(buf)) { + baos.write(buf, 0, read); + } + + final String pem = new String(baos.toByteArray(), StandardCharsets.ISO_8859_1); + baos.close(); + final String encoded = PEM_PATTERN.matcher(pem).replaceFirst("$1"); + final byte[] keyBytes = Base64.getMimeDecoder().decode(encoded); + + return generatePublicKeyFromByteArray(keyBytes); + } catch (final IOException ex) { + throw new ArrowheadException("IOException occurred during PEM file loading from input stream.", ex); + } + } + + //------------------------------------------------------------------------------------------------- + public static boolean isKeyStoreCNArrowheadValid(final String commonName) { + if (isEmpty(commonName)) { + return false; + } + final String[] cnFields = commonName.split("\\.", 0); return cnFields.length == SERVICE_CN_NAME_LENGTH && cnFields[cnFields.length - 1].equals(AH_MASTER_SUFFIX) && cnFields[cnFields.length - 2].equals(AH_MASTER_NAME); } @@ -483,8 +606,42 @@ public static void createExceptionFromErrorMessageDTO(final ErrorMessageDTO dto) logger.error("Unknown exception type: {}", dto.getExceptionType()); throw new ArrowheadException(dto.getErrorMessage(), dto.getErrorCode(), dto.getOrigin()); } - } - + } + + //------------------------------------------------------------------------------------------------- + public static String lowerCaseTrim(final String text) { + if (isEmpty(text)) { + return text; + } + + return text.toLowerCase().trim(); + } + + //------------------------------------------------------------------------------------------------- + public static String firstNotNullIfExists(final String first, final String second) { + return Utilities.notEmpty(first) ? first : second; + } + + //------------------------------------------------------------------------------------------------- + @SuppressWarnings("unchecked") + public static T firstNotNullIfExists(final T first, final T second) { + if (first instanceof String && second instanceof String) { + return (T) firstNotNullIfExists((String) first, (String) second); + } + return Objects.nonNull(first) ? first : second; + } + + //------------------------------------------------------------------------------------------------- + public static String firstNotNullIfExists(final String... args) { + for (final String candidate : args) { + if (Utilities.notEmpty(candidate)) { + return candidate; + } + } + + return null; + } + //================================================================================================= // assistant methods @@ -502,4 +659,18 @@ private static PublicKey generatePublicKeyFromByteArray(final byte[] keyBytes) { throw new AuthException("Public key decoding failed due wrong input key", ex); } } -} \ No newline at end of file + + private static boolean isCloudCertificate(final X509Certificate certificate) + { + final String commonName = getCertCNFromSubject(certificate.getSubjectDN().getName()); + Assert.notNull(commonName, "Certificate without commonName is not allowed"); + final String[] cnParts = commonName.split("\\."); + return (cnParts.length == 4 && cnParts[2].equals(AH_MASTER_NAME) && cnParts[3].equals(AH_MASTER_SUFFIX)); + } + + public static boolean isValidMacAddress(final String macAddress) { + Assert.notNull(macAddress, "MAC address must not be null"); + final Matcher matcher = MAC_ADDRESS_PATTERN.matcher(macAddress); + return matcher.matches(); + } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/core/CoreSystem.java b/core-common/src/main/java/eu/arrowhead/common/core/CoreSystem.java index 4e39afa2a..70401cc84 100644 --- a/core-common/src/main/java/eu/arrowhead/common/core/CoreSystem.java +++ b/core-common/src/main/java/eu/arrowhead/common/core/CoreSystem.java @@ -1,40 +1,63 @@ package eu.arrowhead.common.core; +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.Defaults; +import org.springframework.util.Assert; + import java.util.Collections; import java.util.List; -import org.springframework.util.Assert; - -import eu.arrowhead.common.CommonConstants; -import eu.arrowhead.common.Defaults; +import static eu.arrowhead.common.core.CoreSystemService.DEVICE_REGISTRY_ONBOARDING_WITH_NAME_SERVICE; +import static eu.arrowhead.common.core.CoreSystemService.DEVICE_REGISTRY_REGISTER_SERVICE; +import static eu.arrowhead.common.core.CoreSystemService.DEVICE_REGISTRY_ONBOARDING_WITH_CSR_SERVICE; +import static eu.arrowhead.common.core.CoreSystemService.DEVICE_REGISTRY_UNREGISTER_SERVICE; +import static eu.arrowhead.common.core.CoreSystemService.ONBOARDING_WITH_CERTIFICATE_AND_CSR_SERVICE; +import static eu.arrowhead.common.core.CoreSystemService.ONBOARDING_WITH_CERTIFICATE_AND_NAME_SERVICE; +import static eu.arrowhead.common.core.CoreSystemService.ONBOARDING_WITH_SHARED_SECRET_AND_CSR_SERVICE; +import static eu.arrowhead.common.core.CoreSystemService.ONBOARDING_WITH_SHARED_SECRET_AND_NAME_SERVICE; +import static eu.arrowhead.common.core.CoreSystemService.SERVICE_REGISTRY_REGISTER_SERVICE; +import static eu.arrowhead.common.core.CoreSystemService.SERVICE_REGISTRY_UNREGISTER_SERVICE; +import static eu.arrowhead.common.core.CoreSystemService.SYSTEM_REGISTRY_ONBOARDING_WITH_CSR_SERVICE; +import static eu.arrowhead.common.core.CoreSystemService.SYSTEM_REGISTRY_ONBOARDING_WITH_NAME_SERVICE; +import static eu.arrowhead.common.core.CoreSystemService.SYSTEM_REGISTRY_REGISTER_SERVICE; +import static eu.arrowhead.common.core.CoreSystemService.SYSTEM_REGISTRY_UNREGISTER_SERVICE; public enum CoreSystem { - - //================================================================================================= - // elements - - SERVICE_REGISTRY(Defaults.DEFAULT_SERVICE_REGISTRY_PORT, null), - AUTHORIZATION(Defaults.DEFAULT_AUTHORIZATION_PORT, List.of(CoreSystemService.AUTH_CONTROL_INTRA_SERVICE, CoreSystemService.AUTH_CONTROL_INTER_SERVICE, - CoreSystemService.AUTH_TOKEN_GENERATION_SERVICE, CoreSystemService.AUTH_PUBLIC_KEY_SERVICE, - CoreSystemService.AUTH_CONTROL_SUBSCRIPTION_SERVICE)), - ORCHESTRATOR(Defaults.DEFAULT_ORCHESTRATOR_PORT, List.of(CoreSystemService.ORCHESTRATION_SERVICE)), - GATEKEEPER(Defaults.DEFAULT_GATEKEEPER_PORT, List.of(CoreSystemService.GATEKEEPER_GLOBAL_SERVICE_DISCOVERY, CoreSystemService.GATEKEEPER_INTER_CLOUD_NEGOTIATION)), - EVENT_HANDLER(Defaults.DEFAULT_EVENT_HANDLER_PORT, List.of(CoreSystemService.EVENT_PUBLISH_SERVICE, CoreSystemService.EVENT_SUBSCRIBE_SERVICE - , CoreSystemService.EVENT_UNSUBSCRIBE_SERVICE, CoreSystemService.EVENT_PUBLISH_AUTH_UPDATE_SERVICE)), - GATEWAY(Defaults.DEFAULT_GATEWAY_PORT, List.of(CoreSystemService.GATEWAY_PUBLIC_KEY_SERVICE, CoreSystemService.GATEWAY_PROVIDER_SERVICE,CoreSystemService.GATEWAY_CONSUMER_SERVICE)), - CHOREOGRAPHER(Defaults.DEFAULT_CHOREOGRAPHER_PORT, List.of()), // TODO: add services - CERTIFICATE_AUTHORITY(Defaults.DEFAULT_CERTIFICATE_AUTHORITY_PORT, List.of()); // TODO: add services - - //================================================================================================= - // members - - private final int defaultPort; - private final List services; - - //================================================================================================= - // methods - - //------------------------------------------------------------------------------------------------- + + //================================================================================================= + // elements + + SERVICE_REGISTRY(Defaults.DEFAULT_SERVICE_REGISTRY_PORT, List.of(SERVICE_REGISTRY_REGISTER_SERVICE, SERVICE_REGISTRY_UNREGISTER_SERVICE)), + SYSTEM_REGISTRY(Defaults.DEFAULT_SYSTEM_REGISTRY_PORT, List.of(SYSTEM_REGISTRY_REGISTER_SERVICE, SYSTEM_REGISTRY_UNREGISTER_SERVICE, + SYSTEM_REGISTRY_ONBOARDING_WITH_NAME_SERVICE, SYSTEM_REGISTRY_ONBOARDING_WITH_CSR_SERVICE)), + DEVICE_REGISTRY(Defaults.DEFAULT_DEVICE_REGISTRY_PORT, List.of(DEVICE_REGISTRY_REGISTER_SERVICE, DEVICE_REGISTRY_UNREGISTER_SERVICE, + DEVICE_REGISTRY_ONBOARDING_WITH_NAME_SERVICE, DEVICE_REGISTRY_ONBOARDING_WITH_CSR_SERVICE)), + ONBOARDING_CONTROLLER(Defaults.DEFAULT_ONBOARDING_PORT, List.of(ONBOARDING_WITH_CERTIFICATE_AND_NAME_SERVICE, + ONBOARDING_WITH_SHARED_SECRET_AND_NAME_SERVICE, + ONBOARDING_WITH_CERTIFICATE_AND_CSR_SERVICE, + ONBOARDING_WITH_SHARED_SECRET_AND_CSR_SERVICE)), + AUTHORIZATION(Defaults.DEFAULT_AUTHORIZATION_PORT, List.of(CoreSystemService.AUTH_CONTROL_INTRA_SERVICE, CoreSystemService.AUTH_CONTROL_INTER_SERVICE, + CoreSystemService.AUTH_TOKEN_GENERATION_SERVICE, CoreSystemService.AUTH_PUBLIC_KEY_SERVICE, + CoreSystemService.AUTH_CONTROL_SUBSCRIPTION_SERVICE)), + ORCHESTRATOR(Defaults.DEFAULT_ORCHESTRATOR_PORT, List.of(CoreSystemService.ORCHESTRATION_SERVICE)), + GATEKEEPER(Defaults.DEFAULT_GATEKEEPER_PORT, List.of(CoreSystemService.GATEKEEPER_GLOBAL_SERVICE_DISCOVERY, CoreSystemService.GATEKEEPER_INTER_CLOUD_NEGOTIATION)), + EVENT_HANDLER(Defaults.DEFAULT_EVENT_HANDLER_PORT, List.of(CoreSystemService.EVENT_PUBLISH_SERVICE, CoreSystemService.EVENT_SUBSCRIBE_SERVICE + , CoreSystemService.EVENT_UNSUBSCRIBE_SERVICE, CoreSystemService.EVENT_PUBLISH_AUTH_UPDATE_SERVICE)), + GATEWAY(Defaults.DEFAULT_GATEWAY_PORT, List.of(CoreSystemService.GATEWAY_PUBLIC_KEY_SERVICE, CoreSystemService.GATEWAY_PROVIDER_SERVICE, CoreSystemService.GATEWAY_CONSUMER_SERVICE)), + CHOREOGRAPHER(Defaults.DEFAULT_CHOREOGRAPHER_PORT, List.of()), // TODO: add services + QOS_MONITOR(Defaults.DEFAULT_QOS_MONITOR_PORT, List.of(CoreSystemService.QOS_MONITOR_PING_MEASUREMENT_SERVICE)), + CERTIFICATE_AUTHORITY(Defaults.DEFAULT_CERTIFICATE_AUTHORITY_PORT, List.of(CoreSystemService.CERTIFICATE_AUTHORITY_SIGN_SERVICE)); + + //================================================================================================= + // members + + private final int defaultPort; + private final List services; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- public int getDefaultPort() { return defaultPort; } public List getServices() { return services; } @@ -47,4 +70,4 @@ private CoreSystem(final int defaultPort, final List services this.services = services != null ? Collections.unmodifiableList(services) : List.of(); this.defaultPort = defaultPort; } -} \ No newline at end of file +} diff --git a/core-common/src/main/java/eu/arrowhead/common/core/CoreSystemService.java b/core-common/src/main/java/eu/arrowhead/common/core/CoreSystemService.java index 39f6db738..182bec23a 100644 --- a/core-common/src/main/java/eu/arrowhead/common/core/CoreSystemService.java +++ b/core-common/src/main/java/eu/arrowhead/common/core/CoreSystemService.java @@ -1,62 +1,174 @@ package eu.arrowhead.common.core; +import eu.arrowhead.common.Utilities; import org.springframework.util.Assert; -import eu.arrowhead.common.CommonConstants; -import eu.arrowhead.common.Utilities; +import static eu.arrowhead.common.CommonConstants.AUTHORIZATION_URI; +import static eu.arrowhead.common.CommonConstants.CERTIFICATE_AUTHRORITY_URI; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_AUTH_CONTROL_INTER; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_AUTH_CONTROL_INTRA; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_AUTH_CONTROL_SUBSCRIPTION; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_AUTH_PUBLIC_KEY; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_AUTH_TOKEN_GENERATION; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_CERTIFICATE_AUTHORITY_SIGN; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_DEVICE_REGISTRY_ONBOARDING_WITH_CSR; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_DEVICE_REGISTRY_ONBOARDING_WITH_NAME; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_DEVICE_REGISTRY_REGISTER; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_DEVICE_REGISTRY_UNREGISTER; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_EVENT_HANDLER_PUBLISH; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_EVENT_HANDLER_PUBLISH_AUTH_UPDATE; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_EVENT_HANDLER_SUBSCRIBE; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_EVENT_HANDLER_UNSUBSCRIBE; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_GATEKEEPER_GSD; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_GATEKEEPER_ICN; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_GATEWAY_CONNECT_CONSUMER; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_GATEWAY_CONNECT_PROVIDER; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_GATEWAY_PUBLIC_KEY; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_ONBOARDING_WITH_CERTIFICATE_AND_CSR; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_ONBOARDING_WITH_CERTIFICATE_AND_NAME; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_ONBOARDING_WITH_SHARED_SECRET_AND_CSR; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_ONBOARDING_WITH_SHARED_SECRET_AND_NAME; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_ORCH_PROCESS; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_QOS_MONITOR_PING_MEASUREMENT; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_SERVICE_REGISTRY_REGISTER; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_SERVICE_REGISTRY_UNREGISTER; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_SYSTEM_REGISTRY_ONBOARDING_WITH_CSR; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_SYSTEM_REGISTRY_ONBOARDING_WITH_NAME; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_SYSTEM_REGISTRY_REGISTER; +import static eu.arrowhead.common.CommonConstants.CORE_SERVICE_SYSTEM_REGISTRY_UNREGISTER; +import static eu.arrowhead.common.CommonConstants.DEVICE_REGISTRY_URI; +import static eu.arrowhead.common.CommonConstants.EVENT_HANDLER_URI; +import static eu.arrowhead.common.CommonConstants.GATEKEEPER_URI; +import static eu.arrowhead.common.CommonConstants.GATEWAY_URI; +import static eu.arrowhead.common.CommonConstants.ONBOARDING_URI; +import static eu.arrowhead.common.CommonConstants.OP_AUTH_INTER_CHECK_URI; +import static eu.arrowhead.common.CommonConstants.OP_AUTH_INTRA_CHECK_URI; +import static eu.arrowhead.common.CommonConstants.OP_AUTH_KEY_URI; +import static eu.arrowhead.common.CommonConstants.OP_AUTH_SUBSCRIPTION_CHECK_URI; +import static eu.arrowhead.common.CommonConstants.OP_AUTH_TOKEN_URI; +import static eu.arrowhead.common.CommonConstants.OP_CA_SIGN_CERTIFICATE_URI; +import static eu.arrowhead.common.CommonConstants.OP_DEVICE_REGISTRY_ONBOARDING_WITH_CSR_URI; +import static eu.arrowhead.common.CommonConstants.OP_DEVICE_REGISTRY_ONBOARDING_WITH_NAME_URI; +import static eu.arrowhead.common.CommonConstants.OP_DEVICE_REGISTRY_REGISTER_URI; +import static eu.arrowhead.common.CommonConstants.OP_DEVICE_REGISTRY_UNREGISTER_URI; +import static eu.arrowhead.common.CommonConstants.OP_EVENT_HANDLER_PUBLISH; +import static eu.arrowhead.common.CommonConstants.OP_EVENT_HANDLER_PUBLISH_AUTH_UPDATE; +import static eu.arrowhead.common.CommonConstants.OP_EVENT_HANDLER_SUBSCRIBE; +import static eu.arrowhead.common.CommonConstants.OP_EVENT_HANDLER_UNSUBSCRIBE; +import static eu.arrowhead.common.CommonConstants.OP_GATEKEEPER_GSD_SERVICE; +import static eu.arrowhead.common.CommonConstants.OP_GATEKEEPER_ICN_SERVICE; +import static eu.arrowhead.common.CommonConstants.OP_GATEWAY_CONNECT_CONSUMER_URI; +import static eu.arrowhead.common.CommonConstants.OP_GATEWAY_CONNECT_PROVIDER_URI; +import static eu.arrowhead.common.CommonConstants.OP_GATEWAY_KEY_URI; +import static eu.arrowhead.common.CommonConstants.OP_ONBOARDING_WITH_CERTIFICATE_AND_CSR; +import static eu.arrowhead.common.CommonConstants.OP_ONBOARDING_WITH_CERTIFICATE_AND_NAME; +import static eu.arrowhead.common.CommonConstants.OP_ONBOARDING_WITH_SHARED_SECRET_AND_CSR; +import static eu.arrowhead.common.CommonConstants.OP_ONBOARDING_WITH_SHARED_SECRET_AND_NAME; +import static eu.arrowhead.common.CommonConstants.OP_ORCH_PROCESS; +import static eu.arrowhead.common.CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT; +import static eu.arrowhead.common.CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT_SUFFIX; +import static eu.arrowhead.common.CommonConstants.OP_SERVICE_REGISTRY_REGISTER_URI; +import static eu.arrowhead.common.CommonConstants.OP_SERVICE_REGISTRY_UNREGISTER_URI; +import static eu.arrowhead.common.CommonConstants.OP_SYSTEM_REGISTRY_ONBOARDING_WITH_CSR_URI; +import static eu.arrowhead.common.CommonConstants.OP_SYSTEM_REGISTRY_ONBOARDING_WITH_NAME_URI; +import static eu.arrowhead.common.CommonConstants.OP_SYSTEM_REGISTRY_REGISTER_URI; +import static eu.arrowhead.common.CommonConstants.OP_SYSTEM_REGISTRY_UNREGISTER_URI; +import static eu.arrowhead.common.CommonConstants.ORCHESTRATOR_URI; +import static eu.arrowhead.common.CommonConstants.QOS_MONITOR_URI; +import static eu.arrowhead.common.CommonConstants.SERVICE_REGISTRY_URI; +import static eu.arrowhead.common.CommonConstants.SYSTEM_REGISTRY_URI; public enum CoreSystemService { - //================================================================================================= - // elements - - // Authorization services - AUTH_CONTROL_INTRA_SERVICE(CommonConstants.CORE_SERVICE_AUTH_CONTROL_INTRA, CommonConstants.AUTHORIZATION_URI + CommonConstants.OP_AUTH_INTRA_CHECK_URI), - AUTH_CONTROL_INTER_SERVICE(CommonConstants.CORE_SERVICE_AUTH_CONTROL_INTER, CommonConstants.AUTHORIZATION_URI + CommonConstants.OP_AUTH_INTER_CHECK_URI), - AUTH_TOKEN_GENERATION_SERVICE(CommonConstants.CORE_SERVICE_AUTH_TOKEN_GENERATION, CommonConstants.AUTHORIZATION_URI + CommonConstants.OP_AUTH_TOKEN_URI), - AUTH_PUBLIC_KEY_SERVICE(CommonConstants.CORE_SERVICE_AUTH_PUBLIC_KEY, CommonConstants.AUTHORIZATION_URI + CommonConstants.OP_AUTH_KEY_URI), - AUTH_CONTROL_SUBSCRIPTION_SERVICE(CommonConstants.CORE_SERVICE_AUTH_CONTROL_SUBSCRIPTION, CommonConstants.AUTHORIZATION_URI + CommonConstants.OP_AUTH_SUBSCRIPTION_CHECK_URI), - - // Orchestrator services - ORCHESTRATION_SERVICE(CommonConstants.CORE_SERVICE_ORCH_PROCESS, CommonConstants.ORCHESTRATOR_URI + CommonConstants.OP_ORCH_PROCESS), - - // Gatekeeper services - GATEKEEPER_GLOBAL_SERVICE_DISCOVERY(CommonConstants.CORE_SERVICE_GATEKEEPER_GSD, CommonConstants.GATEKEEPER_URI + CommonConstants.OP_GATEKEEPER_GSD_SERVICE), - GATEKEEPER_INTER_CLOUD_NEGOTIATION(CommonConstants.CORE_SERVICE_GATEKEEPER_ICN, CommonConstants.GATEKEEPER_URI + CommonConstants.OP_GATEKEEPER_ICN_SERVICE), - - // Gateway services - GATEWAY_PUBLIC_KEY_SERVICE(CommonConstants.CORE_SERVICE_GATEWAY_PUBLIC_KEY, CommonConstants.GATEWAY_URI + CommonConstants.OP_GATEWAY_KEY_URI), - GATEWAY_PROVIDER_SERVICE(CommonConstants.CORE_SERVICE_GATEWAY_CONNECT_PROVIDER, CommonConstants.GATEWAY_URI + CommonConstants.OP_GATEWAY_CONNECT_PROVIDER_URI), - GATEWAY_CONSUMER_SERVICE(CommonConstants.CORE_SERVICE_GATEWAY_CONNECT_CONSUMER, CommonConstants.GATEWAY_URI + CommonConstants.OP_GATEWAY_CONNECT_CONSUMER_URI), - - //Eventhandler services - EVENT_PUBLISH_SERVICE(CommonConstants.CORE_SERVICE_EVENT_HANDLER_PUBLISH, CommonConstants.EVENT_HANDLER_URI + CommonConstants.OP_EVENT_HANDLER_PUBLISH), - EVENT_SUBSCRIBE_SERVICE(CommonConstants.CORE_SERVICE_EVENT_HANDLER_SUBSCRIBE, CommonConstants.EVENT_HANDLER_URI + CommonConstants.OP_EVENT_HANDLER_SUBSCRIBE), - EVENT_UNSUBSCRIBE_SERVICE(CommonConstants.CORE_SERVICE_EVENT_HANDLER_UNSUBSCRIBE, CommonConstants.EVENT_HANDLER_URI + CommonConstants.OP_EVENT_HANDLER_UNSUBSCRIBE), - EVENT_PUBLISH_AUTH_UPDATE_SERVICE(CommonConstants.CORE_SERVICE_EVENT_HANDLER_PUBLISH_AUTH_UPDATE, CommonConstants.EVENT_HANDLER_URI + CommonConstants.OP_EVENT_HANDLER_PUBLISH_AUTH_UPDATE); - - //TODO: additional services - - //================================================================================================= - // members - - private final String serviceDefinition; - private final String serviceUri; - - //================================================================================================= - // methods - - //------------------------------------------------------------------------------------------------- - public String getServiceDefinition() { return serviceDefinition; } - public String getServiceUri() { return serviceUri; } - - - //================================================================================================= - // assistant methods + //================================================================================================= + // elements + + // Authorization services + AUTH_CONTROL_INTRA_SERVICE(CORE_SERVICE_AUTH_CONTROL_INTRA, AUTHORIZATION_URI + OP_AUTH_INTRA_CHECK_URI), + AUTH_CONTROL_INTER_SERVICE(CORE_SERVICE_AUTH_CONTROL_INTER, AUTHORIZATION_URI + OP_AUTH_INTER_CHECK_URI), + AUTH_TOKEN_GENERATION_SERVICE(CORE_SERVICE_AUTH_TOKEN_GENERATION, AUTHORIZATION_URI + OP_AUTH_TOKEN_URI), + AUTH_PUBLIC_KEY_SERVICE(CORE_SERVICE_AUTH_PUBLIC_KEY, AUTHORIZATION_URI + OP_AUTH_KEY_URI), + AUTH_CONTROL_SUBSCRIPTION_SERVICE(CORE_SERVICE_AUTH_CONTROL_SUBSCRIPTION, AUTHORIZATION_URI + OP_AUTH_SUBSCRIPTION_CHECK_URI), + + // Orchestrator services + ORCHESTRATION_SERVICE(CORE_SERVICE_ORCH_PROCESS, + ORCHESTRATOR_URI + OP_ORCH_PROCESS), + + // Gatekeeper services + GATEKEEPER_GLOBAL_SERVICE_DISCOVERY(CORE_SERVICE_GATEKEEPER_GSD, GATEKEEPER_URI + OP_GATEKEEPER_GSD_SERVICE), + GATEKEEPER_INTER_CLOUD_NEGOTIATION(CORE_SERVICE_GATEKEEPER_ICN, GATEKEEPER_URI + OP_GATEKEEPER_ICN_SERVICE), + + // Gateway services + GATEWAY_PUBLIC_KEY_SERVICE(CORE_SERVICE_GATEWAY_PUBLIC_KEY, GATEWAY_URI + OP_GATEWAY_KEY_URI), + GATEWAY_PROVIDER_SERVICE(CORE_SERVICE_GATEWAY_CONNECT_PROVIDER, GATEWAY_URI + OP_GATEWAY_CONNECT_PROVIDER_URI), + GATEWAY_CONSUMER_SERVICE(CORE_SERVICE_GATEWAY_CONNECT_CONSUMER, GATEWAY_URI + OP_GATEWAY_CONNECT_CONSUMER_URI), + + // Eventhandler services + EVENT_PUBLISH_SERVICE(CORE_SERVICE_EVENT_HANDLER_PUBLISH, EVENT_HANDLER_URI + OP_EVENT_HANDLER_PUBLISH), + EVENT_SUBSCRIBE_SERVICE(CORE_SERVICE_EVENT_HANDLER_SUBSCRIBE, EVENT_HANDLER_URI + OP_EVENT_HANDLER_SUBSCRIBE), + EVENT_UNSUBSCRIBE_SERVICE(CORE_SERVICE_EVENT_HANDLER_UNSUBSCRIBE, EVENT_HANDLER_URI + OP_EVENT_HANDLER_UNSUBSCRIBE), + EVENT_PUBLISH_AUTH_UPDATE_SERVICE(CORE_SERVICE_EVENT_HANDLER_PUBLISH_AUTH_UPDATE, EVENT_HANDLER_URI + OP_EVENT_HANDLER_PUBLISH_AUTH_UPDATE), + + // CA services + CERTIFICATE_AUTHORITY_SIGN_SERVICE(CORE_SERVICE_CERTIFICATE_AUTHORITY_SIGN, CERTIFICATE_AUTHRORITY_URI + OP_CA_SIGN_CERTIFICATE_URI), + // QoS Monitor services + QOS_MONITOR_PING_MEASUREMENT_SERVICE(CORE_SERVICE_QOS_MONITOR_PING_MEASUREMENT, + QOS_MONITOR_URI + OP_QOS_MONITOR_PING_MEASUREMENT + OP_QOS_MONITOR_PING_MEASUREMENT_SUFFIX), + + // Onboarding services + ONBOARDING_WITH_CERTIFICATE_AND_NAME_SERVICE(CORE_SERVICE_ONBOARDING_WITH_CERTIFICATE_AND_NAME, ONBOARDING_URI + OP_ONBOARDING_WITH_CERTIFICATE_AND_NAME), + ONBOARDING_WITH_CERTIFICATE_AND_CSR_SERVICE(CORE_SERVICE_ONBOARDING_WITH_CERTIFICATE_AND_CSR, ONBOARDING_URI + OP_ONBOARDING_WITH_CERTIFICATE_AND_CSR), + ONBOARDING_WITH_SHARED_SECRET_AND_NAME_SERVICE(CORE_SERVICE_ONBOARDING_WITH_SHARED_SECRET_AND_NAME, ONBOARDING_URI + OP_ONBOARDING_WITH_SHARED_SECRET_AND_NAME), + ONBOARDING_WITH_SHARED_SECRET_AND_CSR_SERVICE(CORE_SERVICE_ONBOARDING_WITH_SHARED_SECRET_AND_CSR, ONBOARDING_URI + OP_ONBOARDING_WITH_SHARED_SECRET_AND_CSR), + + // Device Registry services + DEVICE_REGISTRY_REGISTER_SERVICE(CORE_SERVICE_DEVICE_REGISTRY_REGISTER, DEVICE_REGISTRY_URI + OP_DEVICE_REGISTRY_REGISTER_URI), + DEVICE_REGISTRY_UNREGISTER_SERVICE(CORE_SERVICE_DEVICE_REGISTRY_UNREGISTER, DEVICE_REGISTRY_URI + OP_DEVICE_REGISTRY_UNREGISTER_URI), + DEVICE_REGISTRY_ONBOARDING_WITH_NAME_SERVICE(CORE_SERVICE_DEVICE_REGISTRY_ONBOARDING_WITH_NAME, + DEVICE_REGISTRY_URI + ONBOARDING_URI + OP_DEVICE_REGISTRY_ONBOARDING_WITH_NAME_URI), + DEVICE_REGISTRY_ONBOARDING_WITH_CSR_SERVICE(CORE_SERVICE_DEVICE_REGISTRY_ONBOARDING_WITH_CSR, + DEVICE_REGISTRY_URI + ONBOARDING_URI + OP_DEVICE_REGISTRY_ONBOARDING_WITH_CSR_URI), + + // System Registry services + SYSTEM_REGISTRY_REGISTER_SERVICE(CORE_SERVICE_SYSTEM_REGISTRY_REGISTER, SYSTEM_REGISTRY_URI + OP_SYSTEM_REGISTRY_REGISTER_URI), + SYSTEM_REGISTRY_UNREGISTER_SERVICE(CORE_SERVICE_SYSTEM_REGISTRY_UNREGISTER, SYSTEM_REGISTRY_URI + OP_SYSTEM_REGISTRY_UNREGISTER_URI), + SYSTEM_REGISTRY_ONBOARDING_WITH_NAME_SERVICE(CORE_SERVICE_SYSTEM_REGISTRY_ONBOARDING_WITH_NAME, + SYSTEM_REGISTRY_URI + ONBOARDING_URI + OP_SYSTEM_REGISTRY_ONBOARDING_WITH_NAME_URI), + SYSTEM_REGISTRY_ONBOARDING_WITH_CSR_SERVICE(CORE_SERVICE_SYSTEM_REGISTRY_ONBOARDING_WITH_CSR, + SYSTEM_REGISTRY_URI + ONBOARDING_URI + OP_SYSTEM_REGISTRY_ONBOARDING_WITH_CSR_URI), + + // Service Registry services + SERVICE_REGISTRY_REGISTER_SERVICE(CORE_SERVICE_SERVICE_REGISTRY_REGISTER, SERVICE_REGISTRY_URI + OP_SERVICE_REGISTRY_REGISTER_URI), + SERVICE_REGISTRY_UNREGISTER_SERVICE(CORE_SERVICE_SERVICE_REGISTRY_UNREGISTER, SERVICE_REGISTRY_URI + OP_SERVICE_REGISTRY_UNREGISTER_URI); + + //TODO: additional services + + //================================================================================================= + // members + + private final String serviceDefinition; + private final String serviceUri; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public String getServiceDefinition() { + return serviceDefinition; + } + + public String getServiceUri() { + return serviceUri; + } + + + //================================================================================================= + // constructors //------------------------------------------------------------------------------------------------- private CoreSystemService(final String serviceDefinition, final String serviceUri) { - Assert.isTrue(!Utilities.isEmpty(serviceDefinition), serviceUri); + Assert.isTrue(!Utilities.isEmpty(serviceDefinition), "Service definition is null or blank"); + Assert.isTrue(!Utilities.isEmpty(serviceUri), "Service URI is null or blank"); this.serviceDefinition = serviceDefinition; this.serviceUri = serviceUri; diff --git a/core-common/src/main/java/eu/arrowhead/common/database/entity/AuthorizationInterCloud.java b/core-common/src/main/java/eu/arrowhead/common/database/entity/AuthorizationInterCloud.java index c54e1dbc1..b448cff6c 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/entity/AuthorizationInterCloud.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/entity/AuthorizationInterCloud.java @@ -25,12 +25,12 @@ @Entity @Table(uniqueConstraints = @UniqueConstraint(columnNames = {"consumerCloudId", "providerSystemId", "serviceId"})) public class AuthorizationInterCloud { - - public static final List SORTABLE_FIELDS_BY = List.of("id", "updatedAt", "createdAt"); //NOSONAR //================================================================================================= // members + public static final List SORTABLE_FIELDS_BY = List.of("id", "updatedAt", "createdAt"); //NOSONAR + @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private long id; diff --git a/core-common/src/main/java/eu/arrowhead/common/database/entity/Device.java b/core-common/src/main/java/eu/arrowhead/common/database/entity/Device.java new file mode 100644 index 000000000..c1ecf6bc6 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/entity/Device.java @@ -0,0 +1,131 @@ +package eu.arrowhead.common.database.entity; + +import eu.arrowhead.common.CoreDefaults; +import org.hibernate.annotations.OnDelete; +import org.hibernate.annotations.OnDeleteAction; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.OneToMany; +import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; +import java.time.ZonedDateTime; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +@Entity +@Table(name = "device", uniqueConstraints = @UniqueConstraint(columnNames = { "deviceName", "macAddress" })) +@NamedEntityGraph(name = "deviceWithSystemRegistryEntries", + attributeNodes = { + @NamedAttributeNode(value = "systemRegistryEntries") +}) +public class Device +{ + + //================================================================================================= + // members + + public static final List SORTABLE_FIELDS_BY = List.of("id", "updatedAt", "createdAt", "deviceName", "address"); //NOSONAR + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(nullable = false, length = CoreDefaults.VARCHAR_BASIC) + private String deviceName; + + @Column(nullable = false, length = CoreDefaults.VARCHAR_BASIC) + private String address; + + @Column(nullable = false, unique = true, length = CoreDefaults.VARCHAR_BASIC) + private String macAddress; + + @Column(nullable = true, length = CoreDefaults.VARCHAR_EXTENDED) + private String authenticationInfo; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private ZonedDateTime createdAt; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") + private ZonedDateTime updatedAt; + + @OneToMany(mappedBy = "device", fetch = FetchType.LAZY, orphanRemoval = true) + @OnDelete(action = OnDeleteAction.CASCADE) + private Set systemRegistryEntries = new HashSet<>(); + + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public Device() {} + + //------------------------------------------------------------------------------------------------- + public Device(final String deviceName, final String address, final String macAddress, final String authenticationInfo) { + this.deviceName = deviceName; + this.address = address; + this.macAddress = macAddress; + this.authenticationInfo = authenticationInfo; + } + + public Device(final long id, final String deviceName, final String address, final String macAddress, final String authenticationInfo, + final ZonedDateTime createdAt, final ZonedDateTime updatedAt, final Set systemRegistryEntries) { + this.id = id; + this.deviceName = deviceName; + this.address = address; + this.macAddress = macAddress; + this.authenticationInfo = authenticationInfo; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + this.systemRegistryEntries = systemRegistryEntries; + } + + //------------------------------------------------------------------------------------------------- + @PrePersist + public void onCreate() { + this.createdAt = ZonedDateTime.now(); + this.updatedAt = this.createdAt; + } + + //------------------------------------------------------------------------------------------------- + @PreUpdate + public void onUpdate() { + this.updatedAt = ZonedDateTime.now(); + } + + //------------------------------------------------------------------------------------------------- + public long getId() { return id; } + public String getDeviceName() { return deviceName; } + public String getAddress() { return address; } + public String getMacAddress() {return macAddress; } + + public String getAuthenticationInfo() { return authenticationInfo; } + public ZonedDateTime getCreatedAt() { return createdAt; } + public ZonedDateTime getUpdatedAt() { return updatedAt; } + public Set getSystemRegistryEntries() { return systemRegistryEntries; } + + //------------------------------------------------------------------------------------------------- + public void setId(final long id) { this.id = id; } + public void setDeviceName(final String systemName) { this.deviceName = systemName; } + public void setAddress(final String address) { this.address = address; } + public void setMacAddress(final String macAddress) { this.macAddress = macAddress; } + public void setAuthenticationInfo(final String authenticationInfo) { this.authenticationInfo = authenticationInfo; } + public void setCreatedAt(final ZonedDateTime createdAt) { this.createdAt = createdAt; } + public void setUpdatedAt(final ZonedDateTime updatedAt) { this.updatedAt = updatedAt; } + public void setSystemRegistryEntries(final Set systemRegistryEntries) { this.systemRegistryEntries = systemRegistryEntries; } + + //------------------------------------------------------------------------------------------------- + @Override + public String toString() { + return "System [id = " + id + ", systemName = " + deviceName + ", address = " + address + ", macAddress = " + macAddress + "]"; + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/entity/DeviceRegistry.java b/core-common/src/main/java/eu/arrowhead/common/database/entity/DeviceRegistry.java new file mode 100644 index 000000000..bc11e3ef8 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/entity/DeviceRegistry.java @@ -0,0 +1,168 @@ +package eu.arrowhead.common.database.entity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Objects; + +@Entity +@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"deviceId"})) +public class DeviceRegistry { + + //================================================================================================= + // members + public static final List SORTABLE_FIELDS_BY = List.of("id", "updatedAt", "createdAt"); //NOSONAR + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "deviceId", referencedColumnName = "id", nullable = false) + private Device device; + + @Column(nullable = true) + private ZonedDateTime endOfValidity; + + @Column(nullable = true, columnDefinition = "TEXT") + private String metadata; + + @Column(nullable = true) + private Integer version = 1; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private ZonedDateTime createdAt; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") + private ZonedDateTime updatedAt; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public DeviceRegistry() { + } + + //------------------------------------------------------------------------------------------------- + public DeviceRegistry(final Device device, final ZonedDateTime endOfValidity, + final String metadata, final Integer version) { + this.device = device; + this.endOfValidity = endOfValidity; + this.metadata = metadata; + this.version = version; + } + + //------------------------------------------------------------------------------------------------- + @PrePersist + public void onCreate() { + this.createdAt = ZonedDateTime.now(); + this.updatedAt = this.createdAt; + } + + //------------------------------------------------------------------------------------------------- + @PreUpdate + public void onUpdate() { + this.updatedAt = ZonedDateTime.now(); + } + + //------------------------------------------------------------------------------------------------- + public long getId() { + return id; + } + + public Device getDevice() { + return device; + } + + public ZonedDateTime getEndOfValidity() { + return endOfValidity; + } + + public String getMetadata() { + return metadata; + } + + public Integer getVersion() { + return version; + } + + public ZonedDateTime getCreatedAt() { + return createdAt; + } + + public ZonedDateTime getUpdatedAt() { + return updatedAt; + } + + //------------------------------------------------------------------------------------------------- + public void setId(final long id) { + this.id = id; + } + + public void setDevice(final Device device) { + this.device = device; + } + + public void setEndOfValidity(final ZonedDateTime endOfValidity) { + this.endOfValidity = endOfValidity; + } + + public void setMetadata(final String metadata) { + this.metadata = metadata; + } + + public void setVersion(final Integer version) { + this.version = version; + } + + public void setCreatedAt(final ZonedDateTime createdAt) { + this.createdAt = createdAt; + } + + public void setUpdatedAt(final ZonedDateTime updatedAt) { + this.updatedAt = updatedAt; + } + + //------------------------------------------------------------------------------------------------- + @Override + public String toString() { + return "ServiceRegistry [id = " + id + ", device = " + device + ", endOfValidity = " + endOfValidity + ", version = " + version + "]"; + } + + //------------------------------------------------------------------------------------------------- + @Override + public int hashCode() { + return Objects.hash(id); + } + + //------------------------------------------------------------------------------------------------- + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + final DeviceRegistry other = (DeviceRegistry) obj; + + return id == other.id; + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSIntraMeasurement.java b/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSIntraMeasurement.java new file mode 100644 index 000000000..a6b3e40d3 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSIntraMeasurement.java @@ -0,0 +1,92 @@ +package eu.arrowhead.common.database.entity; + +import java.time.ZonedDateTime; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; + +import eu.arrowhead.common.CoreDefaults; +import eu.arrowhead.common.dto.shared.QoSMeasurementType; + +@Entity +@Table(name = "qos_intra_measurement", uniqueConstraints = @UniqueConstraint(columnNames = {"systemId", "measurementType"})) +public class QoSIntraMeasurement { + + //================================================================================================= + // members + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "systemId", referencedColumnName = "id", nullable = false) + private System system; + + @Column(nullable = false, columnDefinition = "varchar(" + CoreDefaults.VARCHAR_BASIC + ")") + @Enumerated(EnumType.STRING) + private QoSMeasurementType measurementType; + + @Column(nullable = false) + private ZonedDateTime lastMeasurementAt; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private ZonedDateTime createdAt; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") + private ZonedDateTime updatedAt; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public QoSIntraMeasurement() {} + + //------------------------------------------------------------------------------------------------- + public QoSIntraMeasurement(final System system, final QoSMeasurementType measurementType, final ZonedDateTime lastMeasurementAt) { + this.system = system; + this.measurementType = measurementType; + this.lastMeasurementAt = lastMeasurementAt; + } + + //------------------------------------------------------------------------------------------------- + @PrePersist + public void onCreate() { + this.createdAt = ZonedDateTime.now(); + this.updatedAt = this.createdAt; + } + + //------------------------------------------------------------------------------------------------- + @PreUpdate + public void onUpdate() { + this.updatedAt = ZonedDateTime.now(); + } + + //------------------------------------------------------------------------------------------------- + public long getId() { return id; } + public System getSystem() { return system; } + public QoSMeasurementType getMeasurementType() { return measurementType; } + public ZonedDateTime getLastMeasurementAt() { return lastMeasurementAt; } + public ZonedDateTime getCreatedAt() { return createdAt; } + public ZonedDateTime getUpdatedAt() { return updatedAt; } + + //------------------------------------------------------------------------------------------------- + public void setId(final long id) { this.id = id; } + public void setSystem(final System system) { this.system = system; } + public void setMeasurementType(final QoSMeasurementType measurementType) { this.measurementType = measurementType; } + public void setLastMeasurementAt(final ZonedDateTime lastMeasurementAt) { this.lastMeasurementAt = lastMeasurementAt; } + public void setCreatedAt(final ZonedDateTime createdAt) { this.createdAt = createdAt; } + public void setUpdatedAt(final ZonedDateTime updatedAt) { this.updatedAt = updatedAt; } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSIntraPingMeasurement.java b/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSIntraPingMeasurement.java new file mode 100644 index 000000000..f22cefd02 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSIntraPingMeasurement.java @@ -0,0 +1,141 @@ +package eu.arrowhead.common.database.entity; + +import java.time.ZonedDateTime; +import java.util.List; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; +import javax.persistence.Table; + +@Entity +@Table(name = "qos_intra_ping_measurement") +public class QoSIntraPingMeasurement { + + //================================================================================================= + // members + + public static final List SORTABLE_FIELDS_BY = List.of( "id", "updatedAt", "createdAt"); //NOSONAR + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "measurementId", referencedColumnName = "id", nullable = false, unique = true) + private QoSIntraMeasurement measurement; + + @Column(name = "available", nullable = false) + private boolean available = false; + + @Column(name = "last_access_at", nullable = true) + private ZonedDateTime lastAccessAt; + + @Column(name = "min_response_time", nullable = true) + private Integer minResponseTime; + + @Column(name = "max_response_time", nullable = true) + private Integer maxResponseTime; + + @Column(name = "mean_response_time_with_timeout", nullable = true) + private Integer meanResponseTimeWithTimeout; + + @Column(name = "mean_response_time_without_timeout", nullable = true) + private Integer meanResponseTimeWithoutTimeout; + + @Column(name = "jitter_with_timeout", nullable = true) + private Integer jitterWithTimeout; + + @Column(name = "jitter_without_timeout", nullable = true) + private Integer jitterWithoutTimeout; + + @Column(name = "lost_per_measurement_percent", nullable = false) + private Integer lostPerMeasurementPercent; + + @Column(name = "sent", nullable = false) + private long sent; + + @Column(name = "received", nullable = false) + private long received; + + @Column(name = "count_started_at", nullable = true) + private ZonedDateTime countStartedAt; + + @Column(name = "sent_all", nullable = false) + private long sentAll; + + @Column(name = "received_all", nullable = false) + private long receivedAll; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private ZonedDateTime createdAt; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") + private ZonedDateTime updatedAt; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public QoSIntraPingMeasurement() {} + + //------------------------------------------------------------------------------------------------- + @PrePersist + public void onCreate() { + this.createdAt = ZonedDateTime.now(); + this.updatedAt = this.createdAt; + } + + //------------------------------------------------------------------------------------------------- + @PreUpdate + public void onUpdate() { + this.updatedAt = ZonedDateTime.now(); + } + + //------------------------------------------------------------------------------------------------- + public long getId() { return id; } + public QoSIntraMeasurement getMeasurement() { return measurement; } + public boolean isAvailable() { return available; } + public ZonedDateTime getLastAccessAt() { return lastAccessAt; } + public Integer getMinResponseTime() { return minResponseTime; } + public Integer getMaxResponseTime() { return maxResponseTime; } + public Integer getMeanResponseTimeWithTimeout() { return meanResponseTimeWithTimeout; } + public Integer getMeanResponseTimeWithoutTimeout() { return meanResponseTimeWithoutTimeout; } + public Integer getJitterWithTimeout() {return jitterWithTimeout;} + public Integer getJitterWithoutTimeout() { return jitterWithoutTimeout; } + public Integer getLostPerMeasurementPercent() { return lostPerMeasurementPercent; } + public long getSent() { return sent; } + public long getReceived() { return received; } + public ZonedDateTime getCountStartedAt() { return countStartedAt; } + public long getSentAll() { return sentAll; } + public long getReceivedAll() { return receivedAll; } + public ZonedDateTime getCreatedAt() { return createdAt; } + public ZonedDateTime getUpdatedAt() { return updatedAt; } + + //------------------------------------------------------------------------------------------------- + public void setId(final long id) { this.id = id; } + public void setMeasurement(final QoSIntraMeasurement measurement) { this.measurement = measurement; } + public void setAvailable(final boolean available) { this.available = available; } + public void setLastAccessAt(final ZonedDateTime lastAccessAt) { this.lastAccessAt = lastAccessAt; } + public void setMinResponseTime(final Integer minResponseTime) { this.minResponseTime = minResponseTime; } + public void setMaxResponseTime(final Integer maxResponseTime) { this.maxResponseTime = maxResponseTime; } + public void setMeanResponseTimeWithoutTimeout(final Integer meanResponseTimeWithoutTimeout) { this.meanResponseTimeWithoutTimeout = meanResponseTimeWithoutTimeout; } + public void setMeanResponseTimeWithTimeout(final Integer meanResponseTimeWithTimeout) { this.meanResponseTimeWithTimeout = meanResponseTimeWithTimeout; } + public void setJitterWithTimeout(final Integer jitterWithTimeout) { this.jitterWithTimeout = jitterWithTimeout; } + public void setJitterWithoutTimeout(final Integer jitterWithoutTimeout) { this.jitterWithoutTimeout = jitterWithoutTimeout; } + public void setLostPerMeasurementPercent(final Integer lostPerMeasurementPercent) { this.lostPerMeasurementPercent = lostPerMeasurementPercent; } + public void setSent(final long sent) { this.sent = sent; } + public void setReceived(final long received) { this.received = received; } + public void setCountStartedAt(final ZonedDateTime countStartedAt) { this.countStartedAt = countStartedAt; } + public void setSentAll(final long sentAll) { this.sentAll = sentAll; } + public void setReceivedAll(final long receivedAll) { this.receivedAll = receivedAll; } + public void setCreatedAt(final ZonedDateTime createdAt) { this.createdAt = createdAt; } + public void setUpdatedAt(final ZonedDateTime updatedAt) { this.updatedAt = updatedAt; } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSIntraPingMeasurementLog.java b/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSIntraPingMeasurementLog.java new file mode 100644 index 000000000..d8a306891 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSIntraPingMeasurementLog.java @@ -0,0 +1,114 @@ +package eu.arrowhead.common.database.entity; + +import java.time.ZonedDateTime; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; +import javax.persistence.Table; + +@Entity +@Table(name = "qos_intra_ping_measurement_log") +public class QoSIntraPingMeasurementLog { + + //================================================================================================= + // members + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @Column(name = "measured_system_address", nullable = false) + private String measuredSystemAddress; + + @Column(name = "available", nullable = false) + private boolean available = false; + + @Column(name = "min_response_time", nullable = true) + private Integer minResponseTime; + + @Column(name = "max_response_time", nullable = true) + private Integer maxResponseTime; + + @Column(name = "mean_response_time_with_timeout", nullable = true) + private Integer meanResponseTimeWithTimeout; + + @Column(name = "mean_response_time_without_timeout", nullable = true) + private Integer meanResponseTimeWithoutTimeout; + + @Column(name = "jitter_with_timeout", nullable = true) + private Integer jitterWithTimeout; + + @Column(name = "jitter_without_timeout", nullable = true) + private Integer jitterWithoutTimeout; + + @Column(name = "lost_per_measurement_percent", nullable = false) + private Integer lostPerMeasurementPercent; + + @Column(name = "sent", nullable = false) + private long sent; + + @Column(name = "received", nullable = false) + private long received; + + @Column(name = "measured_at",nullable = false) + private ZonedDateTime measuredAt; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private ZonedDateTime createdAt; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") + private ZonedDateTime updatedAt; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public QoSIntraPingMeasurementLog() {} + + //------------------------------------------------------------------------------------------------- + @PrePersist + public void onCreate() { + this.createdAt = ZonedDateTime.now(); + this.updatedAt = this.createdAt; + } + + //------------------------------------------------------------------------------------------------- + @PreUpdate + public void onUpdate() { + this.updatedAt = ZonedDateTime.now(); + } + + //------------------------------------------------------------------------------------------------- + public String getMeasuredSystemAddress() { return measuredSystemAddress; } + public boolean isAvailable() { return available; } + public Integer getMinResponseTime() { return minResponseTime; } + public Integer getMaxResponseTime() { return maxResponseTime; } + public Integer getMeanResponseTimeWithTimeout() { return meanResponseTimeWithTimeout; } + public Integer getMeanResponseTimeWithoutTimeout() { return meanResponseTimeWithoutTimeout; } + public Integer getJitterWithTimeout() { return jitterWithTimeout; } + public Integer getJitterWithoutTimeout() { return jitterWithoutTimeout; } + public Integer getLostPerMeasurementPercent() { return lostPerMeasurementPercent; } + public long getSent() { return sent; } + public long getReceived() { return received; } + public ZonedDateTime getMeasuredAt() { return measuredAt; } + + //------------------------------------------------------------------------------------------------- + public void setMeasuredSystemAddress(final String measuredSystemAddress) { this.measuredSystemAddress = measuredSystemAddress; } + public void setAvailable(final boolean available) { this.available = available; } + public void setMinResponseTime(final Integer minResponseTime) { this.minResponseTime = minResponseTime; } + public void setMaxResponseTime(final Integer maxResponseTime) { this.maxResponseTime = maxResponseTime; } + public void setMeanResponseTimeWithTimeout(final Integer meanResponseTimeWithTimeout) { this.meanResponseTimeWithTimeout = meanResponseTimeWithTimeout; } + public void setMeanResponseTimeWithoutTimeout(final Integer meanResponseTimeWithoutTimeout) { this.meanResponseTimeWithoutTimeout = meanResponseTimeWithoutTimeout; } + public void setJitterWithTimeout(final Integer jitterWithTimeout) { this.jitterWithTimeout = jitterWithTimeout; } + public void setJitterWithoutTimeout(final Integer jitterWithoutTimeout) { this.jitterWithoutTimeout = jitterWithoutTimeout; } + public void setLostPerMeasurementPercent(final Integer lostPerMeasurementPercent) { this.lostPerMeasurementPercent = lostPerMeasurementPercent; } + public void setSent(final long sent) { this.sent = sent; } + public void setReceived(final long received) { this.received = received; } + public void setMeasuredAt(final ZonedDateTime measuredAt) { this.measuredAt = measuredAt; } + +} diff --git a/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSIntraPingMeasurementLogDetails.java b/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSIntraPingMeasurementLogDetails.java new file mode 100644 index 000000000..f19de5443 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSIntraPingMeasurementLogDetails.java @@ -0,0 +1,113 @@ +package eu.arrowhead.common.database.entity; + +import java.time.ZonedDateTime; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; +import javax.persistence.Table; + +@Entity +@Table(name = "qos_intra_ping_measurement_log_details") +public class QoSIntraPingMeasurementLogDetails { + + //================================================================================================= + // members + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "measurement_log_id", referencedColumnName = "id", nullable = false, unique = true) + private QoSIntraPingMeasurementLog measurementLog; + + @Column(name = "measurement_sequenece_number", nullable = false) + private int measurementSequeneceNumber; + + @Column(name = "success_flag", nullable = false) + private boolean successFlag = false; + + @Column(name = "timeout_flag", nullable = false) + private boolean timeoutFlag = false; + + @Column(name = "error_message", nullable = true) + private String errorMessage; + + @Column(name = "throwable", nullable = true) + private String throwable; + + @Column(name = "size_", nullable = true) + private Integer size; + + @Column(name = "rtt", nullable = true) + private Integer rtt; + + @Column(name = "ttl", nullable = true) + private Integer ttl; + + @Column(name = "duration", nullable = true) + private Integer duration; + + @Column(name = "measured_at", nullable = false) + private ZonedDateTime measuredAt; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private ZonedDateTime createdAt; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") + private ZonedDateTime updatedAt; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public QoSIntraPingMeasurementLogDetails() {} + + //------------------------------------------------------------------------------------------------- + @PrePersist + public void onCreate() { + this.createdAt = ZonedDateTime.now(); + this.updatedAt = this.createdAt; + } + + //------------------------------------------------------------------------------------------------- + @PreUpdate + public void onUpdate() { + this.updatedAt = ZonedDateTime.now(); + } + + //------------------------------------------------------------------------------------------------- + public QoSIntraPingMeasurementLog getMeasurementLog() { return measurementLog; } + public int getMeasurementSequeneceNumber() { return measurementSequeneceNumber; } + public boolean isSuccessFlag() { return successFlag; } + public boolean isTimeoutFlag() { return timeoutFlag; } + public String getErrorMessage() { return errorMessage; } + public String getThrowable() { return throwable; } + public Integer getSize() { return size; } + public Integer getRtt() { return rtt; } + public Integer getTtl() { return ttl; } + public Integer getDuration() { return duration; } + public ZonedDateTime getMeasuredAt() { return measuredAt; } + + //------------------------------------------------------------------------------------------------- + public void setMeasurementLog(final QoSIntraPingMeasurementLog measurementLog) { this.measurementLog = measurementLog; } + public void setMeasurementSequeneceNumber(final int measurementSequeneceNumber) { this.measurementSequeneceNumber = measurementSequeneceNumber; } + public void setSuccessFlag(final boolean successFlag) { this.successFlag = successFlag; } + public void setTimeoutFlag(final boolean timeoutFlag) { this.timeoutFlag = timeoutFlag; } + public void setErrorMessage(final String errorMessage) { this.errorMessage = errorMessage; } + public void setThrowable(final String throwable) { this.throwable = throwable; } + public void setSize(final Integer size) { this.size = size; } + public void setRtt(final Integer rtt) { this.rtt = rtt; } + public void setTtl(final Integer ttl) { this.ttl = ttl; } + public void setDuration(final Integer duration) { this.duration = duration; } + public void setMeasuredAt(final ZonedDateTime measuredAt) { this.measuredAt = measuredAt; } + +} diff --git a/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSReservation.java b/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSReservation.java new file mode 100644 index 000000000..4c2df2ea8 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/entity/QoSReservation.java @@ -0,0 +1,97 @@ +package eu.arrowhead.common.database.entity; + +import java.time.ZonedDateTime; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; + +@Entity +@Table(name = "qos_reservation", uniqueConstraints = @UniqueConstraint(columnNames = { "reservedProviderId", "reservedServiceId" }) ) +public class QoSReservation { + + //================================================================================================= + // members + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private long reservedProviderId; + private long reservedServiceId; + + private String consumerSystemName; + private String consumerAddress; + private int consumerPort; + + private ZonedDateTime reservedTo; + + private boolean temporaryLock = false; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private ZonedDateTime createdAt; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") + private ZonedDateTime updatedAt; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public QoSReservation() {} + + //------------------------------------------------------------------------------------------------- + public QoSReservation(final long reservedProviderId, final long reservedServiceId, final String consumerSystemName, final String consumerAddress, final int consumerPort, + final ZonedDateTime reservedTo, final boolean temporaryLock) { + this.reservedProviderId = reservedProviderId; + this.reservedServiceId = reservedServiceId; + this.consumerSystemName = consumerSystemName; + this.consumerAddress = consumerAddress; + this.consumerPort = consumerPort; + this.reservedTo = reservedTo; + this.temporaryLock = temporaryLock; + } + + //------------------------------------------------------------------------------------------------- + @PrePersist + public void onCreate() { + this.createdAt = ZonedDateTime.now(); + this.updatedAt = this.createdAt; + } + + //------------------------------------------------------------------------------------------------- + @PreUpdate + public void onUpdate() { + this.updatedAt = ZonedDateTime.now(); + } + + //------------------------------------------------------------------------------------------------- + public long getId() { return id; } + public long getReservedProviderId() { return reservedProviderId; } + public long getReservedServiceId() { return reservedServiceId; } + public String getConsumerSystemName() { return consumerSystemName; } + public String getConsumerAddress() { return consumerAddress; } + public int getConsumerPort() { return consumerPort; } + public ZonedDateTime getReservedTo() { return reservedTo; } + public boolean isTemporaryLock() { return temporaryLock; } + public ZonedDateTime getCreatedAt() { return createdAt; } + public ZonedDateTime getUpdatedAt() { return updatedAt; } + + //------------------------------------------------------------------------------------------------- + public void setId(final long id) { this.id = id; } + public void setReservedProviderId(final long reservedProviderId) { this.reservedProviderId = reservedProviderId; } + public void setReservedServiceId(final int reservedServiceId) { this.reservedServiceId = reservedServiceId; } + public void setConsumerSystemName(final String consumerSystemName) { this.consumerSystemName = consumerSystemName; } + public void setConsumerAddress(final String consumerAddress) { this.consumerAddress = consumerAddress; } + public void setConsumerPort(final int consumerPort) { this.consumerPort = consumerPort; } + public void setReservedTo(final ZonedDateTime reservedTo) { this.reservedTo = reservedTo; } + public void setTemporaryLock(final boolean temporaryLock) { this.temporaryLock = temporaryLock; } + public void setCreatedAt(final ZonedDateTime createdAt) { this.createdAt = createdAt; } + public void setUpdatedAt(final ZonedDateTime updatedAt) { this.updatedAt = updatedAt; } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/entity/Subscription.java b/core-common/src/main/java/eu/arrowhead/common/database/entity/Subscription.java index 36c80d176..2f1e53ff1 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/entity/Subscription.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/entity/Subscription.java @@ -71,7 +71,6 @@ public class Subscription { @OneToMany(mappedBy = "subscriptionEntry", fetch = FetchType.EAGER, orphanRemoval = true) @OnDelete(action = OnDeleteAction.CASCADE) private Set publisherConnections = new HashSet<>(); - //================================================================================================= // methods @@ -126,7 +125,7 @@ public void onUpdate() { public void setFilterMetaData(final String filterMetaData) { this.filterMetaData = filterMetaData; } public void setNotifyUri(final String notifyUri) { this.notifyUri = notifyUri; } public void setMatchMetaData(final boolean matchMetaData) { this.matchMetaData = matchMetaData; } - public void setOnlyPredefinedPublishers( final boolean onlyPredefinedPublishers) { this.onlyPredefinedPublishers = onlyPredefinedPublishers; } + public void setOnlyPredefinedPublishers(final boolean onlyPredefinedPublishers) { this.onlyPredefinedPublishers = onlyPredefinedPublishers; } public void setStartDate(final ZonedDateTime startDate) { this.startDate = startDate; } public void setEndDate(final ZonedDateTime endDate) { this.endDate = endDate; } public void setCreatedAt(final ZonedDateTime createdAt) { this.createdAt = createdAt; } diff --git a/core-common/src/main/java/eu/arrowhead/common/database/entity/SubscriptionPublisherConnection.java b/core-common/src/main/java/eu/arrowhead/common/database/entity/SubscriptionPublisherConnection.java index 0ed4d6a45..a980828e8 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/entity/SubscriptionPublisherConnection.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/entity/SubscriptionPublisherConnection.java @@ -18,6 +18,7 @@ @Entity @Table(uniqueConstraints = @UniqueConstraint(columnNames = { "subscriptionId", "systemId" })) public class SubscriptionPublisherConnection { + //================================================================================================= // members @@ -33,7 +34,7 @@ public class SubscriptionPublisherConnection { @JoinColumn(name = "systemId", referencedColumnName = "id", nullable = false) private System system; - @Column(nullable = false ) + @Column(nullable = false) private boolean authorized = false; @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") diff --git a/core-common/src/main/java/eu/arrowhead/common/database/entity/SystemRegistry.java b/core-common/src/main/java/eu/arrowhead/common/database/entity/SystemRegistry.java new file mode 100644 index 000000000..43bda3ce6 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/entity/SystemRegistry.java @@ -0,0 +1,181 @@ +package eu.arrowhead.common.database.entity; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.PrePersist; +import javax.persistence.PreUpdate; +import javax.persistence.Table; +import javax.persistence.UniqueConstraint; +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Objects; + +@Entity +@Table(uniqueConstraints = @UniqueConstraint(columnNames = {"systemId", "deviceId"})) +public class SystemRegistry { + + //================================================================================================= + // members + public static final List SORTABLE_FIELDS_BY = List.of("id", "updatedAt", "createdAt"); //NOSONAR + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "systemId", referencedColumnName = "id", nullable = false) + private System system; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "deviceId", referencedColumnName = "id", nullable = false) + private Device device; + + @Column(nullable = true) + private ZonedDateTime endOfValidity; + + @Column(nullable = true, columnDefinition = "TEXT") + private String metadata; + + @Column(nullable = true) + private Integer version = 1; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP") + private ZonedDateTime createdAt; + + @Column(nullable = false, updatable = false, columnDefinition = "TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP") + private ZonedDateTime updatedAt; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public SystemRegistry() { + } + + //------------------------------------------------------------------------------------------------- + public SystemRegistry(final System system, final Device device, final ZonedDateTime endOfValidity, + final String metadata, final Integer version) { + this.system = system; + this.device = device; + this.endOfValidity = endOfValidity; + this.metadata = metadata; + this.version = version; + } + + //------------------------------------------------------------------------------------------------- + @PrePersist + public void onCreate() { + this.createdAt = ZonedDateTime.now(); + this.updatedAt = this.createdAt; + } + + //------------------------------------------------------------------------------------------------- + @PreUpdate + public void onUpdate() { + this.updatedAt = ZonedDateTime.now(); + } + + //------------------------------------------------------------------------------------------------- + public long getId() { + return id; + } + + public System getSystem() { + return system; + } + + public Device getDevice() { + return device; + } + + public ZonedDateTime getEndOfValidity() { + return endOfValidity; + } + + public String getMetadata() { + return metadata; + } + + public Integer getVersion() { + return version; + } + + public ZonedDateTime getCreatedAt() { + return createdAt; + } + + public ZonedDateTime getUpdatedAt() { + return updatedAt; + } + + //------------------------------------------------------------------------------------------------- + public void setId(final long id) { + this.id = id; + } + + public void setSystem(final System system) { + this.system = system; + } + + public void setDevice(final Device device) { + this.device = device; + } + + public void setEndOfValidity(final ZonedDateTime endOfValidity) { + this.endOfValidity = endOfValidity; + } + + public void setMetadata(final String metadata) { + this.metadata = metadata; + } + + public void setVersion(final Integer version) { + this.version = version; + } + + public void setCreatedAt(final ZonedDateTime createdAt) { + this.createdAt = createdAt; + } + + public void setUpdatedAt(final ZonedDateTime updatedAt) { + this.updatedAt = updatedAt; + } + + //------------------------------------------------------------------------------------------------- + @Override + public String toString() { + return "ServiceRegistry [id = " + id + ", system = " + system + ", device = " + device + ", endOfValidity = " + endOfValidity + ", version = " + version + "]"; + } + + //------------------------------------------------------------------------------------------------- + @Override + public int hashCode() { + return Objects.hash(id); + } + + //------------------------------------------------------------------------------------------------- + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + + if (obj == null) { + return false; + } + + if (getClass() != obj.getClass()) { + return false; + } + + final SystemRegistry other = (SystemRegistry) obj; + + return id == other.id; + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/AuthorizationInterCloudInterfaceConnectionRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/AuthorizationInterCloudInterfaceConnectionRepository.java index 8f411aebb..eb201a31d 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/repository/AuthorizationInterCloudInterfaceConnectionRepository.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/AuthorizationInterCloudInterfaceConnectionRepository.java @@ -6,5 +6,4 @@ @Repository public interface AuthorizationInterCloudInterfaceConnectionRepository extends RefreshableRepository { - } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/AuthorizationIntraCloudInterfaceConnectionRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/AuthorizationIntraCloudInterfaceConnectionRepository.java index baa3155ab..39042da56 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/repository/AuthorizationIntraCloudInterfaceConnectionRepository.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/AuthorizationIntraCloudInterfaceConnectionRepository.java @@ -6,5 +6,4 @@ @Repository public interface AuthorizationIntraCloudInterfaceConnectionRepository extends RefreshableRepository { - } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/AuthorizationIntraCloudRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/AuthorizationIntraCloudRepository.java index 35f9832c6..b18b93326 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/repository/AuthorizationIntraCloudRepository.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/AuthorizationIntraCloudRepository.java @@ -22,7 +22,5 @@ public interface AuthorizationIntraCloudRepository extends RefreshableRepository //------------------------------------------------------------------------------------------------- public Optional findByConsumerSystemAndProviderSystemAndServiceDefinition(final System consumer, final System provider, final ServiceDefinition serviceDefinition); - - //------------------------------------------------------------------------------------------------- public List findAllByConsumerSystem(final System consumer); } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerActionActionStepConnectionRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerActionActionStepConnectionRepository.java index 71e03f334..8b4f9b20b 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerActionActionStepConnectionRepository.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerActionActionStepConnectionRepository.java @@ -5,5 +5,4 @@ @Repository public interface ChoreographerActionActionStepConnectionRepository extends RefreshableRepository { - } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerActionPlanActionConnectionRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerActionPlanActionConnectionRepository.java index bc26c4406..85047832d 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerActionPlanActionConnectionRepository.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerActionPlanActionConnectionRepository.java @@ -6,5 +6,4 @@ @Repository public interface ChoreographerActionPlanActionConnectionRepository extends RefreshableRepository { - } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerActionStepServiceDefinitionConnectionRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerActionStepServiceDefinitionConnectionRepository.java index 34309477d..6710b9825 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerActionStepServiceDefinitionConnectionRepository.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerActionStepServiceDefinitionConnectionRepository.java @@ -5,5 +5,4 @@ @Repository public interface ChoreographerActionStepServiceDefinitionConnectionRepository extends RefreshableRepository { - } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerNextActionStepRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerNextActionStepRepository.java index 8c6ae64df..4ff71485d 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerNextActionStepRepository.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/ChoreographerNextActionStepRepository.java @@ -5,5 +5,4 @@ @Repository public interface ChoreographerNextActionStepRepository extends RefreshableRepository { - } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/CloudGatekeeperRelayRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/CloudGatekeeperRelayRepository.java index 9143b59fa..e4636f140 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/repository/CloudGatekeeperRelayRepository.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/CloudGatekeeperRelayRepository.java @@ -6,5 +6,4 @@ @Repository public interface CloudGatekeeperRelayRepository extends RefreshableRepository { - } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/CloudGatewayRelayRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/CloudGatewayRelayRepository.java index b9bf21e08..b1f980798 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/repository/CloudGatewayRelayRepository.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/CloudGatewayRelayRepository.java @@ -6,5 +6,4 @@ @Repository public interface CloudGatewayRelayRepository extends RefreshableRepository { - } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/DeviceRegistryRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/DeviceRegistryRepository.java new file mode 100644 index 000000000..95480eec6 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/DeviceRegistryRepository.java @@ -0,0 +1,23 @@ +package eu.arrowhead.common.database.repository; + +import eu.arrowhead.common.database.entity.Device; +import eu.arrowhead.common.database.entity.DeviceRegistry; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface DeviceRegistryRepository extends RefreshableRepository +{ + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + Optional findByDevice(final Device device); + Page findAllByDeviceIsIn(final List devices, final PageRequest pageRequest); + List findAllByDeviceIsIn(final List devices); +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/DeviceRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/DeviceRepository.java new file mode 100644 index 000000000..bfe573e7b --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/DeviceRepository.java @@ -0,0 +1,19 @@ +package eu.arrowhead.common.database.repository; + +import eu.arrowhead.common.database.entity.Device; +import eu.arrowhead.common.database.entity.System; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface DeviceRepository extends RefreshableRepository { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public Optional findByDeviceNameAndMacAddress(final String deviceName, final String address); + public List findByDeviceName(final String deviceName); +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/EventTypeRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/EventTypeRepository.java index 4c6455222..7fb619237 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/repository/EventTypeRepository.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/EventTypeRepository.java @@ -14,4 +14,4 @@ public interface EventTypeRepository extends RefreshableRepository findByEventTypeName(final String eventTypeName); -} +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSIntraMeasurementPingRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSIntraMeasurementPingRepository.java new file mode 100644 index 000000000..9dfb91be5 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSIntraMeasurementPingRepository.java @@ -0,0 +1,15 @@ +package eu.arrowhead.common.database.repository; + +import java.util.Optional; + +import org.springframework.stereotype.Repository; + +import eu.arrowhead.common.database.entity.QoSIntraMeasurement; +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurement; + +@Repository +public interface QoSIntraMeasurementPingRepository extends RefreshableRepository { + + //================================================================================================= + public Optional findByMeasurement(final QoSIntraMeasurement measurement); +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSIntraMeasurementRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSIntraMeasurementRepository.java new file mode 100644 index 000000000..a17d5b359 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSIntraMeasurementRepository.java @@ -0,0 +1,17 @@ +package eu.arrowhead.common.database.repository; + +import java.util.Optional; + +import org.springframework.stereotype.Repository; + +import eu.arrowhead.common.database.entity.QoSIntraMeasurement; +import eu.arrowhead.common.database.entity.System; +import eu.arrowhead.common.dto.shared.QoSMeasurementType; + +@Repository +public interface QoSIntraMeasurementRepository extends RefreshableRepository { + + //================================================================================================= + // methods + public Optional findBySystemAndMeasurementType(final System systemToCheck,final QoSMeasurementType type); +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSIntraPingMeasurementLogDetailsRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSIntraPingMeasurementLogDetailsRepository.java new file mode 100644 index 000000000..e72f6e59b --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSIntraPingMeasurementLogDetailsRepository.java @@ -0,0 +1,11 @@ +package eu.arrowhead.common.database.repository; + +import org.springframework.stereotype.Repository; + +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurementLogDetails; + +@Repository +public interface QoSIntraPingMeasurementLogDetailsRepository extends RefreshableRepository { + //================================================================================================= + // methods +} diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSIntraPingMeasurementLogRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSIntraPingMeasurementLogRepository.java new file mode 100644 index 000000000..5b8702099 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSIntraPingMeasurementLogRepository.java @@ -0,0 +1,15 @@ +package eu.arrowhead.common.database.repository; + +import java.time.ZonedDateTime; +import java.util.Optional; + +import org.springframework.stereotype.Repository; +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurementLog; + +@Repository +public interface QoSIntraPingMeasurementLogRepository extends RefreshableRepository { + + //================================================================================================= + // methods + public Optional findByMeasuredAt(final ZonedDateTime timeStamp); +} diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSReservationRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSReservationRepository.java new file mode 100644 index 000000000..ad3ce72c3 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/QoSReservationRepository.java @@ -0,0 +1,22 @@ +package eu.arrowhead.common.database.repository; + +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Optional; + +import org.springframework.stereotype.Repository; + +import eu.arrowhead.common.database.entity.QoSReservation; + +@Repository +public interface QoSReservationRepository extends RefreshableRepository { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public List findAllByReservedToLessThanEqual(final ZonedDateTime threshold); + public List findAllByConsumerSystemNameNotOrConsumerAddressNotOrConsumerPortNot(final String consumerSystemName, final String consumerAddress, final int consumerPort); + public Optional findByReservedProviderIdAndReservedServiceId(final long reservedProviderId, final long reservedServiceId); + public Optional findByReservedProviderIdAndReservedServiceIdAndTemporaryLockTrue(final long reservedProviderId, final long reservedServiceId); +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/ServiceRegistryInterfaceConnectionRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/ServiceRegistryInterfaceConnectionRepository.java index 0876b9051..f7382af49 100644 --- a/core-common/src/main/java/eu/arrowhead/common/database/repository/ServiceRegistryInterfaceConnectionRepository.java +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/ServiceRegistryInterfaceConnectionRepository.java @@ -6,5 +6,4 @@ @Repository public interface ServiceRegistryInterfaceConnectionRepository extends RefreshableRepository { - } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/database/repository/SystemRegistryRepository.java b/core-common/src/main/java/eu/arrowhead/common/database/repository/SystemRegistryRepository.java new file mode 100644 index 000000000..f8ef9378f --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/database/repository/SystemRegistryRepository.java @@ -0,0 +1,29 @@ +package eu.arrowhead.common.database.repository; + +import eu.arrowhead.common.database.entity.Device; +import eu.arrowhead.common.database.entity.System; +import eu.arrowhead.common.database.entity.SystemRegistry; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Repository; + +import java.util.List; +import java.util.Optional; + +@Repository +public interface SystemRegistryRepository extends RefreshableRepository { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + List findBySystem(final System system); + + List findByDevice(final Device device); + + Optional findBySystemAndDevice(final System systemDb, final Device deviceDb); + + List findAllBySystemIsIn(final List systems); + + Page findAllBySystemIsIn(final List systemList, final PageRequest pageRequest); +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/drivers/CertificateAuthorityDriver.java b/core-common/src/main/java/eu/arrowhead/common/drivers/CertificateAuthorityDriver.java new file mode 100644 index 000000000..20a4ea20b --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/drivers/CertificateAuthorityDriver.java @@ -0,0 +1,40 @@ +package eu.arrowhead.common.drivers; + +import eu.arrowhead.common.core.CoreSystemService; +import eu.arrowhead.common.dto.internal.CertificateSigningRequestDTO; +import eu.arrowhead.common.dto.internal.CertificateSigningResponseDTO; +import eu.arrowhead.common.http.HttpService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.web.util.UriComponents; + +@Service +public class CertificateAuthorityDriver { + + //================================================================================================= + // members + private final Logger logger = LogManager.getLogger(CertificateAuthorityDriver.class); + private final DriverUtilities driverUtilities; + private final HttpService httpService; + + @Autowired + public CertificateAuthorityDriver(final DriverUtilities driverUtilities, final HttpService httpService) { + this.driverUtilities = driverUtilities; + this.httpService = httpService; + } + + public CertificateSigningResponseDTO signCertificate(final CertificateSigningRequestDTO request) throws DriverUtilities.DriverException { + logger.traceEntry("signCertificate: {}", request); + Assert.notNull(request,"CertificateSigningRequestDTO must not be null"); + final UriComponents uri = driverUtilities.findUriByOrchestrator(CoreSystemService.CERTIFICATE_AUTHORITY_SIGN_SERVICE); + final ResponseEntity httpResponse = httpService + .sendRequest(uri, HttpMethod.POST, CertificateSigningResponseDTO.class, request); + final CertificateSigningResponseDTO result = httpResponse.getBody(); + return logger.traceExit(result); + } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/drivers/DriverUtilities.java b/core-common/src/main/java/eu/arrowhead/common/drivers/DriverUtilities.java new file mode 100644 index 000000000..1f4ebcf98 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/drivers/DriverUtilities.java @@ -0,0 +1,329 @@ +package eu.arrowhead.common.drivers; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.CoreSystemRegistrationProperties; +import eu.arrowhead.common.SSLProperties; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.core.CoreSystemService; +import eu.arrowhead.common.dto.shared.OrchestrationFlags; +import eu.arrowhead.common.dto.shared.OrchestrationFormRequestDTO; +import eu.arrowhead.common.dto.shared.OrchestrationResponseDTO; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; +import eu.arrowhead.common.dto.shared.ServiceQueryFormDTO; +import eu.arrowhead.common.dto.shared.ServiceQueryResultDTO; +import eu.arrowhead.common.dto.shared.ServiceRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.ServiceSecurityType; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.common.exception.UnavailableServerException; +import eu.arrowhead.common.http.HttpService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import javax.annotation.Resource; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +@Component +public class DriverUtilities { + + private final Logger logger = LogManager.getLogger(DriverUtilities.class); + private final CoreSystemRegistrationProperties coreSystemProps; + private final HttpService httpService; + private final SSLProperties sslProperties; + + @Resource(name = CommonConstants.ARROWHEAD_CONTEXT) + private Map arrowheadContext; + + @Autowired + public DriverUtilities(final CoreSystemRegistrationProperties coreSystemProps, + final HttpService httpService, + final SSLProperties sslProperties) { + super(); + this.coreSystemProps = coreSystemProps; + this.httpService = httpService; + this.sslProperties = sslProperties; + } + + //------------------------------------------------------------------------------------------------- + public T getContext(final String key) { + return (T) arrowheadContext.get(key); + } + + //------------------------------------------------------------------------------------------------- + public T getContext(final String key, final T defaultValue) { + return (T) arrowheadContext.getOrDefault(key, defaultValue); + } + + //------------------------------------------------------------------------------------------------- + public boolean containsContext(final String key) { + return arrowheadContext.containsKey(key); + } + + //------------------------------------------------------------------------------------------------- + public boolean pingService(final UriComponents echoUri) { + try { + httpService.sendRequest(echoUri, HttpMethod.GET, String.class); + logger.debug("Service at {} is accessible...", echoUri); + return true; + } catch (final Exception e) { + logger.debug("Service at {} is not accessible: {}: {}", echoUri, e.getClass().getSimpleName(), e.getMessage()); + return false; + } + } + + //------------------------------------------------------------------------------------------------- + public boolean pingService(final ServiceSecurityType securityType, final SystemResponseDTO system, final String systemUri) { + final UriComponents echoUri = createUri(securityType, system, systemUri + CommonConstants.ECHO_URI); + return pingService(echoUri); + } + + public UriComponents findUriByContext(final CoreSystemService service) throws DriverException { + Assert.notNull(service, "CoreSystemService must not be null"); + logger.debug("Searching for '{}' uri in context ...", service.getServiceDefinition()); + final String key = getCoreSystemServiceKey(service); + if (containsContext(key)) { + final UriComponents serviceUri = getContext(key); + final UriComponents echoUri = createEchoUri(serviceUri); + if (pingService(echoUri)) { + return serviceUri; + } + } + + throw DriverException.notFoundByArrowheadContext(service); + } + + public ServiceRegistryResponseDTO findByServiceRegistry(final CoreSystemService service, final boolean pingTarget) throws DriverException { + Assert.notNull(service, "CoreSystemService must not be null"); + logger.debug("findByServiceRegistry started..."); + final UriComponents queryUri = getServiceRegistryQueryUri(); + final ServiceQueryFormDTO form = new ServiceQueryFormDTO.Builder(service.getServiceDefinition()) + .interfaces(getInterface()) + .build(); + final ResponseEntity response = httpService.sendRequest(queryUri, HttpMethod.POST, ServiceQueryResultDTO.class, form); + final ServiceQueryResultDTO result = response.getBody(); + + if (Objects.isNull(result) || Objects.isNull(result.getServiceQueryData()) || result.getServiceQueryData().isEmpty()) { + throw DriverException.notFoundByServiceRegistry(service); + } + + final List serviceQueryData = result.getServiceQueryData(); + + for (int reverseIndex = serviceQueryData.size() - 1; reverseIndex >= 0; reverseIndex--) { + final ServiceRegistryResponseDTO entry = serviceQueryData.get(reverseIndex); + final UriComponents uri = createUri(entry); + if (!pingTarget) { + arrowheadContext.putIfAbsent(getCoreSystemServiceKey(service), uri); + return entry; + } else if (pingService(createEchoUri(uri))) { + arrowheadContext.putIfAbsent(getCoreSystemServiceKey(service), uri); + return entry; + } + } + + throw DriverException.notFoundByServiceRegistry(service); + } + + public UriComponents findUriByServiceRegistry(final CoreSystemService service) throws DriverException { + + try { + return findUriByContext(service); + } catch (final DriverException e) { + logger.debug(e.getMessage()); + } + + logger.debug("findUriByServiceRegistry started..."); + final ServiceRegistryResponseDTO entry = findByServiceRegistry(service, true); + return createUri(entry); + } + + public UriComponents findUriByOrchestrator(final CoreSystemService service) throws DriverException { + Assert.notNull(service, "CoreSystemService must not be null"); + + try { + return findUriByContext(service); + } catch (final DriverException e) { + logger.debug(e.getMessage()); + } + + logger.debug("findUriByOrchestrator started..."); + + final UriComponents queryUri = getOrchestrationQueryUri(); + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setAddress(coreSystemProps.getCoreSystemDomainName()); + requester.setPort(coreSystemProps.getCoreSystemDomainPort()); + requester.setSystemName(coreSystemProps.getCoreSystemName()); + + final ServiceQueryFormDTO serviceQueryForm = new ServiceQueryFormDTO.Builder(service.getServiceDefinition()) + .interfaces(getInterface()) + .build(); + + final OrchestrationFormRequestDTO orchestrationForm = new OrchestrationFormRequestDTO + .Builder(requester) + .requestedService(serviceQueryForm) + .flag(OrchestrationFlags.Flag.OVERRIDE_STORE, true) + .build(); + + final ResponseEntity httpResponse = httpService + .sendRequest(queryUri, HttpMethod.POST, OrchestrationResponseDTO.class, orchestrationForm); + final OrchestrationResponseDTO response = httpResponse.getBody(); + + if (Objects.isNull(response) || Objects.isNull(response.getResponse()) || response.getResponse().isEmpty()) { + throw DriverException.notFoundByOrchestrator(service); + } + + final List result = response.getResponse(); + + for (int reverseIndex = result.size() - 1; reverseIndex >= 0; reverseIndex--) { + final OrchestrationResultDTO entry = result.get(reverseIndex); + final UriComponents uri = createUri(entry); + if (pingService(createEchoUri(uri))) { + arrowheadContext.put(getCoreSystemServiceKey(service), uri); + return uri; + } + } + + throw DriverException.notFoundByOrchestrator(service); + } + + public UriComponents createUri(final ServiceRegistryResponseDTO entry) { + Assert.notNull(entry, "ServiceRegistryResponseDTO must not be null"); + return createUri(entry.getSecure(), entry.getProvider(), entry.getServiceUri()); + } + + public UriComponents createUri(final OrchestrationResultDTO entry) { + Assert.notNull(entry, "OrchestrationResultDTO must not be null"); + return createUri(entry.getSecure(), entry.getProvider(), entry.getServiceUri()); + } + + public UriComponents createUri(final ServiceSecurityType securityType, final SystemResponseDTO system, final String serviceUri) { + Assert.notNull(system, "SystemResponseDTO must not be null"); + return Utilities.createURI(getScheme(securityType), + system.getAddress(), + system.getPort(), + serviceUri); + } + + public UriComponents createEchoUri(final UriComponents serviceUri) { + Assert.notNull(serviceUri, "UriComponents must not be null"); + return UriComponentsBuilder.newInstance() + .scheme(serviceUri.getScheme()) + .host(serviceUri.getHost()) + .port(serviceUri.getPort()) + .path(extractSystemUriPath(serviceUri)) + .path(CommonConstants.ECHO_URI) + .build(); + } + + //------------------------------------------------------------------------------------------------- + public UriComponents createCustomUri(final UriComponents serviceUri, final String systemUri, final String postfix) { + Assert.notNull(serviceUri, "UriComponents must not be null"); + return UriComponentsBuilder.newInstance() + .uriComponents(serviceUri) + .replacePath(systemUri) + .path(postfix) + .build(); + } + + //------------------------------------------------------------------------------------------------- + public UriComponents createCustomUri(final UriComponents serviceUri, final String postfix) { + Assert.notNull(serviceUri, "UriComponents must not be null"); + return UriComponentsBuilder.newInstance() + .uriComponents(serviceUri) + .path(extractSystemUriPath(serviceUri)) + .path(postfix) + .build(); + } + + public String getCoreSystemServiceKey(final CoreSystemService service) { + Assert.notNull(service, "CoreSystemService must not be null"); + return service.getServiceDefinition() + CoreCommonConstants.URI_SUFFIX; + } + + protected UriComponents getServiceRegistryQueryUri() { + logger.debug("getServiceRegistryQueryUri started..."); + + if (arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_URI)) { + return (UriComponents) arrowheadContext.get(CoreCommonConstants.SR_QUERY_URI); + } else { + final String scheme = sslProperties.isSslEnabled() ? CommonConstants.HTTPS : CommonConstants.HTTP; + final String registerUriStr = CommonConstants.SERVICE_REGISTRY_URI + CommonConstants.OP_SERVICE_REGISTRY_QUERY_URI; + final UriComponents uri = Utilities.createURI(scheme, coreSystemProps.getServiceRegistryAddress(), + coreSystemProps.getServiceRegistryPort(), registerUriStr); + arrowheadContext.putIfAbsent(CoreCommonConstants.SR_QUERY_URI, uri); + return uri; + } + } + + protected UriComponents getOrchestrationQueryUri() throws DriverException { + logger.debug("getOrchestrationQueryUri started..."); + return findUriByServiceRegistry(CoreSystemService.ORCHESTRATION_SERVICE); + } + + protected String getScheme() { + return sslProperties.isSslEnabled() ? CommonConstants.HTTPS : CommonConstants.HTTP; + } + + protected String getScheme(final ServiceSecurityType securityType) { + return securityType == ServiceSecurityType.NOT_SECURE ? CommonConstants.HTTP : CommonConstants.HTTPS; + } + + protected String getInterface() { + return sslProperties.isSslEnabled() ? CommonConstants.HTTP_SECURE_JSON : CommonConstants.HTTP_INSECURE_JSON; + } + + //------------------------------------------------------------------------------------------------- + private String extractSystemUriPath(final UriComponents components) { + final List pathSegments = components.getPathSegments(); + return pathSegments.isEmpty() ? components.getPath() : pathSegments.get(0); + } + + public static class DriverException extends UnavailableServerException { + + protected DriverException(final String message) { + super(message); + } + + protected DriverException(final String message, final HttpStatus httpStatus) { + super(message, httpStatus.value()); + } + + protected DriverException(final String message, final Throwable cause) { + super(message, cause); + } + + protected DriverException(final String msg, final int errorCode, final String origin, final Throwable cause) { + super(msg, errorCode, origin, cause); + } + + private static DriverException notFoundByArrowheadContext(final CoreSystemService service) { + return new DriverException("Unable to find " + service.getServiceDefinition() + " via ArrowheadContext", HttpStatus.SERVICE_UNAVAILABLE); + } + + private static DriverException notFoundByServiceRegistry(final CoreSystemService service) { + return new DriverException("Unable to find " + service.getServiceDefinition() + " via ServiceRegistry", HttpStatus.SERVICE_UNAVAILABLE); + } + + private static DriverException notFoundByOrchestrator(final CoreSystemService service) { + return new DriverException("Unable to find " + service.getServiceDefinition() + " via Orchestrator", HttpStatus.SERVICE_UNAVAILABLE); + } + + public DriverException createExceptionWith(final HttpStatus errorCode, final String origin) { + return new DriverException(getMessage(), errorCode.value(), origin, getCause()); + } + + public DriverException createExceptionWith(final int errorCode, final String origin) { + return new DriverException(getMessage(), errorCode, origin, getCause()); + } + } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/drivers/OrchestrationDriver.java b/core-common/src/main/java/eu/arrowhead/common/drivers/OrchestrationDriver.java new file mode 100644 index 000000000..e5c3ebdbd --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/drivers/OrchestrationDriver.java @@ -0,0 +1,46 @@ +package eu.arrowhead.common.drivers; + +import eu.arrowhead.common.core.CoreSystemService; +import eu.arrowhead.common.dto.shared.OrchestrationFormRequestDTO; +import eu.arrowhead.common.dto.shared.OrchestrationResponseDTO; +import eu.arrowhead.common.http.HttpService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.web.util.UriComponents; + +@Service +public class OrchestrationDriver { + + //================================================================================================= + // members + private final Logger logger = LogManager.getLogger(OrchestrationDriver.class); + private final DriverUtilities driverUtilities; + private final HttpService httpService; + + @Autowired + public OrchestrationDriver(final DriverUtilities driverUtilities, final HttpService httpService) { + this.driverUtilities = driverUtilities; + this.httpService = httpService; + } + + public UriComponents findCoreSystemService(final CoreSystemService service) throws DriverUtilities.DriverException { + logger.traceEntry("findCoreSystemService: {}", service); + Assert.notNull(service, "CoreSystemService must not be null"); + return logger.traceExit(driverUtilities.findUriByOrchestrator(service)); + } + + public OrchestrationResponseDTO orchestrate(final OrchestrationFormRequestDTO request) throws DriverUtilities.DriverException { + logger.traceEntry("orchestrate: {}", request); + Assert.notNull(request, "OrchestrationFormRequestDTO must not be null"); + final UriComponents uri = driverUtilities.getOrchestrationQueryUri(); + final ResponseEntity httpResponse = httpService + .sendRequest(uri, HttpMethod.POST, OrchestrationResponseDTO.class, request); + final OrchestrationResponseDTO result = httpResponse.getBody(); + return logger.traceExit(result); + } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/drivers/ServiceRegistryDriver.java b/core-common/src/main/java/eu/arrowhead/common/drivers/ServiceRegistryDriver.java new file mode 100644 index 000000000..a5ea526be --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/drivers/ServiceRegistryDriver.java @@ -0,0 +1,80 @@ +package eu.arrowhead.common.drivers; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.core.CoreSystemService; +import eu.arrowhead.common.dto.shared.ServiceQueryFormDTO; +import eu.arrowhead.common.dto.shared.ServiceQueryResultDTO; +import eu.arrowhead.common.dto.shared.ServiceRegistryRequestDTO; +import eu.arrowhead.common.dto.shared.ServiceRegistryResponseDTO; +import eu.arrowhead.common.http.HttpService; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.util.LinkedMultiValueMap; +import org.springframework.util.MultiValueMap; +import org.springframework.web.util.UriComponents; +import org.springframework.web.util.UriComponentsBuilder; + +import java.util.List; + +@Service +public class ServiceRegistryDriver { + + private final Logger logger = LogManager.getLogger(ServiceRegistryDriver.class); + private final DriverUtilities driverUtilities; + private final HttpService httpService; + + @Autowired + public ServiceRegistryDriver(final DriverUtilities driverUtilities, final HttpService httpService) { + this.driverUtilities = driverUtilities; + this.httpService = httpService; + } + + public UriComponents findCoreSystemService(final CoreSystemService service) throws DriverUtilities.DriverException { + logger.traceEntry("findCoreSystemService:{}", service); + Assert.notNull(service, "CoreSystemService must not be null"); + return logger.traceExit(driverUtilities.findUriByServiceRegistry(service)); + } + + public ServiceQueryResultDTO queryRegistry(final ServiceQueryFormDTO form) { + logger.traceEntry("queryRegistry: {}", form); + Assert.notNull(form, "ServiceQueryFormDTO must not be null"); + + final UriComponents uri = driverUtilities.getServiceRegistryQueryUri(); + final ResponseEntity httpEntity = httpService + .sendRequest(uri, HttpMethod.POST, ServiceQueryResultDTO.class, form); + return logger.traceExit(httpEntity.getBody()); + } + + public ServiceRegistryResponseDTO registerService(final ServiceRegistryRequestDTO request) throws DriverUtilities.DriverException { + logger.traceEntry("registerService: {}", request); + Assert.notNull(request, "ServiceRegistryRequestDTO must not be null"); + + final UriComponents uri = driverUtilities.findUriByOrchestrator(CoreSystemService.SERVICE_REGISTRY_REGISTER_SERVICE); + final ResponseEntity httpEntity = httpService + .sendRequest(uri, HttpMethod.POST, ServiceRegistryResponseDTO.class, request); + return logger.traceExit(httpEntity.getBody()); + } + + public void unregisterService(final String serviceDefinition, final String providerName, + final String providerAddress, final int providerPort) + throws DriverUtilities.DriverException { + + logger.traceEntry("unregisterService: {}, {}, {}, {}", serviceDefinition, providerName, providerAddress, providerPort); + final UriComponents uri = driverUtilities.findUriByOrchestrator(CoreSystemService.SERVICE_REGISTRY_UNREGISTER_SERVICE); + final MultiValueMap queryMap = new LinkedMultiValueMap<>(4); + queryMap.put(CommonConstants.OP_SERVICE_REGISTRY_UNREGISTER_REQUEST_PARAM_SERVICE_DEFINITION, List.of(serviceDefinition)); + queryMap.put(CommonConstants.OP_SERVICE_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_SYSTEM_NAME, List.of(providerName)); + queryMap.put(CommonConstants.OP_SERVICE_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_ADDRESS, List.of(providerAddress)); + queryMap.put(CommonConstants.OP_SERVICE_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_PORT, List.of(String.valueOf(providerPort))); + + final UriComponents unregisterUri = UriComponentsBuilder.newInstance().uriComponents(uri) + .queryParams(queryMap).build(); + httpService.sendRequest(unregisterUri, HttpMethod.POST, Void.class); + logger.traceExit(); + } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/CertificateSigningRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/CertificateSigningRequestDTO.java new file mode 100644 index 000000000..780c30e81 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/CertificateSigningRequestDTO.java @@ -0,0 +1,27 @@ +package eu.arrowhead.common.dto.internal; + +import java.io.Serializable; + +import javax.validation.constraints.NotBlank; + +public class CertificateSigningRequestDTO implements Serializable { + + private static final long serialVersionUID = -6810780579000655432L; + + @NotBlank(message = "The encodedCSR is mandatory") + private String encodedCSR; + + public CertificateSigningRequestDTO() {} + + public CertificateSigningRequestDTO(String encodedCSR) { + this.encodedCSR = encodedCSR; + } + + public String getEncodedCSR() { + return encodedCSR; + } + + public void setEncodedCSR(String encodedCSR) { + this.encodedCSR = encodedCSR; + } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/CertificateSigningResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/CertificateSigningResponseDTO.java new file mode 100644 index 000000000..cb8726244 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/CertificateSigningResponseDTO.java @@ -0,0 +1,26 @@ +package eu.arrowhead.common.dto.internal; + +import java.io.Serializable; +import java.util.List; + +public class CertificateSigningResponseDTO implements Serializable { + + private static final long serialVersionUID = -6810780579000655432L; + + private List certificateChain; + + public CertificateSigningResponseDTO() { + } + + public CertificateSigningResponseDTO(List certificateChain) { + this.certificateChain = certificateChain; + } + + public List getCertificateChain() { + return certificateChain; + } + + public void setCertificateChain(List certificateChain) { + this.certificateChain = certificateChain; + } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/CloudResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/CloudResponseDTO.java index 6d966922a..d8e1baa66 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/internal/CloudResponseDTO.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/CloudResponseDTO.java @@ -74,12 +74,15 @@ public boolean equals(final Object obj) { if (this == obj) { return true; } + if (obj == null) { return false; } + if (getClass() != obj.getClass()) { return false; } + final CloudResponseDTO other = (CloudResponseDTO) obj; return id == other.id; diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/DTOConverter.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/DTOConverter.java index d2cc2b0cf..fbc688cb6 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/internal/DTOConverter.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/DTOConverter.java @@ -1,18 +1,5 @@ package eu.arrowhead.common.dto.internal; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Set; - -import eu.arrowhead.common.database.entity.System; -import org.springframework.data.domain.Page; -import org.springframework.util.Assert; - import eu.arrowhead.common.Utilities; import eu.arrowhead.common.database.entity.AuthorizationInterCloud; import eu.arrowhead.common.database.entity.AuthorizationInterCloudInterfaceConnection; @@ -28,9 +15,13 @@ import eu.arrowhead.common.database.entity.Cloud; import eu.arrowhead.common.database.entity.CloudGatekeeperRelay; import eu.arrowhead.common.database.entity.CloudGatewayRelay; +import eu.arrowhead.common.database.entity.Device; +import eu.arrowhead.common.database.entity.DeviceRegistry; import eu.arrowhead.common.database.entity.EventType; import eu.arrowhead.common.database.entity.ForeignSystem; import eu.arrowhead.common.database.entity.OrchestratorStore; +import eu.arrowhead.common.database.entity.QoSIntraMeasurement; +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurement; import eu.arrowhead.common.database.entity.Relay; import eu.arrowhead.common.database.entity.ServiceDefinition; import eu.arrowhead.common.database.entity.ServiceInterface; @@ -38,11 +29,16 @@ import eu.arrowhead.common.database.entity.ServiceRegistryInterfaceConnection; import eu.arrowhead.common.database.entity.Subscription; import eu.arrowhead.common.database.entity.SubscriptionPublisherConnection; +import eu.arrowhead.common.database.entity.System; +import eu.arrowhead.common.database.entity.SystemRegistry; import eu.arrowhead.common.dto.shared.ChoreographerActionPlanResponseDTO; import eu.arrowhead.common.dto.shared.ChoreographerActionResponseDTO; import eu.arrowhead.common.dto.shared.ChoreographerActionStepResponseDTO; import eu.arrowhead.common.dto.shared.ChoreographerNextActionStepResponseDTO; import eu.arrowhead.common.dto.shared.CloudRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceQueryResultDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.DeviceResponseDTO; import eu.arrowhead.common.dto.shared.EventDTO; import eu.arrowhead.common.dto.shared.EventPublishRequestDTO; import eu.arrowhead.common.dto.shared.EventTypeResponseDTO; @@ -53,705 +49,964 @@ import eu.arrowhead.common.dto.shared.ServiceRegistryResponseDTO; import eu.arrowhead.common.dto.shared.SubscriptionListResponseDTO; import eu.arrowhead.common.dto.shared.SubscriptionResponseDTO; +import eu.arrowhead.common.dto.shared.SystemQueryResultDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryResponseDTO; import eu.arrowhead.common.dto.shared.SystemRequestDTO; import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import org.springframework.data.domain.Page; +import org.springframework.util.Assert; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; public class DTOConverter { - - //================================================================================================= - // methods - - //------------------------------------------------------------------------------------------------- - public static SystemResponseDTO convertSystemToSystemResponseDTO(final System system) { - Assert.notNull(system, "System is null"); - - return new SystemResponseDTO(system.getId(), system.getSystemName(), system.getAddress(), system.getPort(), system.getAuthenticationInfo(), - Utilities.convertZonedDateTimeToUTCString(system.getCreatedAt()), Utilities.convertZonedDateTimeToUTCString(system.getUpdatedAt())); - } - - //------------------------------------------------------------------------------------------------- - public static SystemListResponseDTO convertSystemEntryListToSystemListResponseDTO(final Page systemEntryList) { - Assert.notNull(systemEntryList, "systemEntryList is null"); - - final long count = systemEntryList.getTotalElements(); - final SystemListResponseDTO systemListResponseDTO = new SystemListResponseDTO(); - systemListResponseDTO.setCount(count); - systemListResponseDTO.setData(systemEntryListToSystemResponseDTOList(systemEntryList.getContent())); - - return systemListResponseDTO; - } - - //------------------------------------------------------------------------------------------------- - public static ServiceDefinitionResponseDTO convertServiceDefinitionToServiceDefinitionResponseDTO(final ServiceDefinition serviceDefinition) { - Assert.notNull(serviceDefinition, "ServiceDefinition is null"); - - return new ServiceDefinitionResponseDTO(serviceDefinition.getId(), serviceDefinition.getServiceDefinition(), Utilities.convertZonedDateTimeToUTCString(serviceDefinition.getCreatedAt()), - Utilities.convertZonedDateTimeToUTCString(serviceDefinition.getUpdatedAt())); - } - - //------------------------------------------------------------------------------------------------- - public static ServiceDefinitionsListResponseDTO convertServiceDefinitionsListToServiceDefinitionListResponseDTO(final Page serviceDefinitions) { - Assert.notNull(serviceDefinitions, "List of ServiceDefinition is null"); - - final List serviceDefinitionDTOs = new ArrayList<>(serviceDefinitions.getNumberOfElements()); - for (final ServiceDefinition definition : serviceDefinitions) { - serviceDefinitionDTOs.add(convertServiceDefinitionToServiceDefinitionResponseDTO(definition)); - } - - return new ServiceDefinitionsListResponseDTO(serviceDefinitionDTOs, serviceDefinitions.getTotalElements()); - } - - //------------------------------------------------------------------------------------------------- - public static ServiceRegistryResponseDTO convertServiceRegistryToServiceRegistryResponseDTO(final ServiceRegistry entry) { - Assert.notNull(entry, "SR entry is null."); - Assert.notNull(entry.getServiceDefinition(), "Related service definition is null."); - Assert.notNull(entry.getSystem(), "Related system is null."); - Assert.notNull(entry.getInterfaceConnections(), "Related interface connection set is null."); - Assert.isTrue(!entry.getInterfaceConnections().isEmpty(), "Related interface connection set is empty."); - - final ServiceDefinitionResponseDTO serviceDefinitionDTO = convertServiceDefinitionToServiceDefinitionResponseDTO(entry.getServiceDefinition()); - final SystemResponseDTO systemDTO = convertSystemToSystemResponseDTO(entry.getSystem()); - - final ServiceRegistryResponseDTO dto = new ServiceRegistryResponseDTO(); - dto.setId(entry.getId()); - dto.setServiceDefinition(serviceDefinitionDTO); - dto.setProvider(systemDTO); - dto.setServiceUri(entry.getServiceUri()); - dto.setEndOfValidity(Utilities.convertZonedDateTimeToUTCString(entry.getEndOfValidity())); - dto.setSecure(entry.getSecure()); - dto.setMetadata(Utilities.text2Map(entry.getMetadata())); - dto.setVersion(entry.getVersion()); - dto.setInterfaces(collectInterfacesFromServiceRegistry(entry.getInterfaceConnections())); - dto.setCreatedAt(Utilities.convertZonedDateTimeToUTCString(entry.getCreatedAt())); - dto.setUpdatedAt(Utilities.convertZonedDateTimeToUTCString(entry.getUpdatedAt())); - - return dto; - } - - //------------------------------------------------------------------------------------------------- - public static ServiceRegistryListResponseDTO convertServiceRegistryListToServiceRegistryListResponseDTO(final Page serviceRegistryEntries) { - Assert.notNull(serviceRegistryEntries, "List of serviceRegistryEntries is null"); - - final List serviceRegistryEntryDTOs = new ArrayList<>(serviceRegistryEntries.getNumberOfElements()); - for (final ServiceRegistry srEntry: serviceRegistryEntries) { - serviceRegistryEntryDTOs.add(convertServiceRegistryToServiceRegistryResponseDTO(srEntry)); - } - - return new ServiceRegistryListResponseDTO(serviceRegistryEntryDTOs, serviceRegistryEntries.getTotalElements()); - } - - //------------------------------------------------------------------------------------------------- - @SuppressWarnings("squid:S3776") - public static ServiceRegistryGroupedResponseDTO convertServiceRegistryDataToServiceRegistryGroupedResponseDTO(final Iterable serviceDefinitionEntries, - final Iterable systemEntries, - final Iterable interfaceEntries, - final Iterable serviceRegistryEntries) { - Assert.notNull(serviceDefinitionEntries, "List of serviceDefinitionEntries is null"); - Assert.notNull(systemEntries, "List of systemEntries is null"); - Assert.notNull(interfaceEntries, "List of interfaceEntries is null"); - Assert.notNull(serviceRegistryEntries, "List of serviceRegistryEntries is null"); - - final Map servicesBySystemId = new HashMap<>(); - final Map servicesByServiceDefinition = new HashMap<>(); - final List servicesForAutoComplete = new ArrayList<>(); - final List systemsForAutoComplete = new ArrayList<>(); - final List interfacesForAutoComplete = new ArrayList<>(); - - for (final ServiceRegistry srEntry: serviceRegistryEntries) { - final long systemId = srEntry.getSystem().getId(); - final String systemName = srEntry.getSystem().getSystemName(); - final String systemAddress = srEntry.getSystem().getAddress(); - final int systemPort = srEntry.getSystem().getPort(); - final long serviceDefinitionId = srEntry.getServiceDefinition().getId(); - final String serviceDefinition = srEntry.getServiceDefinition().getServiceDefinition(); - - // Creating ServicesGroupedBySystemsResponseDTO - if (servicesBySystemId.containsKey(systemId)) { - servicesBySystemId.get(systemId).getServices().add(convertServiceRegistryToServiceRegistryResponseDTO(srEntry)); - } else { - final ServicesGroupedBySystemsResponseDTO dto = new ServicesGroupedBySystemsResponseDTO(systemId, systemName, systemAddress, systemPort, new ArrayList<>()); - dto.getServices().add(convertServiceRegistryToServiceRegistryResponseDTO(srEntry)); - servicesBySystemId.put(systemId, dto); - } - - // Creating ServicesGroupedByServiceDefinitionResponseDTO - if (servicesByServiceDefinition.containsKey(serviceDefinitionId)) { - servicesByServiceDefinition.get(serviceDefinitionId).getProviderServices().add(convertServiceRegistryToServiceRegistryResponseDTO(srEntry)); - } else { - final ServicesGroupedByServiceDefinitionResponseDTO dto = new ServicesGroupedByServiceDefinitionResponseDTO(serviceDefinitionId, serviceDefinition, new ArrayList<>()); - dto.getProviderServices().add(convertServiceRegistryToServiceRegistryResponseDTO(srEntry)); - servicesByServiceDefinition.put(serviceDefinitionId, dto); - } - } - - // Creating AutoCompleteDataResponseDTO - for (final ServiceDefinition serviceDefinition : serviceDefinitionEntries) { - servicesForAutoComplete.add(new IdValueDTO(serviceDefinition.getId(), serviceDefinition.getServiceDefinition())); - } - for (final System system : systemEntries) { - systemsForAutoComplete.add(DTOConverter.convertSystemToSystemResponseDTO(system)); - } - for (final ServiceInterface serviceInterface : interfaceEntries) { - interfacesForAutoComplete.add(new IdValueDTO(serviceInterface.getId(), serviceInterface.getInterfaceName())); - } - - final List servicesGroupedBySystemsResponseDTOList = new ArrayList<>(); - servicesGroupedBySystemsResponseDTOList.addAll(servicesBySystemId.values()); - final List servicesGroupedByServiceDefinitionResponseDTOList = new ArrayList<>(); - servicesGroupedByServiceDefinitionResponseDTOList.addAll(servicesByServiceDefinition.values()); - final AutoCompleteDataResponseDTO autoCompleteDataResponseDTO = new AutoCompleteDataResponseDTO(servicesForAutoComplete, systemsForAutoComplete, interfacesForAutoComplete); - - return new ServiceRegistryGroupedResponseDTO(servicesGroupedBySystemsResponseDTOList, servicesGroupedByServiceDefinitionResponseDTOList, autoCompleteDataResponseDTO); - } - - //------------------------------------------------------------------------------------------------- - public static ServiceInterfaceResponseDTO convertServiceInterfaceToServiceInterfaceResponseDTO(final ServiceInterface intf) { - Assert.notNull(intf, "Interface entry is null."); - - return new ServiceInterfaceResponseDTO(intf.getId(), intf.getInterfaceName(), Utilities.convertZonedDateTimeToUTCString(intf.getCreatedAt()), - Utilities.convertZonedDateTimeToUTCString(intf.getUpdatedAt())); - } - - //------------------------------------------------------------------------------------------------- - public static ServiceQueryResultDTO convertListOfServiceRegistryEntriesToServiceQueryResultDTO(final List entries, final int unfilteredHits) { - final ServiceQueryResultDTO result = new ServiceQueryResultDTO(); - - if (entries != null) { - Assert.isTrue(unfilteredHits >= entries.size(), "Invalid value of unfiltered hits: " + unfilteredHits); - result.setUnfilteredHits(unfilteredHits); - for (final ServiceRegistry srEntry : entries) { - result.getServiceQueryData().add(convertServiceRegistryToServiceRegistryResponseDTO(srEntry)); - } - } - - return result; - } - - //------------------------------------------------------------------------------------------------- - public static AuthorizationIntraCloudResponseDTO convertAuthorizationIntraCloudToAuthorizationIntraCloudResponseDTO(final AuthorizationIntraCloud entry) { - Assert.notNull(entry, "AuthorizationIntraCloud is null"); - Assert.notNull(entry.getConsumerSystem(), "Consumer is null"); - Assert.notNull(entry.getProviderSystem(), "Provider is null"); - Assert.notNull(entry.getServiceDefinition(), "ServiceDefintion is null"); - Assert.notNull(entry.getInterfaceConnections(), "InterfaceConnections is null"); - - return new AuthorizationIntraCloudResponseDTO(entry.getId(), convertSystemToSystemResponseDTO(entry.getConsumerSystem()), convertSystemToSystemResponseDTO(entry.getProviderSystem()), - convertServiceDefinitionToServiceDefinitionResponseDTO(entry.getServiceDefinition()), - collectInterfacesFromAuthorizationIntraCloud(entry.getInterfaceConnections()), - Utilities.convertZonedDateTimeToUTCString(entry.getCreatedAt()), Utilities.convertZonedDateTimeToUTCString(entry.getUpdatedAt())); - } - - //------------------------------------------------------------------------------------------------- - public static AuthorizationIntraCloudListResponseDTO convertAuthorizationIntraCloudListToAuthorizationIntraCloudListResponseDTO(final Page entries) { - Assert.notNull(entries, "AuthorizationIntraCloudList is null"); - - final List authorizationIntraCloudEntries = new ArrayList<>(entries.getNumberOfElements()); - for (final AuthorizationIntraCloud entry : entries) { - authorizationIntraCloudEntries.add(convertAuthorizationIntraCloudToAuthorizationIntraCloudResponseDTO(entry)); - } - - return new AuthorizationIntraCloudListResponseDTO(authorizationIntraCloudEntries, entries.getTotalElements()); - } - - //------------------------------------------------------------------------------------------------- - public static TokenGenerationResponseDTO convertTokenMapToTokenGenerationResponseDTO(final Map> tokenMap) { - Assert.notNull(tokenMap, "Token map is null."); - - final TokenGenerationResponseDTO result = new TokenGenerationResponseDTO(); - for (final Entry> entry : tokenMap.entrySet()) { - result.getTokenData().add(new TokenDataDTO(entry.getKey(), entry.getValue())); - } - - return result; - } - - //------------------------------------------------------------------------------------------------- - public static CloudListResponseDTO convertCloudToCloudResponseDTO(final Page entries) { - Assert.notNull(entries, "Cloud list is null" ); - - final List cloudEntries = new ArrayList<>(entries.getNumberOfElements()); - for (final Cloud entry : entries) { - cloudEntries.add(convertCloudToCloudResponseDTO(entry)); - } - - return new CloudListResponseDTO(cloudEntries, entries.getTotalElements()); - } - - //------------------------------------------------------------------------------------------------- - public static CloudResponseDTO convertCloudToCloudResponseDTO(final Cloud entity) { - Assert.notNull(entity, "Cloud is null" ); - Assert.notNull(entity.getOperator(), "Cloud.operator is null" ); - Assert.notNull(entity.getName(), "Cloud.name is null" ); - Assert.notNull(entity.getCreatedAt(), "Cloud.createdAt is null" ); - Assert.notNull(entity.getUpdatedAt(), "Cloud.cpdatedAt is null" ); - - return new CloudResponseDTO(entity.getId(), entity.getOperator(), entity.getName(), entity.getSecure(), entity.getNeighbor(), entity.getOwnCloud(), entity.getAuthenticationInfo(), - Utilities.convertZonedDateTimeToUTCString(entity.getCreatedAt()), Utilities.convertZonedDateTimeToUTCString(entity.getUpdatedAt())); - } - - //------------------------------------------------------------------------------------------------- - public static RelayListResponseDTO convertRelayListToRelayResponseListDTO(final Page entries) { - Assert.notNull(entries, "Relay list is null" ); - - final List relayEntries = new ArrayList<>(entries.getNumberOfElements()); - for (final Relay entry : entries) { - relayEntries.add(convertRelayToRelayResponseDTO(entry)); - } - - return new RelayListResponseDTO(relayEntries, entries.getTotalElements()); - } - - //------------------------------------------------------------------------------------------------- - public static RelayResponseDTO convertRelayToRelayResponseDTO(final Relay entry) { - Assert.notNull(entry, "Relay is null"); - Assert.notNull(entry.getAddress(), "Relay.address is null"); - Assert.notNull(entry.getType(), "Relay.type is null"); - Assert.notNull(entry.getCreatedAt(), "Relay.createdAt is null"); - Assert.notNull(entry.getCreatedAt(), "Relay.updatedAt is null"); - - return new RelayResponseDTO(entry.getId(), entry.getAddress(), entry.getPort(), entry.getSecure(), entry.getExclusive(), entry.getType(), - Utilities.convertZonedDateTimeToUTCString(entry.getCreatedAt()), Utilities.convertZonedDateTimeToUTCString(entry.getUpdatedAt())); - } - - //------------------------------------------------------------------------------------------------- - public static List convertRelayListToRelayRequestDTOList(final List relays) { - Assert.notNull(relays, "Relay list is null."); - - final List result = new ArrayList<>(relays.size()); - for (final Relay relay : relays) { - result.add(convertRelayToRelayRequestDTO(relay)); - } - - return result; - } - - //------------------------------------------------------------------------------------------------- - public static RelayRequestDTO convertRelayToRelayRequestDTO(final Relay relay) { - Assert.notNull(relay, "relay is null."); - - return new RelayRequestDTO(relay.getAddress(), relay.getPort(), relay.getSecure(), relay.getExclusive(), relay.getType().name()); - } - - //------------------------------------------------------------------------------------------------- - public static CloudWithRelaysListResponseDTO convertCloudToCloudWithRelaysListResponseDTO(final Page entries) { - Assert.notNull(entries, "Cloud list is null" ); - - final List cloudWithRelaysResponseDTOList = new ArrayList<>(entries.getNumberOfElements()); - for (final Cloud cloud : entries) { - Assert.notNull(cloud.getGatekeeperRelays(), "CloudGatekeeperRelay set is null"); - Assert.notNull(cloud.getGatewayRelays(), "CloudGatewayRelay set is null"); - - cloudWithRelaysResponseDTOList.add(convertCloudToCloudWithRelaysResponseDTO(cloud)); - } - - return new CloudWithRelaysListResponseDTO(cloudWithRelaysResponseDTOList, entries.getTotalElements()); - } - - //------------------------------------------------------------------------------------------------- - public static CloudWithRelaysResponseDTO convertCloudToCloudWithRelaysResponseDTO(final Cloud cloud) { - Assert.notNull(cloud, "Cloud is null"); - Assert.notNull(cloud.getGatekeeperRelays(), "Gatekeeper relays set is null"); - Assert.notNull(cloud.getGatewayRelays(), "Gateway relays set is null"); - - final CloudResponseDTO cloudResponseDTO = convertCloudToCloudResponseDTO(cloud); - - final Set gatekeeperRelays = new HashSet<>(); - for (final CloudGatekeeperRelay conn : cloud.getGatekeeperRelays()) { - gatekeeperRelays.add(conn.getRelay()); - } - - final Set gatewayRelays = new HashSet<>(); - for (final CloudGatewayRelay conn : cloud.getGatewayRelays()) { - gatewayRelays.add(conn.getRelay()); - } - - final List gatekeeperRelayListDTO = new ArrayList<>(gatekeeperRelays.size()); - for (final Relay gatekeeperRelay : gatekeeperRelays) { - gatekeeperRelayListDTO.add(convertRelayToRelayResponseDTO(gatekeeperRelay)); - } - - final List gatewayRelayListDTO = new ArrayList<>(gatewayRelays.size()); - for (final Relay gatewayRelay : gatewayRelays) { - gatewayRelayListDTO.add(convertRelayToRelayResponseDTO(gatewayRelay)); - } - - return new CloudWithRelaysResponseDTO(cloudResponseDTO.getId(), cloudResponseDTO.getOperator(), cloudResponseDTO.getName(), cloudResponseDTO.getSecure(), - cloudResponseDTO.getNeighbor(), cloudResponseDTO.getOwnCloud(), cloudResponseDTO.getAuthenticationInfo(), - cloudResponseDTO.getCreatedAt(), cloudResponseDTO.getUpdatedAt(), gatekeeperRelayListDTO, gatewayRelayListDTO); - } - - //------------------------------------------------------------------------------------------------- - public static AuthorizationInterCloudListResponseDTO convertAuthorizationInterCloudListToAuthorizationInterCloudListResponseDTO(final Page entries) { - Assert.notNull(entries, "AuthorizationInterCloudList is null"); - - final List authorizationInterCloudEntries = new ArrayList<>(entries.getNumberOfElements()); - for (final AuthorizationInterCloud entry : entries) { - authorizationInterCloudEntries.add(convertAuthorizationInterCloudToAuthorizationInterCloudResponseDTO(entry)); - } - - return new AuthorizationInterCloudListResponseDTO(authorizationInterCloudEntries, entries.getTotalElements()); - } - - //------------------------------------------------------------------------------------------------- - public static AuthorizationInterCloudResponseDTO convertAuthorizationInterCloudToAuthorizationInterCloudResponseDTO(final AuthorizationInterCloud entity) { - Assert.notNull(entity, "AuthorizationInterCloud is null" ); - Assert.notNull(entity.getCloud(), "AuthorizationInterCloud.Cloud is null" ); - Assert.notNull(entity.getProvider(), "AuthorizationInterCloud.Provider is null"); - Assert.notNull(entity.getServiceDefinition(), "AuthorizationInterCloud.ServiceDefinition is null" ); - Assert.notNull(entity.getInterfaceConnections(), "AuthorizationInterCloud.InterfaceConnections is null"); - Assert.notNull(entity.getCreatedAt(), "AuthorizationInterCloud.CreatedAt is null" ); - Assert.notNull(entity.getUpdatedAt(), "AuthorizationInterCloud.UpdatedAt is null" ); - - return new AuthorizationInterCloudResponseDTO(entity.getId(), convertCloudToCloudResponseDTO(entity.getCloud()), convertSystemToSystemResponseDTO(entity.getProvider()), - convertServiceDefinitionToServiceDefinitionResponseDTO(entity.getServiceDefinition()), - collectInterfacesFromAuthorizationInterCloud(entity.getInterfaceConnections()), - Utilities.convertZonedDateTimeToUTCString(entity.getCreatedAt()), Utilities.convertZonedDateTimeToUTCString(entity.getUpdatedAt())); - - } - - //------------------------------------------------------------------------------------------------- - public static OrchestratorStoreResponseDTO convertOrchestratorStoreToOrchestratorStoreResponseDTO(final OrchestratorStore entity, final SystemResponseDTO providerSystem, - final CloudResponseDTO providerCloud) { - Assert.notNull(entity, "OrchestratorStore is null"); - Assert.notNull(providerSystem, "OrchestratorStore.ProviderSystem is null"); - Assert.notNull(entity.getCreatedAt(), "OrchestratorStore.CreatedAt is null"); - Assert.notNull(entity.getUpdatedAt(), "OrchestratorStore.UpdatedAt is null"); - - return new OrchestratorStoreResponseDTO(entity.getId(), convertServiceDefinitionToServiceDefinitionResponseDTO(entity.getServiceDefinition()), - convertSystemToSystemResponseDTO(entity.getConsumerSystem()), entity.isForeign(), providerSystem, providerCloud, - convertServiceInterfaceToServiceInterfaceResponseDTO(entity.getServiceInterface()), entity.getPriority(), Utilities.text2Map(entity.getAttribute()), - Utilities.convertZonedDateTimeToUTCString(entity.getCreatedAt()), Utilities.convertZonedDateTimeToUTCString(entity.getUpdatedAt())); - } - - //------------------------------------------------------------------------------------------------- - public static OrchestratorStoreListResponseDTO convertOrchestratorStoreEntryListToOrchestratorStoreListResponseDTO(final List entries) { - Assert.notNull(entries, "OrchestratorStoreList is null"); - - return new OrchestratorStoreListResponseDTO(entries, entries.size()); - } - - //------------------------------------------------------------------------------------------------- - public static OrchestratorStoreListResponseDTO convertOrchestratorStoreEntryListToOrchestratorStoreListResponseDTO(final List entries, final long totalElements) { - Assert.notNull(entries, "OrchestratorStoreList is null"); - - return new OrchestratorStoreListResponseDTO(entries, totalElements); - } - - //------------------------------------------------------------------------------------------------- - public static SystemRequestDTO convertSystemToSystemRequestDTO(final System system) { - Assert.notNull(system, "System is null"); - - final SystemRequestDTO systemRequestDTO = new SystemRequestDTO(); - systemRequestDTO.setAddress(system.getAddress()); - systemRequestDTO.setSystemName(system.getSystemName()); - systemRequestDTO.setPort(system.getPort()); - systemRequestDTO.setAuthenticationInfo(systemRequestDTO.getAuthenticationInfo()); - - return systemRequestDTO; - } - - //------------------------------------------------------------------------------------------------- - public static SystemRequestDTO convertSystemResponseDTOToSystemRequestDTO(final SystemResponseDTO response) { - Assert.notNull(response, "response is null"); - - final SystemRequestDTO result = new SystemRequestDTO(); - result.setSystemName(response.getSystemName()); - result.setAddress(response.getAddress()); - result.setPort(response.getPort()); - result.setAuthenticationInfo(response.getAuthenticationInfo()); - - return result; - } - - //------------------------------------------------------------------------------------------------- - public static PreferredProviderDataDTO convertForeignOrchestratorStoreResponseDTOToPreferredProviderDataDTO(final OrchestratorStoreResponseDTO orchestratorStoreResponseDTO) { - Assert.notNull(orchestratorStoreResponseDTO, "orchestratorStoreResponseDTO is null"); - Assert.isTrue(orchestratorStoreResponseDTO.getForeign(), "orchestratorStoreResponseDTO is not foreign"); - Assert.notNull(orchestratorStoreResponseDTO.getProviderSystem(), "orchestratorStoreResponseDTO.ProviderSystem is null"); - Assert.notNull(orchestratorStoreResponseDTO.getProviderCloud(), "orchestratorStoreResponseDTO.ProviderCloud is null"); - - final PreferredProviderDataDTO preferredProviderDataDTO = new PreferredProviderDataDTO(); - - final SystemRequestDTO providerSystemRequestDTO = DTOConverter.convertSystemResponseDTOToSystemRequestDTO(orchestratorStoreResponseDTO.getProviderSystem()); - preferredProviderDataDTO.setProviderSystem(providerSystemRequestDTO); - - final CloudRequestDTO cloudRequestDTO = convertCloudResponseDTOToCloudRequestDTO(orchestratorStoreResponseDTO.getProviderCloud()); - preferredProviderDataDTO.setProviderCloud(cloudRequestDTO); - - return preferredProviderDataDTO; - } - - //------------------------------------------------------------------------------------------------- - public static CloudRequestDTO convertCloudResponseDTOToCloudRequestDTO(final CloudResponseDTO cloudResponseDTO) { - Assert.notNull(cloudResponseDTO, "cloudResponseDTO is null"); - Assert.notNull(cloudResponseDTO.getOperator(), "cloudResponseDTO.Operator is null"); - Assert.notNull(cloudResponseDTO.getName(), "cloudResponseDTO.Name is null"); - - final CloudRequestDTO cloudRequestDTO = new CloudRequestDTO(); - - cloudRequestDTO.setOperator(cloudResponseDTO.getOperator()); - cloudRequestDTO.setName(cloudResponseDTO.getName()); - cloudRequestDTO.setSecure(cloudResponseDTO.getSecure()); - cloudRequestDTO.setNeighbor(cloudResponseDTO.getNeighbor()); - cloudRequestDTO.setAuthenticationInfo(cloudResponseDTO.getAuthenticationInfo()); - - return cloudRequestDTO; - } - - //------------------------------------------------------------------------------------------------- - public static SubscriptionResponseDTO convertSubscriptionToSubscriptionResponseDTO(final Subscription subscription) { - Assert.notNull(subscription, "subscription is null"); - Assert.notNull(subscription.getSubscriberSystem(), "subscription.ConsumerSystem is null"); - Assert.notNull(subscription.getEventType(), "subscription.EventType is null"); - Assert.notNull(subscription.getNotifyUri(), "subscription.NotifyUri is null"); - Assert.notNull(subscription.getCreatedAt(), "subscription.CreatedAt is null"); - Assert.notNull(subscription.getUpdatedAt(), "subscription.UpdatedAt is null"); - - final String startDate = subscription.getStartDate() == null ? null : Utilities.convertZonedDateTimeToUTCString(subscription.getStartDate()); - final String endDate = subscription.getEndDate() == null ? null : Utilities.convertZonedDateTimeToUTCString(subscription.getEndDate()); - - final Set sources = collectPublishersFromSubscription(subscription.getPublisherConnections()); - - return new SubscriptionResponseDTO(subscription.getId(), convertEventTypeToEventTypeResponseDTO(subscription.getEventType()), - convertSystemToSystemResponseDTO(subscription.getSubscriberSystem()), Utilities.text2Map(subscription.getFilterMetaData()), subscription.getNotifyUri(), - subscription.isMatchMetaData(), startDate, endDate, sources, Utilities.convertZonedDateTimeToUTCString(subscription.getCreatedAt()), - Utilities.convertZonedDateTimeToUTCString(subscription.getUpdatedAt())); - } - - //------------------------------------------------------------------------------------------------- - public static SubscriptionResponseDTO convertSubscriptionToOnlyAuthorizedSourcesSubscriptionResponseDTO(final Subscription subscription) { - Assert.notNull(subscription, "subscription is null"); - Assert.notNull(subscription.getSubscriberSystem(), "subscription.ConsumerSystem is null"); - Assert.notNull(subscription.getEventType(), "subscription.EventType is null"); - Assert.notNull(subscription.getNotifyUri(), "subscription.NotifyUri is null"); - Assert.notNull(subscription.getCreatedAt(), "subscription.CreatedAt is null"); - Assert.notNull(subscription.getUpdatedAt(), "subscription.UpdatedAt is null"); - - final String startDate = subscription.getStartDate() == null ? null : Utilities.convertZonedDateTimeToUTCString(subscription.getStartDate()); - final String endDate = subscription.getEndDate() == null ? null : Utilities.convertZonedDateTimeToUTCString(subscription.getEndDate()); - - final Set sources = collectAuthorizedPublishersFromSubscription(subscription.getPublisherConnections()); - - return new SubscriptionResponseDTO(subscription.getId(), convertEventTypeToEventTypeResponseDTO(subscription.getEventType()), - convertSystemToSystemResponseDTO(subscription.getSubscriberSystem()), Utilities.text2Map(subscription.getFilterMetaData()), subscription.getNotifyUri(), - subscription.isMatchMetaData(), startDate, endDate, sources, Utilities.convertZonedDateTimeToUTCString(subscription.getCreatedAt()), - Utilities.convertZonedDateTimeToUTCString(subscription.getUpdatedAt())); - } - - //------------------------------------------------------------------------------------------------- - public static EventTypeResponseDTO convertEventTypeToEventTypeResponseDTO(final EventType eventType) { - Assert.notNull(eventType, "eventType is null"); - Assert.notNull(eventType.getEventTypeName(), "eventType.EvenTypeName is null"); - - return new EventTypeResponseDTO(eventType.getId(), eventType.getEventTypeName(), Utilities.convertZonedDateTimeToUTCString(eventType.getCreatedAt()), - Utilities.convertZonedDateTimeToUTCString(eventType.getUpdatedAt())); - } - - //------------------------------------------------------------------------------------------------- - public static EventDTO convertEventPublishRequestDTOToEventDTO(final EventPublishRequestDTO eventPublishRequestDTO) { - Assert.notNull(eventPublishRequestDTO, "eventPublishRequestDTO is null"); - Assert.notNull(eventPublishRequestDTO.getEventType(), "eventPublishRequestDTO.EvenType is null"); - Assert.notNull(eventPublishRequestDTO.getPayload(), "eventPublishRequestDTO.Payload is null"); - Assert.notNull(eventPublishRequestDTO.getTimeStamp(), "eventPublishRequestDTO.TimeStamp is null"); - - return new EventDTO(eventPublishRequestDTO.getEventType(), eventPublishRequestDTO.getMetaData(), eventPublishRequestDTO.getPayload(), eventPublishRequestDTO.getTimeStamp()); - } - - //------------------------------------------------------------------------------------------------- - public static SubscriptionListResponseDTO convertSubscriptionPageToSubscriptionListResponseDTO(final Page entries) { - Assert.notNull(entries, "SubscriptionPage is null" ); - - final List subscriptionEntries = new ArrayList<>(entries.getNumberOfElements()); - for (final Subscription entry : entries) { - subscriptionEntries.add(convertSubscriptionToSubscriptionResponseDTO(entry)); - } - - return new SubscriptionListResponseDTO(subscriptionEntries, entries.getTotalElements()); - } - - //------------------------------------------------------------------------------------------------- - public static RelayRequestDTO convertRelayResponseDTOToRelayRequestDTO(final RelayResponseDTO response) { - Assert.notNull(response, "Relay response is null."); - - return new RelayRequestDTO(response.getAddress(), response.getPort(), response.isSecure(), response.isExclusive(), response.getType().name()); - } - - //------------------------------------------------------------------------------------------------- - public static SystemResponseDTO convertForeignSystemToSystemResponseDTO(final ForeignSystem foreignSystem) { - Assert.notNull(foreignSystem, "ForeignSystem is null"); - - return new SystemResponseDTO(foreignSystem.getId(), foreignSystem.getSystemName(), foreignSystem.getAddress(), foreignSystem.getPort(), foreignSystem.getAuthenticationInfo(), - Utilities.convertZonedDateTimeToUTCString(foreignSystem.getCreatedAt()), Utilities.convertZonedDateTimeToUTCString(foreignSystem.getUpdatedAt())); - } - - //------------------------------------------------------------------------------------------------- - public static ChoreographerActionStepResponseDTO convertChoreographerActionStepToChoreographerActionStepResponseDTO(final ChoreographerActionStep actionStep) { - Assert.notNull(actionStep, "ChoreographerActionStep is null."); - - return new ChoreographerActionStepResponseDTO(actionStep.getId(), actionStep.getName(), - collectServiceDefinitionsFromChoreographerActionStep(actionStep.getActionStepServiceDefinitionConnections()), - collectChoreographerNextActionStepsFromChoreographerActionStep(actionStep.getNextActionSteps()), - Utilities.convertZonedDateTimeToUTCString(actionStep.getCreatedAt()), - Utilities.convertZonedDateTimeToUTCString(actionStep.getUpdatedAt())); - } - - //------------------------------------------------------------------------------------------------- - public static List collectChoreographerActionStepsFromChoreographerAction(final Set actionStepConnections) { - Assert.notNull(actionStepConnections, "ActionStepConnectionSet is null."); - - final List result = new ArrayList<>(actionStepConnections.size()); - for (final ChoreographerActionActionStepConnection conn : actionStepConnections) { - result.add(convertChoreographerActionStepToChoreographerActionStepResponseDTO(conn.getActionStepEntry())); - } - - result.sort(Comparator.comparing(ChoreographerActionStepResponseDTO::getId)); - return result; - } - - //------------------------------------------------------------------------------------------------- - public static String collectChoreographerNextActionNameFromChoreographerAction(final ChoreographerAction nextAction) { - if (nextAction != null) { - return nextAction.getActionName(); - } - - return null; - } - - //------------------------------------------------------------------------------------------------- - public static ChoreographerActionResponseDTO convertChoreographerActionToChoreographerActionResponseDTO(final ChoreographerAction actionEntry) { - Assert.notNull(actionEntry, "ChoreographerAction entry is null."); - - return new ChoreographerActionResponseDTO(actionEntry.getId(), actionEntry.getActionName(), - collectChoreographerNextActionNameFromChoreographerAction(actionEntry.getNextAction()), - collectChoreographerActionStepsFromChoreographerAction(actionEntry.getActionActionStepConnections()), - Utilities.convertZonedDateTimeToUTCString(actionEntry.getCreatedAt()), - Utilities.convertZonedDateTimeToUTCString(actionEntry.getUpdatedAt())); - } - - //------------------------------------------------------------------------------------------------- - public static List collectChoreographerActionsFromChoreographerActionPlan(final Set actionConnections) { - Assert.notNull(actionConnections, "ActionConnectionsSet is null."); - - final List result = new ArrayList<>(actionConnections.size()); - for (final ChoreographerActionPlanActionConnection conn : actionConnections) { - result.add(convertChoreographerActionToChoreographerActionResponseDTO(conn.getActionEntry())); - } - - result.sort(Comparator.comparing(ChoreographerActionResponseDTO::getId)); - return result; - } - - //------------------------------------------------------------------------------------------------- - public static ChoreographerActionPlanResponseDTO convertChoreographerActionPlanToChoreographerActionPlanResponseDTO(final ChoreographerActionPlan actionPlanEntry) { - Assert.notNull(actionPlanEntry, "ChoreographerActionPlan entry is null."); - - return new ChoreographerActionPlanResponseDTO(actionPlanEntry.getId(), actionPlanEntry.getActionPlanName(), - collectChoreographerActionsFromChoreographerActionPlan(actionPlanEntry.getActionPlanActionConnections()), - Utilities.convertZonedDateTimeToUTCString(actionPlanEntry.getCreatedAt()), - Utilities.convertZonedDateTimeToUTCString(actionPlanEntry.getUpdatedAt())); - } - - //================================================================================================= - // assistant methods - - //------------------------------------------------------------------------------------------------- - private DTOConverter() { - throw new UnsupportedOperationException(); - } - - //------------------------------------------------------------------------------------------------- - private static List systemEntryListToSystemResponseDTOList(final List systemList) { - final List systemResponseDTOs = new ArrayList<>(systemList.size()); - - for (final System system : systemList) { - systemResponseDTOs.add(convertSystemToSystemResponseDTO(system)); - } - - return systemResponseDTOs; - } - - //------------------------------------------------------------------------------------------------- - private static List collectInterfacesFromServiceRegistry(final Set interfaceConnections) { - final List result = new ArrayList<>(interfaceConnections.size()); - for (final ServiceRegistryInterfaceConnection conn : interfaceConnections) { - result.add(convertServiceInterfaceToServiceInterfaceResponseDTO(conn.getServiceInterface())); - } - - result.sort((dto1, dto2) -> dto1.getInterfaceName().compareToIgnoreCase(dto2.getInterfaceName())); - - return result; - } - - //------------------------------------------------------------------------------------------------- - private static List collectInterfacesFromAuthorizationIntraCloud(final Set interfaceConnections) { - final List result = new ArrayList<>(interfaceConnections.size()); - for (final AuthorizationIntraCloudInterfaceConnection conn : interfaceConnections) { - result.add(convertServiceInterfaceToServiceInterfaceResponseDTO(conn.getServiceInterface())); - } - - result.sort((dto1, dto2) -> dto1.getInterfaceName().compareToIgnoreCase(dto2.getInterfaceName())); - - return result; - } - - //------------------------------------------------------------------------------------------------- - private static List collectInterfacesFromAuthorizationInterCloud(final Set interfaceConnections) { - final List result = new ArrayList<>(interfaceConnections.size()); - for (final AuthorizationInterCloudInterfaceConnection conn : interfaceConnections) { - result.add(convertServiceInterfaceToServiceInterfaceResponseDTO(conn.getServiceInterface())); - } - - result.sort((dto1, dto2) -> dto1.getInterfaceName().compareToIgnoreCase(dto2.getInterfaceName())); - - return result; - } - - //------------------------------------------------------------------------------------------------- - private static List collectServiceDefinitionsFromChoreographerActionStep(final Set serviceDefinitionConnections) { - final List result = new ArrayList<>(serviceDefinitionConnections.size()); - for (final ChoreographerActionStepServiceDefinitionConnection conn : serviceDefinitionConnections) { - result.add(convertServiceDefinitionToServiceDefinitionResponseDTO(conn.getServiceDefinitionEntry())); - } - - result.sort(Comparator.comparing(ServiceDefinitionResponseDTO::getId)); - return result; - } - - //------------------------------------------------------------------------------------------------- - private static List collectChoreographerNextActionStepsFromChoreographerActionStep(final Set nextActionSteps) { - final List result = new ArrayList<>(nextActionSteps.size()); - for (final ChoreographerNextActionStep nextActionStep : nextActionSteps) { - result.add(convertChoreographerNextActionStepToChoreographerNextActionStepResponseDTO(nextActionStep.getNextActionStepEntry())); - } - - result.sort(Comparator.comparing(ChoreographerNextActionStepResponseDTO::getId)); - return result; - } - - //------------------------------------------------------------------------------------------------- - private static ChoreographerNextActionStepResponseDTO convertChoreographerNextActionStepToChoreographerNextActionStepResponseDTO(final ChoreographerActionStep nextActionStepEntry) { - return new ChoreographerNextActionStepResponseDTO(nextActionStepEntry.getId(), nextActionStepEntry.getName()); - } - - //------------------------------------------------------------------------------------------------- - private static Set collectPublishersFromSubscription(final Set connections) { - final Set result = new HashSet<>(connections.size()); - for (final SubscriptionPublisherConnection conn : connections) { - result.add(convertSystemToSystemResponseDTO(conn.getSystem())); - } - - return result; - } - - //------------------------------------------------------------------------------------------------- - private static Set collectAuthorizedPublishersFromSubscription(final Set connections) { - final Set result = new HashSet<>(connections.size()); - for (final SubscriptionPublisherConnection conn : connections) { - if (conn.isAuthorized()) { - result.add(convertSystemToSystemResponseDTO(conn.getSystem())); - } - } - - return result; - } + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + private DTOConverter() { + throw new UnsupportedOperationException(); + } + + //------------------------------------------------------------------------------------------------- + public static DeviceResponseDTO convertDeviceToDeviceResponseDTO(final Device device) { + Assert.notNull(device, "Device is null"); + return new DeviceResponseDTO(device.getId(), device.getDeviceName(), device.getAddress(), device.getMacAddress(), device.getAuthenticationInfo(), + Utilities.convertZonedDateTimeToUTCString(device.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(device.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static DeviceListResponseDTO convertDeviceEntryListToDeviceListResponseDTO(final Page deviceEntryList) { + Assert.notNull(deviceEntryList, "deviceEntryList is null"); + + final long count = deviceEntryList.getTotalElements(); + final DeviceListResponseDTO deviceListResponseDTO = new DeviceListResponseDTO(); + deviceListResponseDTO.setCount(count); + deviceListResponseDTO.setData(deviceEntryListToDeviceResponseDTOList(deviceEntryList.getContent())); + + return deviceListResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + public static SystemResponseDTO convertSystemToSystemResponseDTO(final System system) { + Assert.notNull(system, "System is null"); + + return new SystemResponseDTO(system.getId(), system.getSystemName(), system.getAddress(), system.getPort(), system.getAuthenticationInfo(), + Utilities.convertZonedDateTimeToUTCString(system.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(system.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static SystemListResponseDTO convertSystemEntryListToSystemListResponseDTO(final Page systemEntryList) { + Assert.notNull(systemEntryList, "systemEntryList is null"); + + final long count = systemEntryList.getTotalElements(); + final SystemListResponseDTO systemListResponseDTO = new SystemListResponseDTO(); + systemListResponseDTO.setCount(count); + systemListResponseDTO.setData(systemEntryListToSystemResponseDTOList(systemEntryList.getContent())); + + return systemListResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + public static ServiceDefinitionResponseDTO convertServiceDefinitionToServiceDefinitionResponseDTO(final ServiceDefinition serviceDefinition) { + Assert.notNull(serviceDefinition, "ServiceDefinition is null"); + + return new ServiceDefinitionResponseDTO(serviceDefinition.getId(), serviceDefinition.getServiceDefinition(), + Utilities.convertZonedDateTimeToUTCString(serviceDefinition.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(serviceDefinition.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static ServiceDefinitionsListResponseDTO convertServiceDefinitionsListToServiceDefinitionListResponseDTO( + final Page serviceDefinitions) { + Assert.notNull(serviceDefinitions, "List of ServiceDefinition is null"); + + final List serviceDefinitionDTOs = new ArrayList<>(serviceDefinitions.getNumberOfElements()); + for (final ServiceDefinition definition : serviceDefinitions) { + serviceDefinitionDTOs.add(convertServiceDefinitionToServiceDefinitionResponseDTO(definition)); + } + + return new ServiceDefinitionsListResponseDTO(serviceDefinitionDTOs, serviceDefinitions.getTotalElements()); + } + + //------------------------------------------------------------------------------------------------- + public static ServiceRegistryResponseDTO convertServiceRegistryToServiceRegistryResponseDTO(final ServiceRegistry entry) { + Assert.notNull(entry, "SR entry is null."); + Assert.notNull(entry.getServiceDefinition(), "Related service definition is null."); + Assert.notNull(entry.getSystem(), "Related system is null."); + Assert.notNull(entry.getInterfaceConnections(), "Related interface connection set is null."); + Assert.isTrue(!entry.getInterfaceConnections().isEmpty(), "Related interface connection set is empty."); + + final ServiceDefinitionResponseDTO serviceDefinitionDTO = convertServiceDefinitionToServiceDefinitionResponseDTO(entry.getServiceDefinition()); + final SystemResponseDTO systemDTO = convertSystemToSystemResponseDTO(entry.getSystem()); + + final ServiceRegistryResponseDTO dto = new ServiceRegistryResponseDTO(); + dto.setId(entry.getId()); + dto.setServiceDefinition(serviceDefinitionDTO); + dto.setProvider(systemDTO); + dto.setServiceUri(entry.getServiceUri()); + dto.setEndOfValidity(Utilities.convertZonedDateTimeToUTCString(entry.getEndOfValidity())); + dto.setSecure(entry.getSecure()); + dto.setMetadata(Utilities.text2Map(entry.getMetadata())); + dto.setVersion(entry.getVersion()); + dto.setInterfaces(collectInterfacesFromServiceRegistry(entry.getInterfaceConnections())); + dto.setCreatedAt(Utilities.convertZonedDateTimeToUTCString(entry.getCreatedAt())); + dto.setUpdatedAt(Utilities.convertZonedDateTimeToUTCString(entry.getUpdatedAt())); + + return dto; + } + + //------------------------------------------------------------------------------------------------- + public static ServiceRegistryListResponseDTO convertServiceRegistryListToServiceRegistryListResponseDTO( + final Page serviceRegistryEntries) { + Assert.notNull(serviceRegistryEntries, "List of serviceRegistryEntries is null"); + + final List serviceRegistryEntryDTOs = new ArrayList<>(serviceRegistryEntries.getNumberOfElements()); + for (final ServiceRegistry srEntry : serviceRegistryEntries) { + serviceRegistryEntryDTOs.add(convertServiceRegistryToServiceRegistryResponseDTO(srEntry)); + } + + return new ServiceRegistryListResponseDTO(serviceRegistryEntryDTOs, serviceRegistryEntries.getTotalElements()); + } + + //------------------------------------------------------------------------------------------------- + @SuppressWarnings("squid:S3776") + public static ServiceRegistryGroupedResponseDTO convertServiceRegistryDataToServiceRegistryGroupedResponseDTO( + final Iterable serviceDefinitionEntries, + final Iterable systemEntries, + final Iterable interfaceEntries, + final Iterable serviceRegistryEntries) { + Assert.notNull(serviceDefinitionEntries, "List of serviceDefinitionEntries is null"); + Assert.notNull(systemEntries, "List of systemEntries is null"); + Assert.notNull(interfaceEntries, "List of interfaceEntries is null"); + Assert.notNull(serviceRegistryEntries, "List of serviceRegistryEntries is null"); + + final Map servicesBySystemId = new HashMap<>(); + final Map servicesByServiceDefinition = new HashMap<>(); + final List servicesForAutoComplete = new ArrayList<>(); + final List systemsForAutoComplete = new ArrayList<>(); + final List interfacesForAutoComplete = new ArrayList<>(); + + for (final ServiceRegistry srEntry : serviceRegistryEntries) { + final long systemId = srEntry.getSystem().getId(); + final String systemName = srEntry.getSystem().getSystemName(); + final String systemAddress = srEntry.getSystem().getAddress(); + final int systemPort = srEntry.getSystem().getPort(); + final long serviceDefinitionId = srEntry.getServiceDefinition().getId(); + final String serviceDefinition = srEntry.getServiceDefinition().getServiceDefinition(); + + // Creating ServicesGroupedBySystemsResponseDTO + if (servicesBySystemId.containsKey(systemId)) { + servicesBySystemId.get(systemId).getServices().add(convertServiceRegistryToServiceRegistryResponseDTO(srEntry)); + } else { + final ServicesGroupedBySystemsResponseDTO dto = new ServicesGroupedBySystemsResponseDTO(systemId, systemName, systemAddress, systemPort, + new ArrayList<>()); + dto.getServices().add(convertServiceRegistryToServiceRegistryResponseDTO(srEntry)); + servicesBySystemId.put(systemId, dto); + } + + // Creating ServicesGroupedByServiceDefinitionResponseDTO + if (servicesByServiceDefinition.containsKey(serviceDefinitionId)) { + servicesByServiceDefinition.get(serviceDefinitionId).getProviderServices().add(convertServiceRegistryToServiceRegistryResponseDTO(srEntry)); + } else { + final ServicesGroupedByServiceDefinitionResponseDTO dto = new ServicesGroupedByServiceDefinitionResponseDTO(serviceDefinitionId, + serviceDefinition, + new ArrayList<>()); + dto.getProviderServices().add(convertServiceRegistryToServiceRegistryResponseDTO(srEntry)); + servicesByServiceDefinition.put(serviceDefinitionId, dto); + } + } + + // Creating AutoCompleteDataResponseDTO + for (final ServiceDefinition serviceDefinition : serviceDefinitionEntries) { + servicesForAutoComplete.add(new IdValueDTO(serviceDefinition.getId(), serviceDefinition.getServiceDefinition())); + } + for (final System system : systemEntries) { + systemsForAutoComplete.add(DTOConverter.convertSystemToSystemResponseDTO(system)); + } + for (final ServiceInterface serviceInterface : interfaceEntries) { + interfacesForAutoComplete.add(new IdValueDTO(serviceInterface.getId(), serviceInterface.getInterfaceName())); + } + + final List servicesGroupedBySystemsResponseDTOList = new ArrayList<>(); + servicesGroupedBySystemsResponseDTOList.addAll(servicesBySystemId.values()); + final List servicesGroupedByServiceDefinitionResponseDTOList = new ArrayList<>(); + servicesGroupedByServiceDefinitionResponseDTOList.addAll(servicesByServiceDefinition.values()); + final AutoCompleteDataResponseDTO autoCompleteDataResponseDTO = new AutoCompleteDataResponseDTO(servicesForAutoComplete, systemsForAutoComplete, + interfacesForAutoComplete); + + return new ServiceRegistryGroupedResponseDTO(servicesGroupedBySystemsResponseDTOList, servicesGroupedByServiceDefinitionResponseDTOList, + autoCompleteDataResponseDTO); + } + + //------------------------------------------------------------------------------------------------- + public static ServiceInterfaceResponseDTO convertServiceInterfaceToServiceInterfaceResponseDTO(final ServiceInterface intf) { + Assert.notNull(intf, "Interface entry is null."); + + return new ServiceInterfaceResponseDTO(intf.getId(), intf.getInterfaceName(), Utilities.convertZonedDateTimeToUTCString(intf.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(intf.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static ServiceQueryResultDTO convertListOfServiceRegistryEntriesToServiceQueryResultDTO(final List entries, + final int unfilteredHits) { + final ServiceQueryResultDTO result = new ServiceQueryResultDTO(); + + if (entries != null) { + Assert.isTrue(unfilteredHits >= entries.size(), "Invalid value of unfiltered hits: " + unfilteredHits); + result.setUnfilteredHits(unfilteredHits); + for (final ServiceRegistry srEntry : entries) { + result.getServiceQueryData().add(convertServiceRegistryToServiceRegistryResponseDTO(srEntry)); + } + } + + return result; + } + + //------------------------------------------------------------------------------------------------- + public static SystemQueryResultDTO convertListOfSystemRegistryEntriesToSystemQueryResultDTO(final List entries, final int unfilteredHits) { + final List results = new ArrayList<>(); + + if (entries != null) { + Assert.isTrue(unfilteredHits >= entries.size(), "Invalid value of unfiltered hits: " + unfilteredHits); + for (final SystemRegistry srEntry : entries) { + results.add(convertSystemRegistryToSystemRegistryResponseDTO(srEntry)); + } + } + + return new SystemQueryResultDTO(results, unfilteredHits); + } + + //------------------------------------------------------------------------------------------------- + public static DeviceQueryResultDTO convertListOfDeviceRegistryEntriesToDeviceQueryResultDTO(final List entries, final int unfilteredHits) { + final List results = new ArrayList<>(); + + if (entries != null) { + Assert.isTrue(unfilteredHits >= entries.size(), "Invalid value of unfiltered hits: " + unfilteredHits); + for (final DeviceRegistry srEntry : entries) { + results.add(convertDeviceRegistryToDeviceRegistryResponseDTO(srEntry)); + } + } + + return new DeviceQueryResultDTO(results, unfilteredHits); + } + + //------------------------------------------------------------------------------------------------- + public static AuthorizationIntraCloudResponseDTO convertAuthorizationIntraCloudToAuthorizationIntraCloudResponseDTO(final AuthorizationIntraCloud entry) { + Assert.notNull(entry, "AuthorizationIntraCloud is null"); + Assert.notNull(entry.getConsumerSystem(), "Consumer is null"); + Assert.notNull(entry.getProviderSystem(), "Provider is null"); + Assert.notNull(entry.getServiceDefinition(), "ServiceDefintion is null"); + Assert.notNull(entry.getInterfaceConnections(), "InterfaceConnections is null"); + + return new AuthorizationIntraCloudResponseDTO(entry.getId(), convertSystemToSystemResponseDTO(entry.getConsumerSystem()), + convertSystemToSystemResponseDTO(entry.getProviderSystem()), + convertServiceDefinitionToServiceDefinitionResponseDTO(entry.getServiceDefinition()), + collectInterfacesFromAuthorizationIntraCloud(entry.getInterfaceConnections()), + Utilities.convertZonedDateTimeToUTCString(entry.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(entry.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static AuthorizationIntraCloudListResponseDTO convertAuthorizationIntraCloudListToAuthorizationIntraCloudListResponseDTO( + final Page entries) { + Assert.notNull(entries, "AuthorizationIntraCloudList is null"); + + final List authorizationIntraCloudEntries = new ArrayList<>(entries.getNumberOfElements()); + for (final AuthorizationIntraCloud entry : entries) { + authorizationIntraCloudEntries.add(convertAuthorizationIntraCloudToAuthorizationIntraCloudResponseDTO(entry)); + } + + return new AuthorizationIntraCloudListResponseDTO(authorizationIntraCloudEntries, entries.getTotalElements()); + } + + //------------------------------------------------------------------------------------------------- + public static TokenGenerationResponseDTO convertTokenMapToTokenGenerationResponseDTO(final Map> tokenMap) { + Assert.notNull(tokenMap, "Token map is null."); + + final TokenGenerationResponseDTO result = new TokenGenerationResponseDTO(); + for (final Entry> entry : tokenMap.entrySet()) { + result.getTokenData().add(new TokenDataDTO(entry.getKey(), entry.getValue())); + } + + return result; + } + + //------------------------------------------------------------------------------------------------- + public static CloudListResponseDTO convertCloudToCloudResponseDTO(final Page entries) { + Assert.notNull(entries, "Cloud list is null"); + + final List cloudEntries = new ArrayList<>(entries.getNumberOfElements()); + for (final Cloud entry : entries) { + cloudEntries.add(convertCloudToCloudResponseDTO(entry)); + } + + return new CloudListResponseDTO(cloudEntries, entries.getTotalElements()); + } + + //------------------------------------------------------------------------------------------------- + public static CloudResponseDTO convertCloudToCloudResponseDTO(final Cloud entity) { + Assert.notNull(entity, "Cloud is null"); + Assert.notNull(entity.getOperator(), "Cloud.operator is null"); + Assert.notNull(entity.getName(), "Cloud.name is null"); + Assert.notNull(entity.getCreatedAt(), "Cloud.createdAt is null"); + Assert.notNull(entity.getUpdatedAt(), "Cloud.cpdatedAt is null"); + + return new CloudResponseDTO(entity.getId(), entity.getOperator(), entity.getName(), entity.getSecure(), entity.getNeighbor(), entity.getOwnCloud(), + entity.getAuthenticationInfo(), + Utilities.convertZonedDateTimeToUTCString(entity.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(entity.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static RelayListResponseDTO convertRelayListToRelayResponseListDTO(final Page entries) { + Assert.notNull(entries, "Relay list is null"); + + final List relayEntries = new ArrayList<>(entries.getNumberOfElements()); + for (final Relay entry : entries) { + relayEntries.add(convertRelayToRelayResponseDTO(entry)); + } + + return new RelayListResponseDTO(relayEntries, entries.getTotalElements()); + } + + //------------------------------------------------------------------------------------------------- + public static RelayResponseDTO convertRelayToRelayResponseDTO(final Relay entry) { + Assert.notNull(entry, "Relay is null"); + Assert.notNull(entry.getAddress(), "Relay.address is null"); + Assert.notNull(entry.getType(), "Relay.type is null"); + Assert.notNull(entry.getCreatedAt(), "Relay.createdAt is null"); + Assert.notNull(entry.getCreatedAt(), "Relay.updatedAt is null"); + + return new RelayResponseDTO(entry.getId(), entry.getAddress(), entry.getPort(), entry.getSecure(), entry.getExclusive(), entry.getType(), + Utilities.convertZonedDateTimeToUTCString(entry.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(entry.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static List convertRelayListToRelayRequestDTOList(final List relays) { + Assert.notNull(relays, "Relay list is null."); + + final List result = new ArrayList<>(relays.size()); + for (final Relay relay : relays) { + result.add(convertRelayToRelayRequestDTO(relay)); + } + + return result; + } + + //------------------------------------------------------------------------------------------------- + public static RelayRequestDTO convertRelayToRelayRequestDTO(final Relay relay) { + Assert.notNull(relay, "relay is null."); + + return new RelayRequestDTO(relay.getAddress(), relay.getPort(), relay.getSecure(), relay.getExclusive(), relay.getType().name()); + } + + //------------------------------------------------------------------------------------------------- + public static CloudWithRelaysListResponseDTO convertCloudToCloudWithRelaysListResponseDTO(final Page entries) { + Assert.notNull(entries, "Cloud list is null"); + + final List cloudWithRelaysResponseDTOList = new ArrayList<>(entries.getNumberOfElements()); + for (final Cloud cloud : entries) { + Assert.notNull(cloud.getGatekeeperRelays(), "CloudGatekeeperRelay set is null"); + Assert.notNull(cloud.getGatewayRelays(), "CloudGatewayRelay set is null"); + + cloudWithRelaysResponseDTOList.add(convertCloudToCloudWithRelaysResponseDTO(cloud)); + } + + return new CloudWithRelaysListResponseDTO(cloudWithRelaysResponseDTOList, entries.getTotalElements()); + } + + //------------------------------------------------------------------------------------------------- + public static CloudWithRelaysResponseDTO convertCloudToCloudWithRelaysResponseDTO(final Cloud cloud) { + Assert.notNull(cloud, "Cloud is null"); + Assert.notNull(cloud.getGatekeeperRelays(), "Gatekeeper relays set is null"); + Assert.notNull(cloud.getGatewayRelays(), "Gateway relays set is null"); + + final CloudResponseDTO cloudResponseDTO = convertCloudToCloudResponseDTO(cloud); + + final Set gatekeeperRelays = new HashSet<>(); + for (final CloudGatekeeperRelay conn : cloud.getGatekeeperRelays()) { + gatekeeperRelays.add(conn.getRelay()); + } + + final Set gatewayRelays = new HashSet<>(); + for (final CloudGatewayRelay conn : cloud.getGatewayRelays()) { + gatewayRelays.add(conn.getRelay()); + } + + final List gatekeeperRelayListDTO = new ArrayList<>(gatekeeperRelays.size()); + for (final Relay gatekeeperRelay : gatekeeperRelays) { + gatekeeperRelayListDTO.add(convertRelayToRelayResponseDTO(gatekeeperRelay)); + } + + final List gatewayRelayListDTO = new ArrayList<>(gatewayRelays.size()); + for (final Relay gatewayRelay : gatewayRelays) { + gatewayRelayListDTO.add(convertRelayToRelayResponseDTO(gatewayRelay)); + } + + return new CloudWithRelaysResponseDTO(cloudResponseDTO.getId(), cloudResponseDTO.getOperator(), cloudResponseDTO.getName(), + cloudResponseDTO.getSecure(), + cloudResponseDTO.getNeighbor(), cloudResponseDTO.getOwnCloud(), cloudResponseDTO.getAuthenticationInfo(), + cloudResponseDTO.getCreatedAt(), cloudResponseDTO.getUpdatedAt(), gatekeeperRelayListDTO, gatewayRelayListDTO); + } + + //------------------------------------------------------------------------------------------------- + public static AuthorizationInterCloudListResponseDTO convertAuthorizationInterCloudListToAuthorizationInterCloudListResponseDTO( + final Page entries) { + Assert.notNull(entries, "AuthorizationInterCloudList is null"); + + final List authorizationInterCloudEntries = new ArrayList<>(entries.getNumberOfElements()); + for (final AuthorizationInterCloud entry : entries) { + authorizationInterCloudEntries.add(convertAuthorizationInterCloudToAuthorizationInterCloudResponseDTO(entry)); + } + + return new AuthorizationInterCloudListResponseDTO(authorizationInterCloudEntries, entries.getTotalElements()); + } + + //------------------------------------------------------------------------------------------------- + public static AuthorizationInterCloudResponseDTO convertAuthorizationInterCloudToAuthorizationInterCloudResponseDTO(final AuthorizationInterCloud entity) { + Assert.notNull(entity, "AuthorizationInterCloud is null"); + Assert.notNull(entity.getCloud(), "AuthorizationInterCloud.Cloud is null"); + Assert.notNull(entity.getProvider(), "AuthorizationInterCloud.Provider is null"); + Assert.notNull(entity.getServiceDefinition(), "AuthorizationInterCloud.ServiceDefinition is null"); + Assert.notNull(entity.getInterfaceConnections(), "AuthorizationInterCloud.InterfaceConnections is null"); + Assert.notNull(entity.getCreatedAt(), "AuthorizationInterCloud.CreatedAt is null"); + Assert.notNull(entity.getUpdatedAt(), "AuthorizationInterCloud.UpdatedAt is null"); + + return new AuthorizationInterCloudResponseDTO(entity.getId(), convertCloudToCloudResponseDTO(entity.getCloud()), + convertSystemToSystemResponseDTO(entity.getProvider()), + convertServiceDefinitionToServiceDefinitionResponseDTO(entity.getServiceDefinition()), + collectInterfacesFromAuthorizationInterCloud(entity.getInterfaceConnections()), + Utilities.convertZonedDateTimeToUTCString(entity.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(entity.getUpdatedAt())); + + } + + //------------------------------------------------------------------------------------------------- + public static OrchestratorStoreResponseDTO convertOrchestratorStoreToOrchestratorStoreResponseDTO(final OrchestratorStore entity, + final SystemResponseDTO providerSystem, + final CloudResponseDTO providerCloud) { + Assert.notNull(entity, "OrchestratorStore is null"); + Assert.notNull(providerSystem, "OrchestratorStore.ProviderSystem is null"); + Assert.notNull(entity.getCreatedAt(), "OrchestratorStore.CreatedAt is null"); + Assert.notNull(entity.getUpdatedAt(), "OrchestratorStore.UpdatedAt is null"); + + return new OrchestratorStoreResponseDTO(entity.getId(), convertServiceDefinitionToServiceDefinitionResponseDTO(entity.getServiceDefinition()), + convertSystemToSystemResponseDTO(entity.getConsumerSystem()), entity.isForeign(), providerSystem, providerCloud, + convertServiceInterfaceToServiceInterfaceResponseDTO(entity.getServiceInterface()), entity.getPriority(), + Utilities.text2Map(entity.getAttribute()), + Utilities.convertZonedDateTimeToUTCString(entity.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(entity.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static OrchestratorStoreListResponseDTO convertOrchestratorStoreEntryListToOrchestratorStoreListResponseDTO( + final List entries) { + Assert.notNull(entries, "OrchestratorStoreList is null"); + + return new OrchestratorStoreListResponseDTO(entries, entries.size()); + } + + //------------------------------------------------------------------------------------------------- + public static OrchestratorStoreListResponseDTO convertOrchestratorStoreEntryListToOrchestratorStoreListResponseDTO( + final List entries, final long totalElements) { + Assert.notNull(entries, "OrchestratorStoreList is null"); + + return new OrchestratorStoreListResponseDTO(entries, totalElements); + } + + //------------------------------------------------------------------------------------------------- + public static SystemRequestDTO convertSystemToSystemRequestDTO(final System system) { + Assert.notNull(system, "System is null"); + + final SystemRequestDTO systemRequestDTO = new SystemRequestDTO(); + systemRequestDTO.setAddress(system.getAddress()); + systemRequestDTO.setSystemName(system.getSystemName()); + systemRequestDTO.setPort(system.getPort()); + systemRequestDTO.setAuthenticationInfo(systemRequestDTO.getAuthenticationInfo()); + + return systemRequestDTO; + } + + //------------------------------------------------------------------------------------------------- + public static SystemRequestDTO convertSystemResponseDTOToSystemRequestDTO(final SystemResponseDTO response) { + Assert.notNull(response, "response is null"); + + final SystemRequestDTO result = new SystemRequestDTO(); + result.setSystemName(response.getSystemName()); + result.setAddress(response.getAddress()); + result.setPort(response.getPort()); + result.setAuthenticationInfo(response.getAuthenticationInfo()); + + return result; + } + + //------------------------------------------------------------------------------------------------- + public static PreferredProviderDataDTO convertForeignOrchestratorStoreResponseDTOToPreferredProviderDataDTO( + final OrchestratorStoreResponseDTO orchestratorStoreResponseDTO) { + Assert.notNull(orchestratorStoreResponseDTO, "orchestratorStoreResponseDTO is null"); + Assert.isTrue(orchestratorStoreResponseDTO.getForeign(), "orchestratorStoreResponseDTO is not foreign"); + Assert.notNull(orchestratorStoreResponseDTO.getProviderSystem(), "orchestratorStoreResponseDTO.ProviderSystem is null"); + Assert.notNull(orchestratorStoreResponseDTO.getProviderCloud(), "orchestratorStoreResponseDTO.ProviderCloud is null"); + + final PreferredProviderDataDTO preferredProviderDataDTO = new PreferredProviderDataDTO(); + + final SystemRequestDTO providerSystemRequestDTO = DTOConverter + .convertSystemResponseDTOToSystemRequestDTO(orchestratorStoreResponseDTO.getProviderSystem()); + preferredProviderDataDTO.setProviderSystem(providerSystemRequestDTO); + + final CloudRequestDTO cloudRequestDTO = convertCloudResponseDTOToCloudRequestDTO(orchestratorStoreResponseDTO.getProviderCloud()); + preferredProviderDataDTO.setProviderCloud(cloudRequestDTO); + + return preferredProviderDataDTO; + } + + //------------------------------------------------------------------------------------------------- + public static CloudRequestDTO convertCloudResponseDTOToCloudRequestDTO(final CloudResponseDTO cloudResponseDTO) { + Assert.notNull(cloudResponseDTO, "cloudResponseDTO is null"); + Assert.notNull(cloudResponseDTO.getOperator(), "cloudResponseDTO.Operator is null"); + Assert.notNull(cloudResponseDTO.getName(), "cloudResponseDTO.Name is null"); + + final CloudRequestDTO cloudRequestDTO = new CloudRequestDTO(); + + cloudRequestDTO.setOperator(cloudResponseDTO.getOperator()); + cloudRequestDTO.setName(cloudResponseDTO.getName()); + cloudRequestDTO.setSecure(cloudResponseDTO.getSecure()); + cloudRequestDTO.setNeighbor(cloudResponseDTO.getNeighbor()); + cloudRequestDTO.setAuthenticationInfo(cloudResponseDTO.getAuthenticationInfo()); + + return cloudRequestDTO; + } + + //------------------------------------------------------------------------------------------------- + public static SubscriptionResponseDTO convertSubscriptionToSubscriptionResponseDTO(final Subscription subscription) { + Assert.notNull(subscription, "subscription is null"); + Assert.notNull(subscription.getSubscriberSystem(), "subscription.ConsumerSystem is null"); + Assert.notNull(subscription.getEventType(), "subscription.EventType is null"); + Assert.notNull(subscription.getNotifyUri(), "subscription.NotifyUri is null"); + Assert.notNull(subscription.getCreatedAt(), "subscription.CreatedAt is null"); + Assert.notNull(subscription.getUpdatedAt(), "subscription.UpdatedAt is null"); + + final String startDate = subscription.getStartDate() == null ? null : Utilities.convertZonedDateTimeToUTCString(subscription.getStartDate()); + final String endDate = subscription.getEndDate() == null ? null : Utilities.convertZonedDateTimeToUTCString(subscription.getEndDate()); + + final Set sources = collectPublishersFromSubscription(subscription.getPublisherConnections()); + + return new SubscriptionResponseDTO(subscription.getId(), convertEventTypeToEventTypeResponseDTO(subscription.getEventType()), + convertSystemToSystemResponseDTO(subscription.getSubscriberSystem()), + Utilities.text2Map(subscription.getFilterMetaData()), subscription.getNotifyUri(), + subscription.isMatchMetaData(), startDate, endDate, sources, + Utilities.convertZonedDateTimeToUTCString(subscription.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(subscription.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static SubscriptionResponseDTO convertSubscriptionToOnlyAuthorizedSourcesSubscriptionResponseDTO(final Subscription subscription) { + Assert.notNull(subscription, "subscription is null"); + Assert.notNull(subscription.getSubscriberSystem(), "subscription.ConsumerSystem is null"); + Assert.notNull(subscription.getEventType(), "subscription.EventType is null"); + Assert.notNull(subscription.getNotifyUri(), "subscription.NotifyUri is null"); + Assert.notNull(subscription.getCreatedAt(), "subscription.CreatedAt is null"); + Assert.notNull(subscription.getUpdatedAt(), "subscription.UpdatedAt is null"); + + final String startDate = subscription.getStartDate() == null ? null : Utilities.convertZonedDateTimeToUTCString(subscription.getStartDate()); + final String endDate = subscription.getEndDate() == null ? null : Utilities.convertZonedDateTimeToUTCString(subscription.getEndDate()); + + final Set sources = collectAuthorizedPublishersFromSubscription(subscription.getPublisherConnections()); + + return new SubscriptionResponseDTO(subscription.getId(), convertEventTypeToEventTypeResponseDTO(subscription.getEventType()), + convertSystemToSystemResponseDTO(subscription.getSubscriberSystem()), + Utilities.text2Map(subscription.getFilterMetaData()), subscription.getNotifyUri(), + subscription.isMatchMetaData(), startDate, endDate, sources, + Utilities.convertZonedDateTimeToUTCString(subscription.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(subscription.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static EventTypeResponseDTO convertEventTypeToEventTypeResponseDTO(final EventType eventType) { + Assert.notNull(eventType, "eventType is null"); + Assert.notNull(eventType.getEventTypeName(), "eventType.EvenTypeName is null"); + + return new EventTypeResponseDTO(eventType.getId(), eventType.getEventTypeName(), Utilities.convertZonedDateTimeToUTCString(eventType.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(eventType.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static EventDTO convertEventPublishRequestDTOToEventDTO(final EventPublishRequestDTO eventPublishRequestDTO) { + Assert.notNull(eventPublishRequestDTO, "eventPublishRequestDTO is null"); + Assert.notNull(eventPublishRequestDTO.getEventType(), "eventPublishRequestDTO.EvenType is null"); + Assert.notNull(eventPublishRequestDTO.getPayload(), "eventPublishRequestDTO.Payload is null"); + Assert.notNull(eventPublishRequestDTO.getTimeStamp(), "eventPublishRequestDTO.TimeStamp is null"); + + return new EventDTO(eventPublishRequestDTO.getEventType(), eventPublishRequestDTO.getMetaData(), eventPublishRequestDTO.getPayload(), + eventPublishRequestDTO.getTimeStamp()); + } + + //------------------------------------------------------------------------------------------------- + public static SubscriptionListResponseDTO convertSubscriptionPageToSubscriptionListResponseDTO(final Page entries) { + Assert.notNull(entries, "SubscriptionPage is null"); + + final List subscriptionEntries = new ArrayList<>(entries.getNumberOfElements()); + for (final Subscription entry : entries) { + subscriptionEntries.add(convertSubscriptionToSubscriptionResponseDTO(entry)); + } + + return new SubscriptionListResponseDTO(subscriptionEntries, entries.getTotalElements()); + } + + //------------------------------------------------------------------------------------------------- + public static RelayRequestDTO convertRelayResponseDTOToRelayRequestDTO(final RelayResponseDTO response) { + Assert.notNull(response, "Relay response is null."); + + return new RelayRequestDTO(response.getAddress(), response.getPort(), response.isSecure(), response.isExclusive(), response.getType().name()); + } + + //------------------------------------------------------------------------------------------------- + public static SystemResponseDTO convertForeignSystemToSystemResponseDTO(final ForeignSystem foreignSystem) { + Assert.notNull(foreignSystem, "ForeignSystem is null"); + + return new SystemResponseDTO(foreignSystem.getId(), foreignSystem.getSystemName(), foreignSystem.getAddress(), foreignSystem.getPort(), + foreignSystem.getAuthenticationInfo(), + Utilities.convertZonedDateTimeToUTCString(foreignSystem.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(foreignSystem.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static ChoreographerActionStepResponseDTO convertChoreographerActionStepToChoreographerActionStepResponseDTO( + final ChoreographerActionStep actionStep) { + Assert.notNull(actionStep, "ChoreographerActionStep is null."); + + return new ChoreographerActionStepResponseDTO(actionStep.getId(), actionStep.getName(), + collectServiceDefinitionsFromChoreographerActionStep( + actionStep.getActionStepServiceDefinitionConnections()), + collectChoreographerNextActionStepsFromChoreographerActionStep(actionStep.getNextActionSteps()), + Utilities.convertZonedDateTimeToUTCString(actionStep.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(actionStep.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static List collectChoreographerActionStepsFromChoreographerAction( + final Set actionStepConnections) { + Assert.notNull(actionStepConnections, "ActionStepConnectionSet is null."); + + final List result = new ArrayList<>(actionStepConnections.size()); + for (final ChoreographerActionActionStepConnection conn : actionStepConnections) { + result.add(convertChoreographerActionStepToChoreographerActionStepResponseDTO(conn.getActionStepEntry())); + } + + result.sort(Comparator.comparing(ChoreographerActionStepResponseDTO::getId)); + return result; + } + + //------------------------------------------------------------------------------------------------- + public static String collectChoreographerNextActionNameFromChoreographerAction(final ChoreographerAction nextAction) { + if (nextAction != null) { + return nextAction.getActionName(); + } + + return null; + } + + //------------------------------------------------------------------------------------------------- + public static ChoreographerActionResponseDTO convertChoreographerActionToChoreographerActionResponseDTO(final ChoreographerAction actionEntry) { + Assert.notNull(actionEntry, "ChoreographerAction entry is null."); + + return new ChoreographerActionResponseDTO(actionEntry.getId(), actionEntry.getActionName(), + collectChoreographerNextActionNameFromChoreographerAction(actionEntry.getNextAction()), + collectChoreographerActionStepsFromChoreographerAction(actionEntry.getActionActionStepConnections()), + Utilities.convertZonedDateTimeToUTCString(actionEntry.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(actionEntry.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static List collectChoreographerActionsFromChoreographerActionPlan( + final Set actionConnections) { + Assert.notNull(actionConnections, "ActionConnectionsSet is null."); + + final List result = new ArrayList<>(actionConnections.size()); + for (final ChoreographerActionPlanActionConnection conn : actionConnections) { + result.add(convertChoreographerActionToChoreographerActionResponseDTO(conn.getActionEntry())); + } + + result.sort(Comparator.comparing(ChoreographerActionResponseDTO::getId)); + return result; + } + + //------------------------------------------------------------------------------------------------- + public static ChoreographerActionPlanResponseDTO convertChoreographerActionPlanToChoreographerActionPlanResponseDTO( + final ChoreographerActionPlan actionPlanEntry) { + Assert.notNull(actionPlanEntry, "ChoreographerActionPlan entry is null."); + + return new ChoreographerActionPlanResponseDTO(actionPlanEntry.getId(), actionPlanEntry.getActionPlanName(), + collectChoreographerActionsFromChoreographerActionPlan(actionPlanEntry.getActionPlanActionConnections()), + Utilities.convertZonedDateTimeToUTCString(actionPlanEntry.getCreatedAt()), + Utilities.convertZonedDateTimeToUTCString(actionPlanEntry.getUpdatedAt())); + } + + //------------------------------------------------------------------------------------------------- + public static SystemRegistryResponseDTO convertSystemRegistryToSystemRegistryResponseDTO(final SystemRegistry entry) { + + Assert.notNull(entry, "SR entry is null."); + Assert.notNull(entry.getDevice(), "Related device is null."); + Assert.notNull(entry.getSystem(), "Related system is null."); + + final SystemResponseDTO systemResponseDTO = convertSystemToSystemResponseDTO(entry.getSystem()); + final DeviceResponseDTO deviceResponseDTO = convertDeviceToDeviceResponseDTO(entry.getDevice()); + + final SystemRegistryResponseDTO dto = new SystemRegistryResponseDTO(); + dto.setId(entry.getId()); + dto.setProvider(deviceResponseDTO); + dto.setSystem(systemResponseDTO); + dto.setEndOfValidity(Utilities.convertZonedDateTimeToUTCString(entry.getEndOfValidity())); + dto.setMetadata(Utilities.text2Map(entry.getMetadata())); + dto.setVersion(entry.getVersion()); + dto.setCreatedAt(Utilities.convertZonedDateTimeToUTCString(entry.getCreatedAt())); + dto.setUpdatedAt(Utilities.convertZonedDateTimeToUTCString(entry.getUpdatedAt())); + + return dto; + } + + //------------------------------------------------------------------------------------------------- + public static SystemRegistryListResponseDTO convertSystemRegistryListToSystemRegistryListResponseDTO(final Iterable page) { + Assert.notNull(page, "Iterable must not be null"); + final List list = new ArrayList<>(); + for (final SystemRegistry entry : page) { + list.add(convertSystemRegistryToSystemRegistryResponseDTO(entry)); + } + return new SystemRegistryListResponseDTO(list, list.size()); + } + + //------------------------------------------------------------------------------------------------- + public static SystemQueryResultDTO convertSystemRegistryListToSystemQueryResultDTO(final Iterable page) { + Assert.notNull(page, "Iterable must not be null"); + final List list = new ArrayList<>(); + for (final SystemRegistry entry : page) { + list.add(convertSystemRegistryToSystemRegistryResponseDTO(entry)); + } + return new SystemQueryResultDTO(list, list.size()); + } + + //------------------------------------------------------------------------------------------------- + public static DeviceRegistryResponseDTO convertDeviceRegistryToDeviceRegistryResponseDTO(final DeviceRegistry entry) { + + Assert.notNull(entry, "DR entry is null."); + Assert.notNull(entry.getDevice(), "Related device is null."); + + final DeviceResponseDTO deviceResponseDTO = convertDeviceToDeviceResponseDTO(entry.getDevice()); + + final DeviceRegistryResponseDTO dto = new DeviceRegistryResponseDTO(); + dto.setId(entry.getId()); + dto.setDevice(deviceResponseDTO); + dto.setEndOfValidity(Utilities.convertZonedDateTimeToUTCString(entry.getEndOfValidity())); + dto.setMetadata(Utilities.text2Map(entry.getMetadata())); + dto.setVersion(entry.getVersion()); + dto.setCreatedAt(Utilities.convertZonedDateTimeToUTCString(entry.getCreatedAt())); + dto.setUpdatedAt(Utilities.convertZonedDateTimeToUTCString(entry.getUpdatedAt())); + + return dto; + } + + //------------------------------------------------------------------------------------------------- + public static DeviceRegistryListResponseDTO convertDeviceRegistryListToDeviceRegistryListResponseDTO(final Iterable page) { + Assert.notNull(page, "Iterable must not be null"); + final List list = new ArrayList<>(); + for (final DeviceRegistry entry : page) { + list.add(convertDeviceRegistryToDeviceRegistryResponseDTO(entry)); + } + return new DeviceRegistryListResponseDTO(list, list.size()); + } + + //------------------------------------------------------------------------------------------------- + public static DeviceQueryResultDTO convertDeviceRegistryListToDeviceQueryResultDTO(final Iterable page) { + Assert.notNull(page, "Iterable must not be null"); + final List list = new ArrayList<>(); + for (final DeviceRegistry entry : page) { + list.add(convertDeviceRegistryToDeviceRegistryResponseDTO(entry)); + } + return new DeviceQueryResultDTO(list, list.size()); + } + + //------------------------------------------------------------------------------------------------- + public static PingMeasurementResponseDTO convertQoSIntraPingMeasurementToPingMeasurementResponseDTO( + final QoSIntraPingMeasurement pingMeasurement) { + Assert.notNull(pingMeasurement, "pingMeasurement is null"); + + final QoSIntraMeasurementResponseDTO measurementResponseDTO = convertQoSIntraMeasurementToQoSIntraMeasurementResponseDTO( + pingMeasurement.getMeasurement()); + + final PingMeasurementResponseDTO pingMeasurementResponseDTO = new PingMeasurementResponseDTO(); + pingMeasurementResponseDTO.setId(pingMeasurement.getId()); + pingMeasurementResponseDTO.setMeasurement(measurementResponseDTO); + pingMeasurementResponseDTO.setAvailable(pingMeasurement.isAvailable()); + pingMeasurementResponseDTO.setLastAccessAt(pingMeasurement.getLastAccessAt()); + pingMeasurementResponseDTO.setMinResponseTime(pingMeasurement.getMinResponseTime()); + pingMeasurementResponseDTO.setMaxResponseTime(pingMeasurement.getMaxResponseTime()); + pingMeasurementResponseDTO.setMeanResponseTimeWithTimeout(pingMeasurement.getMeanResponseTimeWithTimeout()); + pingMeasurementResponseDTO.setMeanResponseTimeWithoutTimeout(pingMeasurement.getMeanResponseTimeWithoutTimeout()); + pingMeasurementResponseDTO.setJitterWithTimeout(pingMeasurement.getJitterWithTimeout()); + pingMeasurementResponseDTO.setJitterWithoutTimeout(pingMeasurement.getJitterWithoutTimeout()); + pingMeasurementResponseDTO.setLostPerMeasurementPercent(pingMeasurement.getLostPerMeasurementPercent()); + pingMeasurementResponseDTO.setSent(pingMeasurement.getSent()); + pingMeasurementResponseDTO.setReceived(pingMeasurement.getReceived()); + pingMeasurementResponseDTO.setCountStartedAt(pingMeasurement.getCountStartedAt()); + pingMeasurementResponseDTO.setSentAll(pingMeasurement.getSentAll()); + pingMeasurementResponseDTO.setReceivedAll(pingMeasurement.getReceivedAll()); + pingMeasurementResponseDTO.setCreatedAt(pingMeasurement.getUpdatedAt()); + pingMeasurementResponseDTO.setUpdatedAt(pingMeasurement.getUpdatedAt()); + + return pingMeasurementResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + public static QoSIntraMeasurementResponseDTO convertQoSIntraMeasurementToQoSIntraMeasurementResponseDTO( + final QoSIntraMeasurement measurement) { + Assert.notNull(measurement, "measurement is null"); + + final SystemResponseDTO system = convertSystemToSystemResponseDTO(measurement.getSystem()); + + return new QoSIntraMeasurementResponseDTO( + measurement.getId(), + system, + measurement.getMeasurementType(), + measurement.getLastMeasurementAt(), + measurement.getCreatedAt(), + measurement.getUpdatedAt()); + } + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + public static PingMeasurementListResponseDTO convertQoSIntraPingMeasurementPageToPingMeasurementListResponseDTO( + final Page entries) { + Assert.notNull(entries, "pingMeasurementPage is null"); + + final List pingMeasurementEntries = new ArrayList<>(entries.getNumberOfElements()); + for (final QoSIntraPingMeasurement entry : entries) { + pingMeasurementEntries.add(convertQoSIntraPingMeasurementToPingMeasurementResponseDTO(entry)); + } + + return new PingMeasurementListResponseDTO(pingMeasurementEntries, entries.getTotalElements()); + } + + //------------------------------------------------------------------------------------------------- + private static List systemEntryListToSystemResponseDTOList(final List systemList) { + final List systemResponseDTOs = new ArrayList<>(systemList.size()); + + for (final System system : systemList) { + systemResponseDTOs.add(convertSystemToSystemResponseDTO(system)); + } + + return systemResponseDTOs; + } + + //------------------------------------------------------------------------------------------------- + private static List deviceEntryListToDeviceResponseDTOList(final List deviceList) { + final List deviceResponseDTOs = new ArrayList<>(deviceList.size()); + + for (final Device device : deviceList) { + deviceResponseDTOs.add(convertDeviceToDeviceResponseDTO(device)); + } + + return deviceResponseDTOs; + } + + //------------------------------------------------------------------------------------------------- + private static List collectInterfacesFromServiceRegistry(final Set interfaceConnections) { + final List result = new ArrayList<>(interfaceConnections.size()); + for (final ServiceRegistryInterfaceConnection conn : interfaceConnections) { + result.add(convertServiceInterfaceToServiceInterfaceResponseDTO(conn.getServiceInterface())); + } + + result.sort((dto1, dto2) -> dto1.getInterfaceName().compareToIgnoreCase(dto2.getInterfaceName())); + + return result; + } + + //------------------------------------------------------------------------------------------------- + private static List collectInterfacesFromAuthorizationIntraCloud( + final Set interfaceConnections) { + final List result = new ArrayList<>(interfaceConnections.size()); + for (final AuthorizationIntraCloudInterfaceConnection conn : interfaceConnections) { + result.add(convertServiceInterfaceToServiceInterfaceResponseDTO(conn.getServiceInterface())); + } + + result.sort((dto1, dto2) -> dto1.getInterfaceName().compareToIgnoreCase(dto2.getInterfaceName())); + + return result; + } + + //------------------------------------------------------------------------------------------------- + private static List collectInterfacesFromAuthorizationInterCloud( + final Set interfaceConnections) { + final List result = new ArrayList<>(interfaceConnections.size()); + for (final AuthorizationInterCloudInterfaceConnection conn : interfaceConnections) { + result.add(convertServiceInterfaceToServiceInterfaceResponseDTO(conn.getServiceInterface())); + } + + result.sort((dto1, dto2) -> dto1.getInterfaceName().compareToIgnoreCase(dto2.getInterfaceName())); + + return result; + } + + //------------------------------------------------------------------------------------------------- + private static List collectServiceDefinitionsFromChoreographerActionStep( + final Set serviceDefinitionConnections) { + final List result = new ArrayList<>(serviceDefinitionConnections.size()); + for (final ChoreographerActionStepServiceDefinitionConnection conn : serviceDefinitionConnections) { + result.add(convertServiceDefinitionToServiceDefinitionResponseDTO(conn.getServiceDefinitionEntry())); + } + + result.sort(Comparator.comparing(ServiceDefinitionResponseDTO::getId)); + return result; + } + + //------------------------------------------------------------------------------------------------- + private static List collectChoreographerNextActionStepsFromChoreographerActionStep( + final Set nextActionSteps) { + final List result = new ArrayList<>(nextActionSteps.size()); + for (final ChoreographerNextActionStep nextActionStep : nextActionSteps) { + result.add(convertChoreographerNextActionStepToChoreographerNextActionStepResponseDTO(nextActionStep.getNextActionStepEntry())); + } + + result.sort(Comparator.comparing(ChoreographerNextActionStepResponseDTO::getId)); + return result; + } + + //------------------------------------------------------------------------------------------------- + private static ChoreographerNextActionStepResponseDTO convertChoreographerNextActionStepToChoreographerNextActionStepResponseDTO( + final ChoreographerActionStep nextActionStepEntry) { + return new ChoreographerNextActionStepResponseDTO(nextActionStepEntry.getId(), nextActionStepEntry.getName()); + } + + //------------------------------------------------------------------------------------------------- + private static Set collectPublishersFromSubscription(final Set connections) { + final Set result = new HashSet<>(connections.size()); + for (final SubscriptionPublisherConnection conn : connections) { + result.add(convertSystemToSystemResponseDTO(conn.getSystem())); + } + + return result; + } + + //------------------------------------------------------------------------------------------------- + private static Set collectAuthorizedPublishersFromSubscription(final Set connections) { + final Set result = new HashSet<>(connections.size()); + for (final SubscriptionPublisherConnection conn : connections) { + if (conn.isAuthorized()) { + result.add(convertSystemToSystemResponseDTO(conn.getSystem())); + } + } + + return result; + } } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/DeviceListResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/DeviceListResponseDTO.java new file mode 100644 index 000000000..30891bcd3 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/DeviceListResponseDTO.java @@ -0,0 +1,43 @@ +package eu.arrowhead.common.dto.internal; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import eu.arrowhead.common.dto.shared.DeviceResponseDTO; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +@JsonInclude(Include.NON_NULL) +public class DeviceListResponseDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -1661484009332215820L; + + private List data = new ArrayList<>(); + private long count; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public DeviceListResponseDTO() {} + + //------------------------------------------------------------------------------------------------- + public DeviceListResponseDTO(final List deviceResponseDTOList, final int totalNumberOfSystems) { + super(); + this.data = deviceResponseDTOList; + this.count = totalNumberOfSystems; + } + + //------------------------------------------------------------------------------------------------- + public List getData() { return data; } + public long getCount() { return count; } + + //------------------------------------------------------------------------------------------------- + public void setData(final List data) { this.data = data; } + public void setCount(final long count) { this.count = count; } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/DeviceRegistryListResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/DeviceRegistryListResponseDTO.java new file mode 100644 index 000000000..f1b71c91d --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/DeviceRegistryListResponseDTO.java @@ -0,0 +1,46 @@ +package eu.arrowhead.common.dto.internal; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import eu.arrowhead.common.dto.shared.DeviceRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryResponseDTO; + +import java.io.Serializable; +import java.util.List; + +@JsonInclude(Include.NON_NULL) +public class DeviceRegistryListResponseDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = 3892383727230105100L; + + private List data; + private long count; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public DeviceRegistryListResponseDTO() {} + + //------------------------------------------------------------------------------------------------- + public DeviceRegistryListResponseDTO(final List data) { + this(data, data.size()); + } + + //------------------------------------------------------------------------------------------------- + public DeviceRegistryListResponseDTO(final List data, final long count) { + this.data = data; + this.count = count; + } + + //------------------------------------------------------------------------------------------------- + public List getData() {return data;} + public long getCount() {return count;} + + //------------------------------------------------------------------------------------------------- + public void setData(final List data) {this.data = data;} + public void setCount(final long count) {this.count = count;} +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/ICNProposalRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/ICNProposalRequestDTO.java index b718e92b7..2e9d8747a 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/internal/ICNProposalRequestDTO.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/ICNProposalRequestDTO.java @@ -80,7 +80,7 @@ public ICNProposalRequestDTO(final ServiceQueryFormDTO requestedService, final C public void setRequesterCloud(final CloudRequestDTO requesterCloud) { this.requesterCloud = requesterCloud; } public void setRequesterSystem(final SystemRequestDTO requesterSystem) { this.requesterSystem = requesterSystem; } public void setGatewayIsPresent(final boolean gatewayIsPresent) { this.gatewayIsPresent = gatewayIsPresent; } - public void setConsumerGatewayPublicKey(String consumerGatewayPublicKey) { this.consumerGatewayPublicKey = consumerGatewayPublicKey; } + public void setConsumerGatewayPublicKey(final String consumerGatewayPublicKey) { this.consumerGatewayPublicKey = consumerGatewayPublicKey; } //------------------------------------------------------------------------------------------------- public void setPreferredSystems(final List preferredSystems) { diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/PingMeasurementListResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/PingMeasurementListResponseDTO.java new file mode 100644 index 000000000..5bff5f6af --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/PingMeasurementListResponseDTO.java @@ -0,0 +1,35 @@ +package eu.arrowhead.common.dto.internal; + +import java.io.Serializable; +import java.util.List; + +public class PingMeasurementListResponseDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = 1261528929899029505L; + + private List data; + private long count; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public PingMeasurementListResponseDTO() {} + + //------------------------------------------------------------------------------------------------- + public PingMeasurementListResponseDTO(final List data, final long count) { + this.data = data; + this.count = count; + } + + //------------------------------------------------------------------------------------------------- + public List getData() { return data; } + public long getCount() { return count; } + + //------------------------------------------------------------------------------------------------- + public void setData(final List data) { this.data = data; } + public void setCount(final long count) { this.count = count; } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/PingMeasurementResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/PingMeasurementResponseDTO.java new file mode 100644 index 000000000..a98e02c1a --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/PingMeasurementResponseDTO.java @@ -0,0 +1,85 @@ +package eu.arrowhead.common.dto.internal; + +import java.io.Serializable; +import java.time.ZonedDateTime; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +public class PingMeasurementResponseDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = 4436693629791850816L; + + private Long id; + private QoSIntraMeasurementResponseDTO measurement; + private boolean available = false; + private ZonedDateTime lastAccessAt; + private Integer minResponseTime; + private Integer maxResponseTime; + private Integer meanResponseTimeWithTimeout; + private Integer meanResponseTimeWithoutTimeout; + private Integer jitterWithTimeout; + private Integer jitterWithoutTimeout; + private Integer lostPerMeasurementPercent; + private long sent; + private long received; + private ZonedDateTime countStartedAt; + private long sentAll; + private long receivedAll; + private ZonedDateTime createdAt; + private ZonedDateTime updatedAt; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public PingMeasurementResponseDTO() {} + + //------------------------------------------------------------------------------------------------- + public Long getId() { return id; } + public QoSIntraMeasurementResponseDTO getMeasurement() { return measurement; } + public boolean isAvailable() {return available; } + public ZonedDateTime getLastAccessAt() { return lastAccessAt; } + public Integer getMinResponseTime() { return minResponseTime; } + public Integer getMaxResponseTime() { return maxResponseTime; } + public Integer getMeanResponseTimeWithTimeout() { return meanResponseTimeWithTimeout; } + public Integer getMeanResponseTimeWithoutTimeout() { return meanResponseTimeWithoutTimeout; } + public Integer getJitterWithTimeout() { return jitterWithTimeout; } + public Integer getJitterWithoutTimeout() { return jitterWithoutTimeout; } + public Integer getLostPerMeasurementPercent() { return lostPerMeasurementPercent; } + public long getSent() { return sent; } + public long getReceived() { return received; } + public ZonedDateTime getCountStartedAt() { return countStartedAt; } + public long getSentAll() { return sentAll; } + public long getReceivedAll() { return receivedAll; } + public ZonedDateTime getCreatedAt() { return createdAt; } + public ZonedDateTime getUpdatedAt() { return updatedAt; } + + //------------------------------------------------------------------------------------------------- + @JsonIgnore + public boolean hasRecord() { + return id != null; + } + + //------------------------------------------------------------------------------------------------- + public void setId(final Long id) { this.id = id; } + public void setMeasurement(final QoSIntraMeasurementResponseDTO measurement) { this.measurement = measurement; } + public void setAvailable(final boolean available) { this.available = available; } + public void setLastAccessAt(final ZonedDateTime lastAccessAt) { this.lastAccessAt = lastAccessAt; } + public void setMinResponseTime(final Integer minResponseTime) { this.minResponseTime = minResponseTime; } + public void setMaxResponseTime(final Integer maxResponseTime) { this.maxResponseTime = maxResponseTime; } + public void setMeanResponseTimeWithTimeout(final Integer meanResponseTimeWithTimeout) { this.meanResponseTimeWithTimeout = meanResponseTimeWithTimeout; } + public void setMeanResponseTimeWithoutTimeout(final Integer meanResponseTimeWithoutTimeout) { this.meanResponseTimeWithoutTimeout = meanResponseTimeWithoutTimeout; } + public void setJitterWithTimeout(final Integer jitterWithTimeout) { this.jitterWithTimeout = jitterWithTimeout; } + public void setJitterWithoutTimeout(final Integer jitterWithoutTimeout) { this.jitterWithoutTimeout = jitterWithoutTimeout; } + public void setLostPerMeasurementPercent(final Integer lostPerMeasurementPercent) { this.lostPerMeasurementPercent = lostPerMeasurementPercent; } + public void setSent(final long sent) { this.sent = sent; } + public void setReceived(final long received) { this.received = received; } + public void setCountStartedAt(final ZonedDateTime countStartedAt) { this.countStartedAt = countStartedAt; } + public void setSentAll(final long sentAll) { this.sentAll = sentAll; } + public void setReceivedAll(final long receivedAll) { this.receivedAll = receivedAll; } + public void setCreatedAt(final ZonedDateTime createdAt) { this.createdAt = createdAt; } + public void setUpdatedAt(final ZonedDateTime updatedAt) { this.updatedAt = updatedAt; } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/QoSIntraMeasurementResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/QoSIntraMeasurementResponseDTO.java new file mode 100644 index 000000000..66845dc55 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/QoSIntraMeasurementResponseDTO.java @@ -0,0 +1,57 @@ +package eu.arrowhead.common.dto.internal; + +import java.io.Serializable; +import java.time.ZonedDateTime; + +import eu.arrowhead.common.dto.shared.QoSMeasurementType; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; + +public class QoSIntraMeasurementResponseDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -8158447252910402563L; + + private long id; + private SystemResponseDTO system; + private QoSMeasurementType measurementType; + private ZonedDateTime lastMeasurementAt; + private ZonedDateTime createdAt; + private ZonedDateTime updatedAt; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public QoSIntraMeasurementResponseDTO() {} + + //------------------------------------------------------------------------------------------------- + public QoSIntraMeasurementResponseDTO(final long id, final SystemResponseDTO system, final QoSMeasurementType measurementType, final ZonedDateTime lastMeasurementAt, + final ZonedDateTime createdAt, final ZonedDateTime updatedAt) { + + this.id = id; + this.system = system; + this.measurementType = measurementType; + this.lastMeasurementAt = lastMeasurementAt; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + //------------------------------------------------------------------------------------------------- + public long getId() { return id; } + public SystemResponseDTO getSystem() { return system; } + public QoSMeasurementType getMeasurementType() { return measurementType; } + public ZonedDateTime getLastMeasurementAt() { return lastMeasurementAt; } + public ZonedDateTime getCreatedAt() { return createdAt; } + public ZonedDateTime getUpdatedAt() { return updatedAt; } + + //------------------------------------------------------------------------------------------------- + public void setId(final long id) { this.id = id; } + public void setSystem(final SystemResponseDTO system) { this.system = system; } + public void setMeasurementType(final QoSMeasurementType measurementType) { this.measurementType = measurementType; } + public void setLastMeasurementAt(final ZonedDateTime lastMeasurementAt) { this.lastMeasurementAt = lastMeasurementAt; } + public void setCreatedAt(final ZonedDateTime createdAt) { this.createdAt = createdAt; } + public void setUpdatedAt(final ZonedDateTime updatedAt) { this.updatedAt = updatedAt; } + +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/SystemListResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/SystemListResponseDTO.java index fd1c94b31..abd8d004a 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/internal/SystemListResponseDTO.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/SystemListResponseDTO.java @@ -27,9 +27,9 @@ public class SystemListResponseDTO implements Serializable { public SystemListResponseDTO() {} //------------------------------------------------------------------------------------------------- - public SystemListResponseDTO(final List systemResponeDTOList, final int totalNumberOfSystems) { + public SystemListResponseDTO(final List systemResponseDTOList, final int totalNumberOfSystems) { super(); - this.data = systemResponeDTOList; + this.data = systemResponseDTOList; this.count = totalNumberOfSystems; } diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/SystemRegistryListResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/SystemRegistryListResponseDTO.java new file mode 100644 index 000000000..37200d99e --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/SystemRegistryListResponseDTO.java @@ -0,0 +1,46 @@ +package eu.arrowhead.common.dto.internal; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import eu.arrowhead.common.dto.shared.ServiceRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryResponseDTO; + +import java.io.Serializable; +import java.util.List; + +@JsonInclude(Include.NON_NULL) +public class SystemRegistryListResponseDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = 3892383727230105100L; + + private List data; + private long count; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public SystemRegistryListResponseDTO() {} + + //------------------------------------------------------------------------------------------------- + public SystemRegistryListResponseDTO(final List data) { + this(data, data.size()); + } + + //------------------------------------------------------------------------------------------------- + public SystemRegistryListResponseDTO(final List data, final long count) { + this.data = data; + this.count = count; + } + + //------------------------------------------------------------------------------------------------- + public List getData() {return data;} + public long getCount() {return count;} + + //------------------------------------------------------------------------------------------------- + public void setData(final List data) {this.data = data;} + public void setCount(final long count) {this.count = count;} +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/TokenGenerationProviderDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/TokenGenerationProviderDTO.java index a9551c44e..92e5796da 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/internal/TokenGenerationProviderDTO.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/TokenGenerationProviderDTO.java @@ -13,10 +13,11 @@ public class TokenGenerationProviderDTO implements Serializable { //================================================================================================= // members - private static final long serialVersionUID = 5119997814495760531L; + private static final long serialVersionUID = -8058322682102502369L; private SystemRequestDTO provider; private List serviceInterfaces = new ArrayList<>(); + private int tokenDuration = -1; // in seconds //================================================================================================= // methods @@ -25,19 +26,22 @@ public class TokenGenerationProviderDTO implements Serializable { public TokenGenerationProviderDTO() {} //------------------------------------------------------------------------------------------------- - public TokenGenerationProviderDTO(final SystemRequestDTO provider, final List serviceInterfaces) { + public TokenGenerationProviderDTO(final SystemRequestDTO provider, final int tokenDuration, final List serviceInterfaces) { Assert.notNull(provider, "Provider is null."); Assert.isTrue(serviceInterfaces != null && !serviceInterfaces.isEmpty(), "Interface list is null or empty."); this.provider = provider; + this.tokenDuration = tokenDuration; this.serviceInterfaces = serviceInterfaces; } //------------------------------------------------------------------------------------------------- public SystemRequestDTO getProvider() { return provider; } + public int getTokenDuration() { return tokenDuration; } public List getServiceInterfaces() { return serviceInterfaces; } //------------------------------------------------------------------------------------------------- public void setProvider(final SystemRequestDTO provider) { this.provider = provider; } + public void setTokenDuration(final int tokenDuration) { this.tokenDuration = tokenDuration; } public void setServiceInterfaces(final List serviceInterfaces) { this.serviceInterfaces = serviceInterfaces; } } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/internal/TokenGenerationRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/internal/TokenGenerationRequestDTO.java index 0001419f2..f6d20d69a 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/internal/TokenGenerationRequestDTO.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/internal/TokenGenerationRequestDTO.java @@ -15,13 +15,12 @@ public class TokenGenerationRequestDTO implements Serializable { //================================================================================================= // members - private static final long serialVersionUID = 1323986110293510298L; + private static final long serialVersionUID = -662827797790310767L; private SystemRequestDTO consumer; private CloudRequestDTO consumerCloud; private List providers = new ArrayList<>(); private String service; - private Integer duration; // in minutes //================================================================================================= // methods @@ -30,8 +29,7 @@ public class TokenGenerationRequestDTO implements Serializable { public TokenGenerationRequestDTO() {} //------------------------------------------------------------------------------------------------- - public TokenGenerationRequestDTO(final SystemRequestDTO consumer, final CloudRequestDTO consumerCloud, final List providers, final String service, - final Integer duration) { + public TokenGenerationRequestDTO(final SystemRequestDTO consumer, final CloudRequestDTO consumerCloud, final List providers, final String service) { Assert.notNull(consumer, "Consumer is null."); Assert.isTrue(providers != null && !providers.isEmpty(), "Provider list is null or empty."); Assert.isTrue(!Utilities.isEmpty(service), "Service is null or blank."); @@ -40,7 +38,6 @@ public TokenGenerationRequestDTO(final SystemRequestDTO consumer, final CloudReq this.consumerCloud = consumerCloud; this.providers = providers; this.service = service; - this.duration = duration; } //------------------------------------------------------------------------------------------------- @@ -48,12 +45,10 @@ public TokenGenerationRequestDTO(final SystemRequestDTO consumer, final CloudReq public CloudRequestDTO getConsumerCloud() { return consumerCloud; } public List getProviders() { return providers; } public String getService() { return service; } - public Integer getDuration() { return duration; } //------------------------------------------------------------------------------------------------- public void setConsumer(final SystemRequestDTO consumer) { this.consumer = consumer; } public void setConsumerCloud(final CloudRequestDTO consumerCloud) { this.consumerCloud = consumerCloud; } public void setProviders(final List providers) { this.providers = providers; } public void setService(final String service) { this.service = service; } - public void setDuration(final Integer duration) { this.duration = duration; } } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/CertificateCreationRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/CertificateCreationRequestDTO.java new file mode 100644 index 000000000..be2344ba3 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/CertificateCreationRequestDTO.java @@ -0,0 +1,56 @@ +package eu.arrowhead.common.dto.shared; + +import java.io.Serializable; +import java.util.StringJoiner; + +public class CertificateCreationRequestDTO implements Serializable { + + //================================================================================================= + // members + private static final long serialVersionUID = 1L; + + private String commonName; + private KeyPairDTO keyPairDTO; + + + //================================================================================================= + // constructors + + public CertificateCreationRequestDTO() { + } + + public CertificateCreationRequestDTO(final String commonName) { + this.commonName = commonName; + } + + public CertificateCreationRequestDTO(final String commonName, final KeyPairDTO keyPairDTO) { + this.commonName = commonName; + this.keyPairDTO = keyPairDTO; + } + + //================================================================================================= + // methods + + public String getCommonName() { + return commonName; + } + public void setCommonName(String commonName) { + this.commonName = commonName; + } + + public KeyPairDTO getKeyPairDTO() { + return keyPairDTO; + } + + public void setKeyPairDTO(final KeyPairDTO keyPairDTO) { + this.keyPairDTO = keyPairDTO; + } + + @Override + public String toString() { + return new StringJoiner(", ", CertificateCreationRequestDTO.class.getSimpleName() + "[", "]") + .add("commonName='" + commonName + "'") + .add("keyPairDTO=" + keyPairDTO) + .toString(); + } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/CertificateCreationResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/CertificateCreationResponseDTO.java new file mode 100644 index 000000000..b400270e6 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/CertificateCreationResponseDTO.java @@ -0,0 +1,83 @@ +package eu.arrowhead.common.dto.shared; + +import java.io.Serializable; +import java.util.StringJoiner; + +public class CertificateCreationResponseDTO implements Serializable { + + //================================================================================================= + // members + private static final long serialVersionUID = 1L; + + private String certificate; + private CertificateType certificateType; + private KeyPairDTO keyPairDTO; + private String certificateFormat; + + //================================================================================================= + // constructors + + public CertificateCreationResponseDTO() { + } + + public CertificateCreationResponseDTO(final String certificate, final CertificateType certificateType, final String certificateFormat) { + this.certificate = certificate; + this.certificateType = certificateType; + this.certificateFormat = certificateFormat; + } + + public CertificateCreationResponseDTO(final String certificate, + final CertificateType certificateType, + final KeyPairDTO keyPairDTO, + final String certificateFormat) { + this.certificate = certificate; + this.certificateType = certificateType; + this.keyPairDTO = keyPairDTO; + this.certificateFormat = certificateFormat; + } + + //================================================================================================= + // methods + + public String getCertificate() { + return certificate; + } + + public void setCertificate(String certificate) { + this.certificate = certificate; + } + + public String getCertificateFormat() { + return certificateFormat; + } + + public void setCertificateFormat(final String certificateFormat) { + this.certificateFormat = certificateFormat; + } + + public CertificateType getCertificateType() { + return certificateType; + } + + public void setCertificateType(final CertificateType certificateType) { + this.certificateType = certificateType; + } + + public KeyPairDTO getKeyPairDTO() { + return keyPairDTO; + } + + public void setKeyPairDTO(final KeyPairDTO keyPairDTO) { + this.keyPairDTO = keyPairDTO; + } + + @Override + public String toString() { + return new StringJoiner(", ", CertificateCreationResponseDTO.class.getSimpleName() + "[", "]") + .add("certificate='" + certificate + "'") + .add("certificateFormat=" + certificateFormat) + .add("certificateType=" + certificateType) + .add("keyPairDTO=" + keyPairDTO) + .toString(); + } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/CertificateType.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/CertificateType.java new file mode 100644 index 000000000..cc0ace910 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/CertificateType.java @@ -0,0 +1,56 @@ +package eu.arrowhead.common.dto.shared; + +import eu.arrowhead.common.Utilities; +import org.springframework.util.Assert; + +import java.util.Objects; + +public enum CertificateType { + + AH_ONBOARDING("onboarding", 0), + AH_DEVICE("device", 1), + AH_SYSTEM("", 2), + UNKNOWN("", 0); + + private final String commonNamePart; + private final int strength; + + CertificateType(final String commonNamePart, final int strength) { + this.commonNamePart = commonNamePart; + this.strength = strength; + } + + public static CertificateType getTypeFromCN(final String commonName) { + if (Objects.isNull(commonName)) { return CertificateType.UNKNOWN; } + + final String[] split = commonName.split("\\."); + + if (Utilities.isKeyStoreCNArrowheadValid(commonName)) { + return AH_SYSTEM; + } else if (split.length >= 2) { + return CertificateType.getTypeFromCNPart(split[1]); + } else { + return CertificateType.getTypeFromCNPart(split[0]); + } + } + + private static CertificateType getTypeFromCNPart(final String commonNamePart) { + for (CertificateType type : values()) { + if (type.commonNamePart.equalsIgnoreCase(commonNamePart)) { + return type; + } + } + return UNKNOWN; + } + + public boolean hasMinimumStrength(final CertificateType minimumStrengthType) { + Assert.notNull(minimumStrengthType, "CertificateType must not be null"); + return this.strength >= minimumStrengthType.strength; + } + + public String appendTypeToCN(final String commonName) { + if (Utilities.notEmpty(commonNamePart)) { + return commonName + '.' + commonNamePart; + } else { return commonName; } + } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/CloudRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/CloudRequestDTO.java index 798646856..877d0c55c 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/shared/CloudRequestDTO.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/CloudRequestDTO.java @@ -52,12 +52,15 @@ public boolean equals(final Object obj) { if (this == obj) { return true; } + if (obj == null) { return false; } + if (getClass() != obj.getClass()) { return false; } + final CloudRequestDTO other = (CloudRequestDTO) obj; return Objects.equals(name, other.name) && Objects.equals(operator, other.operator); diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceQueryFormDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceQueryFormDTO.java new file mode 100644 index 000000000..a4ae76efe --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceQueryFormDTO.java @@ -0,0 +1,151 @@ +package eu.arrowhead.common.dto.shared; + +import org.springframework.util.Assert; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.StringJoiner; + +public class DeviceQueryFormDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -2699823381165019336L; + + private String deviceNameRequirements; + private String addressRequirement; + private String macAddressRequirement; + private Map metadataRequirements; // if specified the whole content of the map must match + private Integer versionRequirement; // if specified version must match + private Integer minVersionRequirement; // if specified version must be equals or higher; ignored if versionRequirement is specified + private Integer maxVersionRequirement; // if specified version must be equals or lower; ignored if versionRequirement is specified + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public DeviceQueryFormDTO() {} + + //------------------------------------------------------------------------------------------------- + public String getDeviceNameRequirements() { return deviceNameRequirements; } + public String getAddressRequirement() { return addressRequirement; } + public String getMacAddressRequirement() { return macAddressRequirement; } + public Map getMetadataRequirements() { return metadataRequirements; } + public Integer getVersionRequirement() { return versionRequirement; } + public Integer getMinVersionRequirement() { return minVersionRequirement; } + public Integer getMaxVersionRequirement() { return maxVersionRequirement; } + + //------------------------------------------------------------------------------------------------- + public void setDeviceNameRequirements(final String deviceNameRequirements) { this.deviceNameRequirements = deviceNameRequirements; } + public void setAddressRequirement(final String addressRequirement) { this.addressRequirement = addressRequirement; } + public void setMacAddressRequirement(final String macAddressRequirement) { this.macAddressRequirement = macAddressRequirement; } + public void setMetadataRequirements(final Map metadataRequirements) { this.metadataRequirements = metadataRequirements; } + public void setVersionRequirement(final Integer versionRequirement) { this.versionRequirement = versionRequirement; } + public void setMinVersionRequirement(final Integer minVersionRequirement) { this.minVersionRequirement = minVersionRequirement; } + public void setMaxVersionRequirement(final Integer maxVersionRequirement) { this.maxVersionRequirement = maxVersionRequirement; } + + @Override + public String toString() { + return new StringJoiner(", ", DeviceQueryFormDTO.class.getSimpleName() + "[", "]") + .add("deviceNameRequirements='" + deviceNameRequirements + "'") + .add("addressRequirement='" + addressRequirement + "'") + .add("macAddressRequirement='" + macAddressRequirement + "'") + .add("metadataRequirements=" + metadataRequirements) + .add("versionRequirement=" + versionRequirement) + .add("minVersionRequirement=" + minVersionRequirement) + .add("maxVersionRequirement=" + maxVersionRequirement) + .toString(); + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + private DeviceQueryFormDTO(final Builder builder) { + this.deviceNameRequirements = builder.deviceNameRequirements; + this.addressRequirement = builder.addressRequirements; + this.macAddressRequirement = builder.macAddressRequirement; + this.metadataRequirements = builder.metadataRequirements; + this.versionRequirement = builder.versionRequirement; + this.minVersionRequirement = builder.minVersionRequirement; + this.maxVersionRequirement = builder.maxVersionRequirement; + } + + //================================================================================================= + // nested classes + + //------------------------------------------------------------------------------------------------- + public static class Builder { + + //================================================================================================= + // members + + private final String deviceNameRequirements; + private String addressRequirements; + private String macAddressRequirement; + private Map metadataRequirements; + private Integer versionRequirement; + private Integer minVersionRequirement; + private Integer maxVersionRequirement; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public Builder(final String deviceNameRequirements) { + Assert.isTrue(deviceNameRequirements != null && !deviceNameRequirements.isBlank(), "deviceNameRequirements is null or blank."); + this.deviceNameRequirements = deviceNameRequirements; + } + + + //------------------------------------------------------------------------------------------------- + public Builder address(final String address) { + this.addressRequirements = address; + return this; + } + + //------------------------------------------------------------------------------------------------- + public Builder macAddress(final String macAddress) { + this.macAddressRequirement = macAddress; + return this; + } + + //------------------------------------------------------------------------------------------------- + public Builder metadata(final Map metadataRequirements) { + this.metadataRequirements = metadataRequirements; + return this; + } + + //------------------------------------------------------------------------------------------------- + public Builder metadata(final String key, final String value) { + Assert.isTrue(key != null && !key.isBlank(), "Key is null or blank"); + + if (this.metadataRequirements == null) { + this.metadataRequirements = new HashMap<>(); + } + this.metadataRequirements.put(key, value); + + return this; + } + + //------------------------------------------------------------------------------------------------- + public Builder version(final Integer versionRequirement) { + this.versionRequirement = versionRequirement; + return this; + } + + //------------------------------------------------------------------------------------------------- + public Builder version(final Integer minVersionRequirement, final Integer maxVersionRequirement) { + this.minVersionRequirement = minVersionRequirement; + this.maxVersionRequirement = maxVersionRequirement; + return this; + } + + //------------------------------------------------------------------------------------------------- + public DeviceQueryFormDTO build() { + return new DeviceQueryFormDTO(this); + } + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceQueryResultDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceQueryResultDTO.java new file mode 100644 index 000000000..116bc78ec --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceQueryResultDTO.java @@ -0,0 +1,57 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class DeviceQueryResultDTO implements Serializable +{ + + //================================================================================================= + // members + + private static final long serialVersionUID = -1822444510232108526L; + + private List deviceQueryData = null; + private int unfilteredHits = 0; + + //================================================================================================= + // constructors + + public DeviceQueryResultDTO() + { + this(new ArrayList<>(), 0); + } + + public DeviceQueryResultDTO(final List deviceQueryData, final int unfilteredHits) + { + this.deviceQueryData = deviceQueryData; + this.unfilteredHits = unfilteredHits; + } + + @Override + public String toString() { + return new StringJoiner(", ", DeviceQueryResultDTO.class.getSimpleName() + "[", "]") + .add("deviceQueryData=" + deviceQueryData) + .add("unfilteredHits=" + unfilteredHits) + .toString(); + } + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public List getDeviceQueryData() { return deviceQueryData; } + + //------------------------------------------------------------------------------------------------- + public void setDeviceQueryData(final List deviceQueryData) { this.deviceQueryData = deviceQueryData; } + + public int getUnfilteredHits() { return unfilteredHits; } + + public void setUnfilteredHits(final int unfilteredHits) { this.unfilteredHits = unfilteredHits; } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingResponseDTO.java new file mode 100644 index 000000000..6dbe5e7e9 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingResponseDTO.java @@ -0,0 +1,61 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import org.springframework.util.Assert; + +import java.io.Serializable; +import java.util.Map; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public abstract class DeviceRegistryOnboardingResponseDTO extends DeviceRegistryResponseDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -635438605292398404L; + private CertificateCreationResponseDTO certificateResponse; + + //================================================================================================= + // methods + + public DeviceRegistryOnboardingResponseDTO() { + } + + public DeviceRegistryOnboardingResponseDTO(final long id, final DeviceResponseDTO device, final String endOfValidity, + final Map metadata, final int version, final String createdAt, final String updatedAt, + final CertificateCreationResponseDTO certificateResponse) { + super(id, device, endOfValidity, metadata, version, createdAt, updatedAt); + this.certificateResponse = certificateResponse; + } + + public void load(final DeviceRegistryResponseDTO dto) { + Assert.notNull(dto, "DeviceRegistryResponseDTO must not be null"); + + setId(dto.getId()); + setDevice(dto.getDevice()); + setEndOfValidity(dto.getEndOfValidity()); + setMetadata(dto.getMetadata()); + setVersion(dto.getVersion()); + setCreatedAt(dto.getCreatedAt()); + setUpdatedAt(dto.getUpdatedAt()); + } + + //------------------------------------------------------------------------------------------------- + public CertificateCreationResponseDTO getCertificateResponse() { + return certificateResponse; + } + + public void setCertificateResponse(final CertificateCreationResponseDTO certificateResponse) { + this.certificateResponse = certificateResponse; + } + + @Override + public String toString() { + return new StringJoiner(", ", DeviceRegistryOnboardingResponseDTO.class.getSimpleName() + "[", "]") + .add("certificateResponse=" + certificateResponse) + .add("parent=" + super.toString()) + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingWithCsrRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingWithCsrRequestDTO.java new file mode 100644 index 000000000..00ceabaed --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingWithCsrRequestDTO.java @@ -0,0 +1,62 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import java.io.Serializable; +import java.util.Map; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class DeviceRegistryOnboardingWithCsrRequestDTO extends DeviceRegistryRequestDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -635438605292398404L; + private String certificateSigningRequest; + + //================================================================================================= + // methods + + public DeviceRegistryOnboardingWithCsrRequestDTO() { + } + + //------------------------------------------------------------------------------------------------- + public DeviceRegistryOnboardingWithCsrRequestDTO(final DeviceRequestDTO device, final String endOfValidity, final String certificateSigningRequest) { + super(device, endOfValidity); + this.certificateSigningRequest = certificateSigningRequest; + } + + //------------------------------------------------------------------------------------------------- + public DeviceRegistryOnboardingWithCsrRequestDTO(final String deviceName, final String macAddress, final String endOfValidity, final String certificateSigningRequest) { + super(new DeviceRequestDTO(deviceName, macAddress), endOfValidity); + this.certificateSigningRequest = certificateSigningRequest; + } + + //------------------------------------------------------------------------------------------------- + public DeviceRegistryOnboardingWithCsrRequestDTO(final DeviceRequestDTO device, + final String endOfValidity, + final Map metadata, + final Integer version, final String certificateSigningRequest) { + super(device, endOfValidity, metadata, version); + this.certificateSigningRequest = certificateSigningRequest; + } + + //------------------------------------------------------------------------------------------------- + public String getCertificateSigningRequest() { + return certificateSigningRequest; + } + + public void setCertificateSigningRequest(final String certificateSigningRequest) { + this.certificateSigningRequest = certificateSigningRequest; + } + + @Override + public String toString() { + return new StringJoiner(", ", DeviceRegistryOnboardingWithCsrRequestDTO.class.getSimpleName() + "[", "]") + .add("certificateSigningRequest=" + certificateSigningRequest) + .add("parent=" + super.toString()) + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingWithCsrResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingWithCsrResponseDTO.java new file mode 100644 index 000000000..4dfeae54a --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingWithCsrResponseDTO.java @@ -0,0 +1,23 @@ +package eu.arrowhead.common.dto.shared; + +import java.io.Serializable; +import java.util.Map; + +public class DeviceRegistryOnboardingWithCsrResponseDTO extends DeviceRegistryOnboardingResponseDTO implements Serializable { + + //================================================================================================= + // members + private static final long serialVersionUID = 1L; + + public DeviceRegistryOnboardingWithCsrResponseDTO() { + } + + public DeviceRegistryOnboardingWithCsrResponseDTO(final long id, final DeviceResponseDTO device, final String endOfValidity, + final Map metadata, final int version, final String createdAt, + final String updatedAt, + final CertificateCreationResponseDTO certificateResponse) { + super(id, device, endOfValidity, metadata, version, createdAt, updatedAt, certificateResponse); + } + + // this class exist to keep the structure of RequestDTO, ResponseDTO +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingWithNameRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingWithNameRequestDTO.java new file mode 100644 index 000000000..92070ee76 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingWithNameRequestDTO.java @@ -0,0 +1,62 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import java.io.Serializable; +import java.util.Map; +import java.util.Objects; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class DeviceRegistryOnboardingWithNameRequestDTO extends DeviceRegistryRequestDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -635438605292398404L; + private CertificateCreationRequestDTO certificateCreationRequest; + + //================================================================================================= + // methods + + public DeviceRegistryOnboardingWithNameRequestDTO() { + } + + //------------------------------------------------------------------------------------------------- + public DeviceRegistryOnboardingWithNameRequestDTO(final DeviceRequestDTO device, final String endOfValidity) { + super(device, endOfValidity); + } + + //------------------------------------------------------------------------------------------------- + public DeviceRegistryOnboardingWithNameRequestDTO(final String deviceName, final String macAddress, final String endOfValidity) { + super(new DeviceRequestDTO(deviceName, macAddress), endOfValidity); + this.certificateCreationRequest = new CertificateCreationRequestDTO(deviceName); + } + + //------------------------------------------------------------------------------------------------- + public DeviceRegistryOnboardingWithNameRequestDTO(final DeviceRequestDTO device, + final String endOfValidity, + final Map metadata, + final Integer version) { + super(device, endOfValidity, metadata, version); + this.certificateCreationRequest = new CertificateCreationRequestDTO(Objects.requireNonNull(device).getDeviceName()); + } + + //------------------------------------------------------------------------------------------------- + public CertificateCreationRequestDTO getCertificateCreationRequest() { + return certificateCreationRequest; + } + + public void setCertificateCreationRequest(final CertificateCreationRequestDTO certificateCreationRequest) { + this.certificateCreationRequest = certificateCreationRequest; + } + + @Override + public String toString() { + return new StringJoiner(", ", DeviceRegistryOnboardingWithNameRequestDTO.class.getSimpleName() + "[", "]") + .add("certificateCreationRequest=" + certificateCreationRequest) + .add("parent=" + super.toString()) + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingWithNameResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingWithNameResponseDTO.java new file mode 100644 index 000000000..4c3079432 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryOnboardingWithNameResponseDTO.java @@ -0,0 +1,23 @@ +package eu.arrowhead.common.dto.shared; + +import java.io.Serializable; +import java.util.Map; + +public class DeviceRegistryOnboardingWithNameResponseDTO extends DeviceRegistryOnboardingResponseDTO implements Serializable { + + //================================================================================================= + // members + private static final long serialVersionUID = 1L; + + public DeviceRegistryOnboardingWithNameResponseDTO() { + } + + public DeviceRegistryOnboardingWithNameResponseDTO(final long id, final DeviceResponseDTO device, final String endOfValidity, + final Map metadata, final int version, final String createdAt, + final String updatedAt, + final CertificateCreationResponseDTO certificateResponse) { + super(id, device, endOfValidity, metadata, version, createdAt, updatedAt, certificateResponse); + } + + // this class exist to keep the structure of RequestDTO, ResponseDTO +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryRequestDTO.java new file mode 100644 index 000000000..3e5f34424 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryRequestDTO.java @@ -0,0 +1,63 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import org.springframework.util.Assert; + +import java.io.Serializable; +import java.util.Map; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class DeviceRegistryRequestDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -635438605292398404L; + + private DeviceRequestDTO device; + private String endOfValidity; + private Map metadata; + private Integer version; + + //================================================================================================= + // methods + + public DeviceRegistryRequestDTO() { + } + + public DeviceRegistryRequestDTO(final DeviceRequestDTO device, final String endOfValidity) {this.device = device; + this.endOfValidity = endOfValidity; + } + + //------------------------------------------------------------------------------------------------- + public DeviceRegistryRequestDTO(final DeviceRequestDTO device, final String endOfValidity, final Map metadata, final Integer version) { + this.device = device; + this.endOfValidity = endOfValidity; + this.metadata = metadata; + this.version = version; + } + + //------------------------------------------------------------------------------------------------- + public DeviceRequestDTO getDevice() { return device; } + public String getEndOfValidity() { return endOfValidity; } + public Map getMetadata() { return metadata; } + public Integer getVersion() { return version; } + + //------------------------------------------------------------------------------------------------- + public void setDevice(final DeviceRequestDTO device) { this.device = device; } + public void setEndOfValidity(final String endOfValidity) { this.endOfValidity = endOfValidity; } + public void setMetadata(final Map metadata) { this.metadata = metadata; } + public void setVersion(final Integer version) { this.version = version; } + + @Override + public String toString() { + return new StringJoiner(", ", DeviceRegistryRequestDTO.class.getSimpleName() + "[", "]") + .add("device=" + device) + .add("endOfValidity='" + endOfValidity + "'") + .add("metadata=" + metadata) + .add("version=" + version) + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryResponseDTO.java new file mode 100644 index 000000000..9abb13229 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRegistryResponseDTO.java @@ -0,0 +1,95 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import java.io.Serializable; +import java.util.Map; +import java.util.Objects; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class DeviceRegistryResponseDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -635438605292398404L; + + private long id; + private DeviceResponseDTO device; + private String endOfValidity; + private Map metadata; + private int version; + private String createdAt; + private String updatedAt; + + //================================================================================================= + // methods + + + public DeviceRegistryResponseDTO() { + } + + //------------------------------------------------------------------------------------------------- + public DeviceRegistryResponseDTO(final long id, final DeviceResponseDTO device, final String endOfValidity, + final Map metadata, final int version, final String createdAt, final String updatedAt) { + this.id = id; + this.device = device; + this.endOfValidity = endOfValidity; + this.metadata = metadata; + this.version = version; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + //------------------------------------------------------------------------------------------------- + public long getId() { return id; } + public DeviceResponseDTO getDevice() { return device; } + public String getEndOfValidity() { return endOfValidity; } + public Map getMetadata() { return metadata; } + public int getVersion() { return version; } + public String getCreatedAt() { return createdAt; } + public String getUpdatedAt() { return updatedAt; } + + //------------------------------------------------------------------------------------------------- + public void setId(final long id) { this.id = id; } + public void setDevice(final DeviceResponseDTO device) { this.device = device; } + public void setEndOfValidity(final String endOfValidity) { this.endOfValidity = endOfValidity; } + public void setMetadata(final Map metadata) { this.metadata = metadata; } + public void setVersion(final int version) { this.version = version; } + public void setCreatedAt(final String createdAt) { this.createdAt = createdAt; } + public void setUpdatedAt(final String updatedAt) { this.updatedAt = updatedAt; } + + @Override + public boolean equals(final Object o) { + if (this == o) { return true; } + if (o == null || getClass() != o.getClass()) { return false; } + final DeviceRegistryResponseDTO that = (DeviceRegistryResponseDTO) o; + return id == that.id && + version == that.version && + device.equals(that.device) && + Objects.equals(endOfValidity, that.endOfValidity) && + Objects.equals(metadata, that.metadata) && + createdAt.equals(that.createdAt) && + updatedAt.equals(that.updatedAt); + } + + @Override + public int hashCode() { + return Objects.hash(id, device, endOfValidity, metadata, version, createdAt, updatedAt); + } + + @Override + public String toString() { + return new StringJoiner(", ", DeviceRegistryResponseDTO.class.getSimpleName() + "[", "]") + .add("id=" + id) + .add("device=" + device) + .add("endOfValidity='" + endOfValidity + "'") + .add("metadata=" + metadata) + .add("version=" + version) + .add("createdAt='" + createdAt + "'") + .add("updatedAt='" + updatedAt + "'") + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRequestDTO.java new file mode 100644 index 000000000..3fbbbc479 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceRequestDTO.java @@ -0,0 +1,101 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import java.io.Serializable; +import java.util.Objects; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class DeviceRequestDTO implements Serializable +{ + + //================================================================================================= + // members + + private static final long serialVersionUID = 3919207845374510215L; + + private String deviceName; + private String address; + private String macAddress; + private String authenticationInfo; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public DeviceRequestDTO() {} + + public DeviceRequestDTO(final String deviceName, final String macAddress) { + this.deviceName = deviceName; + this.macAddress = macAddress; + } + + //------------------------------------------------------------------------------------------------- + public DeviceRequestDTO(final String deviceName, final String address, final String macAddress, final String authenticationInfo) + { + this.deviceName = deviceName; + this.address = address; + this.macAddress = macAddress; + this.authenticationInfo = authenticationInfo; + } + + //------------------------------------------------------------------------------------------------- + public String getDeviceName() { return deviceName; } + + //------------------------------------------------------------------------------------------------- + public void setDeviceName(final String deviceName) { this.deviceName = deviceName; } + + public String getAddress() { return address; } + + public void setAddress(final String address) { this.address = address; } + + public String getMacAddress() { return macAddress; } + + public void setMacAddress(final String macAddress) { this.macAddress = macAddress; } + + public String getAuthenticationInfo() { return authenticationInfo; } + + public void setAuthenticationInfo(final String authenticationInfo) { this.authenticationInfo = authenticationInfo; } + + //------------------------------------------------------------------------------------------------- + @Override + public int hashCode() + { + return Objects.hash(address, macAddress, deviceName); + } + + //------------------------------------------------------------------------------------------------- + @Override + public boolean equals(final Object obj) + { + if (this == obj) + { + return true; + } + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final DeviceRequestDTO other = (DeviceRequestDTO) obj; + + return Objects.equals(address, other.address) && + Objects.equals(macAddress, other.macAddress) && + Objects.equals(deviceName, other.deviceName); + } + + @Override + public String toString() { + return new StringJoiner(", ", DeviceRequestDTO.class.getSimpleName() + "[", "]") + .add("deviceName='" + deviceName + "'") + .add("address='" + address + "'") + .add("macAddress='" + macAddress + "'") + .add("authenticationInfo='" + authenticationInfo + "'") + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceResponseDTO.java new file mode 100644 index 000000000..cd3a44b1b --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/DeviceResponseDTO.java @@ -0,0 +1,98 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import java.io.Serializable; +import java.util.Objects; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class DeviceResponseDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = 3919207845374510215L; + + private long id; + private String deviceName; + private String address; + private String macAddress; + private String authenticationInfo; + private String createdAt; + private String updatedAt; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public DeviceResponseDTO() {} + + //------------------------------------------------------------------------------------------------- + public DeviceResponseDTO(final long deviceId, final String deviceName, final String address, final String macAddress, final String authenticationInfo, final String createdAt, final String upDatedAt) { + this.id = deviceId; + this.deviceName = deviceName; + this.address = address; + this.macAddress = macAddress; + this.authenticationInfo = authenticationInfo; + this.createdAt = createdAt; + this.updatedAt = upDatedAt; + } + + //------------------------------------------------------------------------------------------------- + public long getId() { return id; } + public String getDeviceName() { return deviceName; } + public String getAddress() { return address; } + public String getMacAddress() { return macAddress; } + public String getAuthenticationInfo() { return authenticationInfo; } + public String getUpdatedAt() { return updatedAt; } + public String getCreatedAt() { return createdAt; } + + //------------------------------------------------------------------------------------------------- + public void setId(final long sytemId) { this.id = sytemId; } + public void setDeviceName(final String deviceName) { this.deviceName = deviceName; } + public void setAddress(final String address) { this.address = address; } + public void setMacAddress(final String macAddress) { this.macAddress = macAddress; } + public void setAuthenticationInfo(final String authenticationInfo) { this.authenticationInfo = authenticationInfo; } + public void setCreatedAt(final String createdAt) { this.createdAt = createdAt; } + public void setUpdatedAt(final String updatedAt) { this.updatedAt = updatedAt; } + + //------------------------------------------------------------------------------------------------- + @Override + public int hashCode() { + return Objects.hash(address, macAddress, deviceName); + } + + //------------------------------------------------------------------------------------------------- + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final DeviceResponseDTO other = (DeviceResponseDTO) obj; + + return Objects.equals(address, other.address) && + Objects.equals(macAddress, other.macAddress) && + Objects.equals(deviceName, other.deviceName); + } + + @Override + public String toString() { + return new StringJoiner(", ", DeviceResponseDTO.class.getSimpleName() + "[", "]") + .add("id=" + id) + .add("deviceName='" + deviceName + "'") + .add("address='" + address + "'") + .add("macAddress='" + macAddress + "'") + .add("authenticationInfo='" + authenticationInfo + "'") + .add("createdAt='" + createdAt + "'") + .add("updatedAt='" + updatedAt + "'") + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/KeyPairDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/KeyPairDTO.java new file mode 100644 index 000000000..ef38df1d3 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/KeyPairDTO.java @@ -0,0 +1,64 @@ +package eu.arrowhead.common.dto.shared; + +import java.io.Serializable; +import java.util.Objects; +import java.util.StringJoiner; + +public class KeyPairDTO implements Serializable { + + private String keyAlgorithm; + private String keyFormat; + private String publicKey; + private String privateKey; + + public KeyPairDTO() { super(); } + + public KeyPairDTO(final String keyAlgorithm, final String keyFormat, final String publicKey, final String privateKey) { + this.keyAlgorithm = keyAlgorithm; + this.keyFormat = keyFormat; + this.publicKey = publicKey; + this.privateKey = privateKey; + } + + public String getKeyAlgorithm() { + return keyAlgorithm; + } + + public void setKeyAlgorithm(final String keyAlgorithm) { + this.keyAlgorithm = keyAlgorithm; + } + + public String getKeyFormat() { + return keyFormat; + } + + public void setKeyFormat(final String keyFormat) { + this.keyFormat = keyFormat; + } + + public String getPublicKey() { + return publicKey; + } + + public void setPublicKey(final String publicKey) { + this.publicKey = publicKey; + } + + public String getPrivateKey() { + return privateKey; + } + + public void setPrivateKey(final String privateKey) { + this.privateKey = privateKey; + } + + @Override + public String toString() { + return new StringJoiner(", ", KeyPairDTO.class.getSimpleName() + "[", "]") + .add("keyAlgorithm='" + keyAlgorithm + "'") + .add("keyFormat='" + keyFormat + "'") + .add("publicKey='" + publicKey + "'") + .add("privateKey='" + Objects.nonNull(privateKey) + "'") + .toString(); + } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingResponseDTO.java new file mode 100644 index 000000000..d0d5be908 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingResponseDTO.java @@ -0,0 +1,123 @@ +package eu.arrowhead.common.dto.shared; + +import java.io.Serializable; +import java.util.StringJoiner; + +public abstract class OnboardingResponseDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = 1L; + private ServiceEndpoint deviceRegistry; + private ServiceEndpoint systemRegistry; + private ServiceEndpoint serviceRegistry; + private ServiceEndpoint orchestrationService; + + private CertificateCreationResponseDTO onboardingCertificate; + private String intermediateCertificate; + private String rootCertificate; + + + public OnboardingResponseDTO() { + } + + public OnboardingResponseDTO(final ServiceEndpoint deviceRegistry, final ServiceEndpoint systemRegistry, final ServiceEndpoint serviceRegistry, + final ServiceEndpoint orchestrationService, final CertificateCreationResponseDTO onboardingCertificate, + final String intermediateCertificate, final String rootCertificate) { + this.deviceRegistry = deviceRegistry; + this.systemRegistry = systemRegistry; + this.serviceRegistry = serviceRegistry; + this.orchestrationService = orchestrationService; + this.onboardingCertificate = onboardingCertificate; + this.intermediateCertificate = intermediateCertificate; + this.rootCertificate = rootCertificate; + } + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public ServiceEndpoint getDeviceRegistry() { + return deviceRegistry; + } + + //------------------------------------------------------------------------------------------------- + public void setDeviceRegistry(final ServiceEndpoint deviceRegistry) { + this.deviceRegistry = deviceRegistry; + } + + //------------------------------------------------------------------------------------------------- + public ServiceEndpoint getSystemRegistry() { + return systemRegistry; + } + + //------------------------------------------------------------------------------------------------- + public void setSystemRegistry(final ServiceEndpoint systemRegistry) { + this.systemRegistry = systemRegistry; + } + + //------------------------------------------------------------------------------------------------- + public ServiceEndpoint getServiceRegistry() { + return serviceRegistry; + } + + //------------------------------------------------------------------------------------------------- + public void setServiceRegistry(final ServiceEndpoint serviceRegistry) { + this.serviceRegistry = serviceRegistry; + } + + //------------------------------------------------------------------------------------------------- + public ServiceEndpoint getOrchestrationService() { + return orchestrationService; + } + + //------------------------------------------------------------------------------------------------- + public void setOrchestrationService(ServiceEndpoint orchestrationService) { + this.orchestrationService = orchestrationService; + } + + //------------------------------------------------------------------------------------------------- + public CertificateCreationResponseDTO getOnboardingCertificate() { + return onboardingCertificate; + } + + //------------------------------------------------------------------------------------------------- + public void setOnboardingCertificate(final CertificateCreationResponseDTO onboardingCertificate) { + this.onboardingCertificate = onboardingCertificate; + } + + //------------------------------------------------------------------------------------------------- + public String getIntermediateCertificate() { + return intermediateCertificate; + } + + //------------------------------------------------------------------------------------------------- + public void setIntermediateCertificate(final String intermediateCertificate) { + this.intermediateCertificate = intermediateCertificate; + } + + //------------------------------------------------------------------------------------------------- + public String getRootCertificate() { + return rootCertificate; + } + + //------------------------------------------------------------------------------------------------- + public void setRootCertificate(final String rootCertificate) { + this.rootCertificate = rootCertificate; + } + + + @Override + public String toString() { + return new StringJoiner(", ", OnboardingResponseDTO.class.getSimpleName() + "[", "]") + .add("deviceRegistry=" + deviceRegistry) + .add("systemRegistry=" + systemRegistry) + .add("serviceRegistry=" + serviceRegistry) + .add("orchestrationService=" + orchestrationService) + .add("onboardingCertificate=" + onboardingCertificate) + .add("intermediateCertificate='" + intermediateCertificate + "'") + .add("rootCertificate='" + rootCertificate + "'") + .toString(); + } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingWithCsrRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingWithCsrRequestDTO.java new file mode 100644 index 000000000..984c1a528 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingWithCsrRequestDTO.java @@ -0,0 +1,63 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import java.io.Serializable; +import java.util.Objects; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class OnboardingWithCsrRequestDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = 1L; + + private String certificateSigningRequest; + + //================================================================================================= + // methods + //------------------------------------------------------------------------------------------------- + public String getCertificateSigningRequest() { return certificateSigningRequest; } + + //------------------------------------------------------------------------------------------------- + public void setCertificateSigningRequest(final String certificateSigningRequest) { this.certificateSigningRequest = certificateSigningRequest; } + + //------------------------------------------------------------------------------------------------- + @Override + public int hashCode() + { + return Objects.hash(certificateSigningRequest); + } + + //------------------------------------------------------------------------------------------------- + @Override + public boolean equals(final Object obj) + { + if (this == obj) + { + return true; + } + if (obj == null) + { + return false; + } + if (getClass() != obj.getClass()) + { + return false; + } + final OnboardingWithCsrRequestDTO other = (OnboardingWithCsrRequestDTO) obj; + + return Objects.equals(certificateSigningRequest, other.certificateSigningRequest); + } + + @Override + public String toString() { + return new StringJoiner(", ", OnboardingWithCsrRequestDTO.class.getSimpleName() + "[", "]") + .add("certificateSigningRequest='" + certificateSigningRequest + "'") + .add("parent=" + super.toString()) + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingWithCsrResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingWithCsrResponseDTO.java new file mode 100644 index 000000000..e5f3fa047 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingWithCsrResponseDTO.java @@ -0,0 +1,22 @@ +package eu.arrowhead.common.dto.shared; + +import java.io.Serializable; + +public class OnboardingWithCsrResponseDTO extends OnboardingResponseDTO implements Serializable { + + //================================================================================================= + // members + private static final long serialVersionUID = 1L; + + public OnboardingWithCsrResponseDTO() { + } + + public OnboardingWithCsrResponseDTO(final ServiceEndpoint deviceRegistry, final ServiceEndpoint systemRegistry, + final ServiceEndpoint serviceRegistry, final ServiceEndpoint orchestrationService, + final CertificateCreationResponseDTO onboardingCertificate, final String intermediateCertificate, + final String rootCertificate) { + super(deviceRegistry, systemRegistry, serviceRegistry, orchestrationService, onboardingCertificate, intermediateCertificate, rootCertificate); + } + + // this class exist to keep the structure of RequestDTO, ResponseDTO +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingWithNameRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingWithNameRequestDTO.java new file mode 100644 index 000000000..56ff849d7 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingWithNameRequestDTO.java @@ -0,0 +1,48 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import java.io.Serializable; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class OnboardingWithNameRequestDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = 1L; + + private CertificateCreationRequestDTO creationRequestDTO; + + //================================================================================================= + // constructors + + public OnboardingWithNameRequestDTO() { + } + + public OnboardingWithNameRequestDTO(CertificateCreationRequestDTO creationRequestDTO) { + this.creationRequestDTO = creationRequestDTO; + } + + //================================================================================================= + // methods + //------------------------------------------------------------------------------------------------- + + public CertificateCreationRequestDTO getCreationRequestDTO() { + return creationRequestDTO; + } + + public void setCreationRequestDTO(CertificateCreationRequestDTO creationRequestDTO) { + this.creationRequestDTO = creationRequestDTO; + } + + @Override + public String toString() { + return new StringJoiner(", ", OnboardingWithNameRequestDTO.class.getSimpleName() + "[", "]") + .add("creationRequestDTO=" + creationRequestDTO) + .add("parent=" + super.toString()) + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingWithNameResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingWithNameResponseDTO.java new file mode 100644 index 000000000..8af13a480 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OnboardingWithNameResponseDTO.java @@ -0,0 +1,20 @@ +package eu.arrowhead.common.dto.shared; + +public class OnboardingWithNameResponseDTO extends OnboardingResponseDTO { + + //================================================================================================= + // members + private static final long serialVersionUID = 1L; + + public OnboardingWithNameResponseDTO() { + } + + public OnboardingWithNameResponseDTO(final ServiceEndpoint deviceRegistry, final ServiceEndpoint systemRegistry, + final ServiceEndpoint serviceRegistry, final ServiceEndpoint orchestrationService, + final CertificateCreationResponseDTO onboardingCertificate, final String intermediateCertificate, + final String rootCertificate) { + super(deviceRegistry, systemRegistry, serviceRegistry, orchestrationService, onboardingCertificate, intermediateCertificate, rootCertificate); + } + + // this class exist to keep the structure of RequestDTO, ResponseDTO +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/OrchestrationFlags.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OrchestrationFlags.java index 9744eeb4d..2ef72f100 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/shared/OrchestrationFlags.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OrchestrationFlags.java @@ -64,15 +64,15 @@ public boolean containsKey(final Flag flag) { //------------------------------------------------------------------------------------------------- private static Map initFlagMap() { final Map result = new HashMap<>(Flag.values().length); - result.put(CommonConstants.ORCHESTRATON_FLAG_MATCHMAKING, Flag.MATCHMAKING); - result.put(CommonConstants.ORCHESTRATON_FLAG_METADATA_SEARCH, Flag.METADATA_SEARCH); - result.put(CommonConstants.ORCHESTRATON_FLAG_ONLY_PREFERRED, Flag.ONLY_PREFERRED); - result.put(CommonConstants.ORCHESTRATON_FLAG_PING_PROVIDERS, Flag.PING_PROVIDERS); - result.put(CommonConstants.ORCHESTRATON_FLAG_OVERRIDE_STORE, Flag.OVERRIDE_STORE); - result.put(CommonConstants.ORCHESTRATON_FLAG_TRIGGER_INTER_CLOUD, Flag.TRIGGER_INTER_CLOUD); - result.put(CommonConstants.ORCHESTRATON_FLAG_EXTERNAL_SERVICE_REQUEST, Flag.EXTERNAL_SERVICE_REQUEST); - result.put(CommonConstants.ORCHESTRATON_FLAG_ENABLE_INTER_CLOUD, Flag.ENABLE_INTER_CLOUD); - result.put(CommonConstants.ORCHESTRATON_FLAG_ENABLE_QOS, Flag.ENABLE_QOS); + result.put(CommonConstants.ORCHESTRATION_FLAG_MATCHMAKING, Flag.MATCHMAKING); + result.put(CommonConstants.ORCHESTRATION_FLAG_METADATA_SEARCH, Flag.METADATA_SEARCH); + result.put(CommonConstants.ORCHESTRATION_FLAG_ONLY_PREFERRED, Flag.ONLY_PREFERRED); + result.put(CommonConstants.ORCHESTRATION_FLAG_PING_PROVIDERS, Flag.PING_PROVIDERS); + result.put(CommonConstants.ORCHESTRATION_FLAG_OVERRIDE_STORE, Flag.OVERRIDE_STORE); + result.put(CommonConstants.ORCHESTRATION_FLAG_TRIGGER_INTER_CLOUD, Flag.TRIGGER_INTER_CLOUD); + result.put(CommonConstants.ORCHESTRATION_FLAG_EXTERNAL_SERVICE_REQUEST, Flag.EXTERNAL_SERVICE_REQUEST); + result.put(CommonConstants.ORCHESTRATION_FLAG_ENABLE_INTER_CLOUD, Flag.ENABLE_INTER_CLOUD); + result.put(CommonConstants.ORCHESTRATION_FLAG_ENABLE_QOS, Flag.ENABLE_QOS); return result; } @@ -86,15 +86,15 @@ public enum Flag { //================================================================================================= // elements - MATCHMAKING(CommonConstants.ORCHESTRATON_FLAG_MATCHMAKING), - METADATA_SEARCH(CommonConstants.ORCHESTRATON_FLAG_METADATA_SEARCH), - ONLY_PREFERRED(CommonConstants.ORCHESTRATON_FLAG_ONLY_PREFERRED), - PING_PROVIDERS(CommonConstants.ORCHESTRATON_FLAG_PING_PROVIDERS), - OVERRIDE_STORE(CommonConstants.ORCHESTRATON_FLAG_OVERRIDE_STORE), - TRIGGER_INTER_CLOUD(CommonConstants.ORCHESTRATON_FLAG_TRIGGER_INTER_CLOUD), - EXTERNAL_SERVICE_REQUEST(CommonConstants.ORCHESTRATON_FLAG_EXTERNAL_SERVICE_REQUEST), - ENABLE_INTER_CLOUD(CommonConstants.ORCHESTRATON_FLAG_ENABLE_INTER_CLOUD), - ENABLE_QOS(CommonConstants.ORCHESTRATON_FLAG_ENABLE_QOS); + MATCHMAKING(CommonConstants.ORCHESTRATION_FLAG_MATCHMAKING), + METADATA_SEARCH(CommonConstants.ORCHESTRATION_FLAG_METADATA_SEARCH), + ONLY_PREFERRED(CommonConstants.ORCHESTRATION_FLAG_ONLY_PREFERRED), + PING_PROVIDERS(CommonConstants.ORCHESTRATION_FLAG_PING_PROVIDERS), + OVERRIDE_STORE(CommonConstants.ORCHESTRATION_FLAG_OVERRIDE_STORE), + TRIGGER_INTER_CLOUD(CommonConstants.ORCHESTRATION_FLAG_TRIGGER_INTER_CLOUD), + EXTERNAL_SERVICE_REQUEST(CommonConstants.ORCHESTRATION_FLAG_EXTERNAL_SERVICE_REQUEST), + ENABLE_INTER_CLOUD(CommonConstants.ORCHESTRATION_FLAG_ENABLE_INTER_CLOUD), + ENABLE_QOS(CommonConstants.ORCHESTRATION_FLAG_ENABLE_QOS); //================================================================================================= // members diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/OrchestrationFormRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OrchestrationFormRequestDTO.java index fe81c1f69..98509fdf8 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/shared/OrchestrationFormRequestDTO.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/OrchestrationFormRequestDTO.java @@ -14,18 +14,27 @@ import eu.arrowhead.common.exception.BadPayloadException; public class OrchestrationFormRequestDTO implements Serializable { + + public static final String QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD = "qosMaxRespTimeThreshold"; // in milliseconds, it means the maximum value of the maximum response time + public static final String QOS_REQUIREMENT_AVERAGE_RESPONSE_TIME_THRESHOLD = "qosAvgRespTime"; // in milliseconds, it means the maximum value of the average (mean) response time + public static final String QOS_REQUIREMENT_JITTER_THRESHOLD = "qosJitterThreshold"; // in milliseconds, it mean the maximum acceptable jitter + public static final String QOS_REQUIREMENT_MAXIMUM_RECENT_PACKET_LOSS = "qosMaxRecentPacketLoss"; // in percent, for example 20% is 20 + public static final String QOS_REQUIREMENT_MAXIMUM_PACKET_LOSS = "qosMaxPacketLost"; // in percent + + public static final String QOS_COMMAND_EXCLUSIVITY = "qosExclusivity"; // in seconds //================================================================================================= // members - private static final long serialVersionUID = -3595427649312358521L; - + private static final long serialVersionUID = 5875552294338921238L; + private SystemRequestDTO requesterSystem; private CloudRequestDTO requesterCloud; private ServiceQueryFormDTO requestedService; private OrchestrationFlags orchestrationFlags = new OrchestrationFlags(); private List preferredProviders = new ArrayList<>(); private Map commands = new HashMap<>(); + private Map qosRequirements = new HashMap<>(); //================================================================================================= // methods @@ -40,13 +49,20 @@ public OrchestrationFormRequestDTO() {} public OrchestrationFlags getOrchestrationFlags() { return orchestrationFlags; } public List getPreferredProviders() { return preferredProviders; } public Map getCommands() { return commands; } - + public Map getQosRequirements() { return qosRequirements; } + //------------------------------------------------------------------------------------------------- public void setRequesterSystem(final SystemRequestDTO requesterSystem) { this.requesterSystem = requesterSystem; } public void setRequesterCloud(final CloudRequestDTO requesterCloud) { this.requesterCloud = requesterCloud; } public void setRequestedService(final ServiceQueryFormDTO requestedService) { this.requestedService = requestedService; } public void setOrchestrationFlags(final Map orchestrationFlags) { this.orchestrationFlags = new OrchestrationFlags(orchestrationFlags); } - public void setCommands(final Map commands) { this.commands = commands; } + + //------------------------------------------------------------------------------------------------- + public void setCommands(final Map commands) { + if (commands != null) { + this.commands = commands; + } + } //------------------------------------------------------------------------------------------------- public void setPreferredProviders(final List preferredProviders) { @@ -55,6 +71,13 @@ public void setPreferredProviders(final List preferred } } + //------------------------------------------------------------------------------------------------- + public void setQosRequirements(final Map qosRequirements) { + if (qosRequirements != null) { + this.qosRequirements = qosRequirements; + } + } + //------------------------------------------------------------------------------------------------- public OrchestrationFormRequestDTO validateCrossParameterConstraints() { if (requestedService == null && orchestrationFlags.get(Flag.OVERRIDE_STORE)) { @@ -77,6 +100,10 @@ public OrchestrationFormRequestDTO validateCrossParameterConstraints() { throw new BadPayloadException("There is no valid preferred provider, but \"" + Flag.ONLY_PREFERRED + "\" is set to true"); } } + + if (orchestrationFlags.get(Flag.ENABLE_QOS) && commands.containsKey(QOS_COMMAND_EXCLUSIVITY) && !orchestrationFlags.get(Flag.MATCHMAKING)) { + throw new BadPayloadException("Exclusive service orchestration is only possible when \"" + Flag.MATCHMAKING + "\" is set to true"); + } return this; } @@ -91,7 +118,8 @@ private OrchestrationFormRequestDTO(final Builder builder) { this.requestedService = builder.requestedService; this.orchestrationFlags = builder.orchestrationFlags; this.preferredProviders = builder.preferredProviders; - this.commands = builder.commands; + this.setCommands(builder.commands); + this.setQosRequirements(builder.qosRequirements); } //================================================================================================= @@ -109,6 +137,7 @@ public static class Builder { private final OrchestrationFlags orchestrationFlags = new OrchestrationFlags(); private List preferredProviders = new ArrayList<>(); private Map commands = new HashMap<>(); + private Map qosRequirements = new HashMap<>(); //================================================================================================= // methods @@ -168,6 +197,24 @@ public Builder command(final String key, final String value) { } + //------------------------------------------------------------------------------------------------- + public Builder qosRequirements(final Map qosRequirements) { + this.qosRequirements = qosRequirements; + return this; + } + + //------------------------------------------------------------------------------------------------- + public Builder qosRequirement(final String key, final String value) { + Assert.isTrue(key != null && !key.isBlank(), "Key is null or blank"); + + if (this.qosRequirements == null) { + this.qosRequirements = new HashMap<>(); + } + this.qosRequirements.put(key, value); + + return this; + } + //------------------------------------------------------------------------------------------------- public OrchestrationFormRequestDTO build() { return new OrchestrationFormRequestDTO(this).validateCrossParameterConstraints(); diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/PreferredProviderDataDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/PreferredProviderDataDTO.java index 7d0e3309c..cd659c94c 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/shared/PreferredProviderDataDTO.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/PreferredProviderDataDTO.java @@ -22,8 +22,8 @@ public class PreferredProviderDataDTO implements Serializable { public CloudRequestDTO getProviderCloud() { return providerCloud; } //------------------------------------------------------------------------------------------------- - public void setProviderSystem(SystemRequestDTO providerSystem) { this.providerSystem = providerSystem; } - public void setProviderCloud(CloudRequestDTO providerCloud) { this.providerCloud = providerCloud; } + public void setProviderSystem(final SystemRequestDTO providerSystem) { this.providerSystem = providerSystem; } + public void setProviderCloud(final CloudRequestDTO providerCloud) { this.providerCloud = providerCloud; } //------------------------------------------------------------------------------------------------- @JsonIgnore diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/QoSMeasurementType.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/QoSMeasurementType.java new file mode 100644 index 000000000..ad56b33c0 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/QoSMeasurementType.java @@ -0,0 +1,5 @@ +package eu.arrowhead.common.dto.shared; + +public enum QoSMeasurementType { + PING +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/ServiceEndpoint.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/ServiceEndpoint.java new file mode 100644 index 000000000..e2a2591df --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/ServiceEndpoint.java @@ -0,0 +1,44 @@ +package eu.arrowhead.common.dto.shared; + +import eu.arrowhead.common.core.CoreSystemService; + +import java.io.Serializable; +import java.net.URI; +import java.util.StringJoiner; + +public class ServiceEndpoint implements Serializable { + + //================================================================================================= + // members + private static final long serialVersionUID = 1L; + + private CoreSystemService system; + private URI uri; + + public ServiceEndpoint() { + super(); + } + + public ServiceEndpoint(final CoreSystemService service, final URI uri) { + this.system = service; + this.uri = uri; + } + + public CoreSystemService getService() { + return system; + } + public void setSystem(final CoreSystemService system) { this.system = system; } + + public URI getUri() { + return uri; + } + public void setUri(final URI uri) { this.uri = uri; } + + @Override + public String toString() { + return new StringJoiner(", ", ServiceEndpoint.class.getSimpleName() + "[", "]") + .add("system=" + system) + .add("uri=" + uri) + .toString(); + } +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/ServiceRegistryRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/ServiceRegistryRequestDTO.java index 0631ffab6..023cc2167 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/shared/ServiceRegistryRequestDTO.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/ServiceRegistryRequestDTO.java @@ -3,12 +3,15 @@ import java.io.Serializable; import java.util.List; import java.util.Map; +import java.util.StringJoiner; public class ServiceRegistryRequestDTO implements Serializable { //================================================================================================= // members + public static final String KEY_RECOMMENDED_ORCHESTRATION_TIME = "recommendedOrchestrationTime"; // in seconds + private static final long serialVersionUID = -3805773665976065056L; private String serviceDefinition; @@ -19,7 +22,37 @@ public class ServiceRegistryRequestDTO implements Serializable { private Map metadata; private Integer version; private List interfaces; - + + //================================================================================================= + // constructors + + public ServiceRegistryRequestDTO() { + } + + public ServiceRegistryRequestDTO(final String serviceDefinition, final SystemRequestDTO providerSystem, final String serviceUri, final String endOfValidity, + final String secure, + final List interfaces) { + this.serviceDefinition = serviceDefinition; + this.providerSystem = providerSystem; + this.serviceUri = serviceUri; + this.endOfValidity = endOfValidity; + this.secure = secure; + this.interfaces = interfaces; + } + + public ServiceRegistryRequestDTO(final String serviceDefinition, final SystemRequestDTO providerSystem, final String serviceUri, final String endOfValidity, + final String secure, + final Map metadata, final Integer version, final List interfaces) { + this.serviceDefinition = serviceDefinition; + this.providerSystem = providerSystem; + this.serviceUri = serviceUri; + this.endOfValidity = endOfValidity; + this.secure = secure; + this.metadata = metadata; + this.version = version; + this.interfaces = interfaces; + } + //================================================================================================= // methods @@ -39,7 +72,23 @@ public class ServiceRegistryRequestDTO implements Serializable { public void setServiceUri(final String serviceUri) { this.serviceUri = serviceUri; } public void setEndOfValidity(final String endOfValidity) { this.endOfValidity = endOfValidity; } public void setSecure(final String secure) { this.secure = secure; } - public void setMetadata(Map metadata) { this.metadata = metadata; } + public void setMetadata(final Map metadata) { this.metadata = metadata; } public void setVersion(final Integer version) { this.version = version; } public void setInterfaces(final List interfaces) { this.interfaces = interfaces; } -} \ No newline at end of file + + //------------------------------------------------------------------------------------------------- + + @Override + public String toString() { + return new StringJoiner(", ", ServiceRegistryRequestDTO.class.getSimpleName() + "[", "]") + .add("serviceDefinition='" + serviceDefinition + "'") + .add("providerSystem=" + providerSystem) + .add("serviceUri='" + serviceUri + "'") + .add("endOfValidity='" + endOfValidity + "'") + .add("secure='" + secure + "'") + .add("metadata=" + metadata) + .add("version=" + version) + .add("interfaces=" + interfaces) + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/ServiceRegistryResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/ServiceRegistryResponseDTO.java index 4d01c1c5a..ea94960a1 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/shared/ServiceRegistryResponseDTO.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/ServiceRegistryResponseDTO.java @@ -3,6 +3,7 @@ import java.io.Serializable; import java.util.List; import java.util.Map; +import java.util.StringJoiner; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -55,4 +56,22 @@ public class ServiceRegistryResponseDTO implements Serializable { public void setInterfaces(final List interfaces) { this.interfaces = interfaces; } public void setCreatedAt(final String createdAt) { this.createdAt = createdAt; } public void setUpdatedAt(final String updatedAt) { this.updatedAt = updatedAt; } + + //------------------------------------------------------------------------------------------------- + @Override + public String toString() { + return new StringJoiner(", ", ServiceRegistryResponseDTO.class.getSimpleName() + "[", "]") + .add("id=" + id) + .add("serviceDefinition=" + serviceDefinition) + .add("provider=" + provider) + .add("serviceUri='" + serviceUri + "'") + .add("endOfValidity='" + endOfValidity + "'") + .add("secure=" + secure) + .add("metadata=" + metadata) + .add("version=" + version) + .add("interfaces=" + interfaces) + .add("createdAt='" + createdAt + "'") + .add("updatedAt='" + updatedAt + "'") + .toString(); + } } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SubscriptionResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SubscriptionResponseDTO.java index cfd5d964f..82e67caca 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SubscriptionResponseDTO.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SubscriptionResponseDTO.java @@ -68,6 +68,6 @@ public SubscriptionResponseDTO(final long id, final EventTypeResponseDTO eventTy public void setStartDate(final String startDate) { this.startDate = startDate; } public void setEndDate(final String endDate) { this.endDate = endDate; } public void setSources(final Set sources) { this.sources = sources; } - public void setCreatedAt( final String createdAt ) { this.createdAt = createdAt; } - public void setUpdatedAt( final String updatedAt ) { this.updatedAt = updatedAt; } + public void setCreatedAt(final String createdAt) { this.createdAt = createdAt; } + public void setUpdatedAt(final String updatedAt) { this.updatedAt = updatedAt; } } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemQueryFormDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemQueryFormDTO.java new file mode 100644 index 000000000..3e47de93a --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemQueryFormDTO.java @@ -0,0 +1,153 @@ +package eu.arrowhead.common.dto.shared; + +import org.springframework.util.Assert; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import java.util.StringJoiner; + +public class SystemQueryFormDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -2699823381165019336L; + + private String systemNameRequirements; + private String deviceNameRequirements; + private Map metadataRequirements; // if specified the whole content of the map must match + private Integer versionRequirement; // if specified version must match + private Integer minVersionRequirement; // if specified version must be equals or higher; ignored if versionRequirement is specified + private Integer maxVersionRequirement; // if specified version must be equals or lower; ignored if versionRequirement is specified + + private boolean pingProviders = false; + + + //================================================================================================= + // methods + //------------------------------------------------------------------------------------------------- + + public SystemQueryFormDTO() {} + //------------------------------------------------------------------------------------------------- + + public String getSystemNameRequirements() { return systemNameRequirements; } + public String getDeviceNameRequirements() { return deviceNameRequirements; } + public Map getMetadataRequirements() { return metadataRequirements; } + public Integer getVersionRequirement() { return versionRequirement; } + public Integer getMinVersionRequirement() { return minVersionRequirement; } + public Integer getMaxVersionRequirement() { return maxVersionRequirement; } + public boolean getPingProviders() { return pingProviders; } + //------------------------------------------------------------------------------------------------- + + public void setSystemNameRequirements(final String systemNameRequirements) { this.systemNameRequirements = systemNameRequirements; } + public void setDeviceNameRequirements(final String deviceNameRequirements) { this.deviceNameRequirements = deviceNameRequirements; } + public void setMetadataRequirements(final Map metadataRequirements) { this.metadataRequirements = metadataRequirements; } + public void setVersionRequirement(final Integer versionRequirement) { this.versionRequirement = versionRequirement; } + public void setMinVersionRequirement(final Integer minVersionRequirement) { this.minVersionRequirement = minVersionRequirement; } + public void setMaxVersionRequirement(final Integer maxVersionRequirement) { this.maxVersionRequirement = maxVersionRequirement; } + public void setPingProviders(final boolean pingProviders) { this.pingProviders = pingProviders; } + + @Override + public String toString() { + return new StringJoiner(", ", SystemQueryFormDTO.class.getSimpleName() + "[", "]") + .add("systemNameRequirements='" + systemNameRequirements + "'") + .add("deviceNameRequirements='" + deviceNameRequirements + "'") + .add("metadataRequirements=" + metadataRequirements) + .add("versionRequirement=" + versionRequirement) + .add("minVersionRequirement=" + minVersionRequirement) + .add("maxVersionRequirement=" + maxVersionRequirement) + .add("pingProviders=" + pingProviders) + .toString(); + } + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + + private SystemQueryFormDTO(final Builder builder) { + this.systemNameRequirements = builder.systemNameRequirements; + this.deviceNameRequirements = builder.deviceNameRequirements; + this.metadataRequirements = builder.metadataRequirements; + this.versionRequirement = builder.versionRequirement; + this.minVersionRequirement = builder.minVersionRequirement; + this.maxVersionRequirement = builder.maxVersionRequirement; + this.pingProviders = builder.pingProviders; + } + //================================================================================================= + // nested classes + //------------------------------------------------------------------------------------------------- + public static class Builder { + + + //================================================================================================= + // members + + private final String systemNameRequirements; + private String deviceNameRequirements; + private Map metadataRequirements; + private Integer versionRequirement; + private Integer minVersionRequirement; + private Integer maxVersionRequirement; + + private boolean pingProviders = false; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public Builder(final String systemNameRequirements) { + Assert.isTrue(systemNameRequirements != null && !systemNameRequirements.isBlank(), "systemNameRequirements is null or blank."); + this.systemNameRequirements = systemNameRequirements; + } + + + //------------------------------------------------------------------------------------------------- + public Builder deviceName(final String deviceNameRequirements) { + this.deviceNameRequirements = deviceNameRequirements; + return this; + } + + //------------------------------------------------------------------------------------------------- + public Builder metadata(final Map metadataRequirements) { + this.metadataRequirements = metadataRequirements; + return this; + } + + //------------------------------------------------------------------------------------------------- + public Builder metadata(final String key, final String value) { + Assert.isTrue(key != null && !key.isBlank(), "Key is null or blank"); + + if (this.metadataRequirements == null) { + this.metadataRequirements = new HashMap<>(); + } + this.metadataRequirements.put(key, value); + + return this; + } + + //------------------------------------------------------------------------------------------------- + public Builder version(final Integer versionRequirement) { + this.versionRequirement = versionRequirement; + return this; + } + + //------------------------------------------------------------------------------------------------- + public Builder version(final Integer minVersionRequirement, final Integer maxVersionRequirement) { + this.minVersionRequirement = minVersionRequirement; + this.maxVersionRequirement = maxVersionRequirement; + return this; + } + + //------------------------------------------------------------------------------------------------- + public Builder pingProviders(final boolean pingProviders) { + this.pingProviders = pingProviders; + return this; + } + + //------------------------------------------------------------------------------------------------- + public SystemQueryFormDTO build() { + return new SystemQueryFormDTO(this); + } + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemQueryResultDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemQueryResultDTO.java new file mode 100644 index 000000000..7bfe62927 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemQueryResultDTO.java @@ -0,0 +1,50 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class SystemQueryResultDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -1822444510232108526L; + + private List systemQueryData = new ArrayList<>(); + private int unfilteredHits = 0; + + + //================================================================================================= + // constructors + public SystemQueryResultDTO(final List systemQueryData, final int unfilteredHits) + { + this.systemQueryData = systemQueryData; + this.unfilteredHits = unfilteredHits; + } + + + //================================================================================================= + // methods + //------------------------------------------------------------------------------------------------- + + public List getSystemQueryData() { return systemQueryData; } + public int getUnfilteredHits() { return unfilteredHits; } + //------------------------------------------------------------------------------------------------- + + public void setSystemQueryData(final List systemQueryData) { this.systemQueryData = systemQueryData; } + public void setUnfilteredHits(final int unfilteredHits) { this.unfilteredHits = unfilteredHits; } + + @Override + public String toString() { + return new StringJoiner(", ", SystemQueryResultDTO.class.getSimpleName() + "[", "]") + .add("systemQueryData=" + systemQueryData) + .add("unfilteredHits=" + unfilteredHits) + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingResponseDTO.java new file mode 100644 index 000000000..6ba626b6a --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingResponseDTO.java @@ -0,0 +1,63 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; +import org.springframework.util.Assert; + +import java.io.Serializable; +import java.util.Map; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public abstract class SystemRegistryOnboardingResponseDTO extends SystemRegistryResponseDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -635438605292398404L; + private CertificateCreationResponseDTO certificateResponse; + + //================================================================================================= + // methods + + public SystemRegistryOnboardingResponseDTO() { + } + + public SystemRegistryOnboardingResponseDTO(final long id, final SystemResponseDTO system, final DeviceResponseDTO provider, + final String endOfValidity, final Map metadata, final int version, final String createdAt, + final String updatedAt, final CertificateCreationResponseDTO certificateResponse) { + super(id, system, provider, endOfValidity, metadata, version, createdAt, updatedAt); + this.certificateResponse = certificateResponse; + } + + //------------------------------------------------------------------------------------------------- + public CertificateCreationResponseDTO getCertificateResponse() { + return certificateResponse; + } + + public void setCertificateResponse(final CertificateCreationResponseDTO certificateResponse) { + this.certificateResponse = certificateResponse; + } + + @Override + public String toString() { + return new StringJoiner(", ", SystemRegistryOnboardingResponseDTO.class.getSimpleName() + "[", "]") + .add("certificateResponse=" + certificateResponse) + .add("parent=" + super.toString()) + .toString(); + } + + public void load(final SystemRegistryResponseDTO dto) + { + Assert.notNull(dto, "SystemRegistryResponseDTO must not be null"); + + this.setId(dto.getId()); + this.setProvider(dto.getProvider()); + this.setSystem(dto.getSystem()); + this.setMetadata(dto.getMetadata()); + this.setEndOfValidity(dto.getEndOfValidity()); + this.setCreatedAt(dto.getCreatedAt()); + this.setUpdatedAt(dto.getUpdatedAt()); + this.setVersion(dto.getVersion()); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingWithCsrRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingWithCsrRequestDTO.java new file mode 100644 index 000000000..2babf9a43 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingWithCsrRequestDTO.java @@ -0,0 +1,53 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import java.io.Serializable; +import java.util.Map; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class SystemRegistryOnboardingWithCsrRequestDTO extends SystemRegistryRequestDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -635438605292398404L; + private String certificateSigningRequest; + + //================================================================================================= + // methods + + public SystemRegistryOnboardingWithCsrRequestDTO() { + } + + public SystemRegistryOnboardingWithCsrRequestDTO(final SystemRequestDTO system, final DeviceRequestDTO provider, final String endOfValidity, + final String certificateSigningRequest) { + super(system, provider, endOfValidity); + this.certificateSigningRequest = certificateSigningRequest; + } + + public SystemRegistryOnboardingWithCsrRequestDTO(final SystemRequestDTO system, final DeviceRequestDTO provider, final String endOfValidity, + final Map metadata, final Integer version, final String certificateSigningRequest) { + super(system, provider, endOfValidity, metadata, version); + this.certificateSigningRequest = certificateSigningRequest; + } + + //------------------------------------------------------------------------------------------------- + public String getCertificateSigningRequest() { + return certificateSigningRequest; + } + + public void setCertificateSigningRequest(final String certificateSigningRequest) { + this.certificateSigningRequest = certificateSigningRequest; + } + + @Override + public String toString() { + return new StringJoiner(", ", SystemRegistryOnboardingWithCsrRequestDTO.class.getSimpleName() + "[", "]") + .add("certificateSigningRequest=" + certificateSigningRequest) + .add("parent=" + super.toString()) + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingWithCsrResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingWithCsrResponseDTO.java new file mode 100644 index 000000000..98f37e4f7 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingWithCsrResponseDTO.java @@ -0,0 +1,24 @@ +package eu.arrowhead.common.dto.shared; + +import java.io.Serializable; +import java.util.Map; + +public class SystemRegistryOnboardingWithCsrResponseDTO extends SystemRegistryOnboardingResponseDTO implements Serializable { + + //================================================================================================= + // members + private static final long serialVersionUID = 1L; + + public SystemRegistryOnboardingWithCsrResponseDTO() { + } + + public SystemRegistryOnboardingWithCsrResponseDTO(final long id, final SystemResponseDTO system, + final DeviceResponseDTO provider, final String endOfValidity, + final Map metadata, final int version, final String createdAt, + final String updatedAt, + final CertificateCreationResponseDTO certificateResponse) { + super(id, system, provider, endOfValidity, metadata, version, createdAt, updatedAt, certificateResponse); + } + + // this class exist to keep the structure of RequestDTO, ResponseDTO +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingWithNameRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingWithNameRequestDTO.java new file mode 100644 index 000000000..0b8afc88b --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingWithNameRequestDTO.java @@ -0,0 +1,55 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import java.io.Serializable; +import java.util.Map; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class SystemRegistryOnboardingWithNameRequestDTO extends SystemRegistryRequestDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -635438605292398404L; + private CertificateCreationRequestDTO certificateCreationRequest; + + //================================================================================================= + // methods + + public SystemRegistryOnboardingWithNameRequestDTO() { + } + + public SystemRegistryOnboardingWithNameRequestDTO(final SystemRequestDTO system, final DeviceRequestDTO provider, final String endOfValidity, + final CertificateCreationRequestDTO certificateCreationRequest) { + super(system, provider, endOfValidity); + this.certificateCreationRequest = certificateCreationRequest; + } + + + public SystemRegistryOnboardingWithNameRequestDTO(final SystemRequestDTO system, final DeviceRequestDTO provider, final String endOfValidity, + final Map metadata, final Integer version, + final CertificateCreationRequestDTO certificateCreationRequest) { + super(system, provider, endOfValidity, metadata, version); + this.certificateCreationRequest = certificateCreationRequest; + } + + //------------------------------------------------------------------------------------------------- + public CertificateCreationRequestDTO getCertificateCreationRequest() { + return certificateCreationRequest; + } + + public void setCertificateCreationRequest(final CertificateCreationRequestDTO certificateCreationRequest) { + this.certificateCreationRequest = certificateCreationRequest; + } + + @Override + public String toString() { + return new StringJoiner(", ", SystemRegistryOnboardingWithNameRequestDTO.class.getSimpleName() + "[", "]") + .add("certificateRequest=" + certificateCreationRequest) + .add("parent=" + super.toString()) + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingWithNameResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingWithNameResponseDTO.java new file mode 100644 index 000000000..8d2a8d95e --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryOnboardingWithNameResponseDTO.java @@ -0,0 +1,24 @@ +package eu.arrowhead.common.dto.shared; + +import java.io.Serializable; +import java.util.Map; + +public class SystemRegistryOnboardingWithNameResponseDTO extends SystemRegistryOnboardingResponseDTO implements Serializable { + + //================================================================================================= + // members + private static final long serialVersionUID = 1L; + + public SystemRegistryOnboardingWithNameResponseDTO() { + } + + public SystemRegistryOnboardingWithNameResponseDTO(final long id, final SystemResponseDTO system, + final DeviceResponseDTO provider, final String endOfValidity, + final Map metadata, final int version, final String createdAt, + final String updatedAt, + final CertificateCreationResponseDTO certificateResponse) { + super(id, system, provider, endOfValidity, metadata, version, createdAt, updatedAt, certificateResponse); + } + + // this class exist to keep the structure of RequestDTO, ResponseDTO +} diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryRequestDTO.java new file mode 100644 index 000000000..d9da3f30d --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryRequestDTO.java @@ -0,0 +1,69 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import java.io.Serializable; +import java.util.Map; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class SystemRegistryRequestDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -635438605292398404L; + + private SystemRequestDTO system; + private DeviceRequestDTO provider; + private String endOfValidity; + private Map metadata; + private Integer version; + + //================================================================================================= + // methods + + public SystemRegistryRequestDTO() { + } + + public SystemRegistryRequestDTO(final SystemRequestDTO system, final DeviceRequestDTO provider, final String endOfValidity) { + this.system = system; + this.provider = provider; + this.endOfValidity = endOfValidity; + } + + public SystemRegistryRequestDTO(final SystemRequestDTO system, final DeviceRequestDTO provider, final String endOfValidity, + final Map metadata, final Integer version) { + this.system = system; + this.provider = provider; + this.endOfValidity = endOfValidity; + this.metadata = metadata; + this.version = version; + } + + //------------------------------------------------------------------------------------------------- + public SystemRequestDTO getSystem() { return system; } + public DeviceRequestDTO getProvider() { return provider; } + public String getEndOfValidity() { return endOfValidity; } + public Map getMetadata() { return metadata; } + public Integer getVersion() { return version; } + + //------------------------------------------------------------------------------------------------- + public void setSystem(final SystemRequestDTO system) { this.system = system; } + public void setProvider(final DeviceRequestDTO provider) { this.provider = provider; } + public void setEndOfValidity(final String endOfValidity) { this.endOfValidity = endOfValidity; } + public void setMetadata(final Map metadata) { this.metadata = metadata; } + public void setVersion(final Integer version) { this.version = version; } + + @Override + public String toString() { + return new StringJoiner(", ", SystemRegistryRequestDTO.class.getSimpleName() + "[", "]") + .add("system=" + system) + .add("provider=" + provider) + .add("endOfValidity='" + endOfValidity + "'") + .add("metadata=" + metadata) + .add("version=" + version) + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryResponseDTO.java new file mode 100644 index 000000000..de8045ac3 --- /dev/null +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRegistryResponseDTO.java @@ -0,0 +1,99 @@ +package eu.arrowhead.common.dto.shared; + +import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonInclude.Include; + +import java.io.Serializable; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.StringJoiner; + +@JsonInclude(Include.NON_NULL) +public class SystemRegistryResponseDTO implements Serializable { + + //================================================================================================= + // members + + private static final long serialVersionUID = -635438605292398404L; + + private long id; + private SystemResponseDTO system; + private DeviceResponseDTO provider; + private String endOfValidity; + private Map metadata; + private int version; + private String createdAt; + private String updatedAt; + + //================================================================================================= + // methods + public SystemRegistryResponseDTO() { + } + + public SystemRegistryResponseDTO(final long id, final SystemResponseDTO system, final DeviceResponseDTO provider, final String endOfValidity, + final Map metadata, final int version, final String createdAt, final String updatedAt) { + this.id = id; + this.system = system; + this.provider = provider; + this.endOfValidity = endOfValidity; + this.metadata = metadata; + this.version = version; + this.createdAt = createdAt; + this.updatedAt = updatedAt; + } + + //------------------------------------------------------------------------------------------------- + public long getId() { return id; } + public SystemResponseDTO getSystem() { return system; } + public DeviceResponseDTO getProvider() { return provider; } + public String getEndOfValidity() { return endOfValidity; } + public Map getMetadata() { return metadata; } + public int getVersion() { return version; } + public String getCreatedAt() { return createdAt; } + public String getUpdatedAt() { return updatedAt; } + + //------------------------------------------------------------------------------------------------- + public void setId(final long id) { this.id = id; } + public void setSystem(final SystemResponseDTO system) { this.system = system; } + public void setProvider(final DeviceResponseDTO provider) { this.provider = provider; } + public void setEndOfValidity(final String endOfValidity) { this.endOfValidity = endOfValidity; } + public void setMetadata(final Map metadata) { this.metadata = metadata; } + public void setVersion(final int version) { this.version = version; } + public void setCreatedAt(final String createdAt) { this.createdAt = createdAt; } + public void setUpdatedAt(final String updatedAt) { this.updatedAt = updatedAt; } + + @Override + public boolean equals(final Object o) { + if (this == o) { return true; } + if (o == null || getClass() != o.getClass()) { return false; } + final SystemRegistryResponseDTO that = (SystemRegistryResponseDTO) o; + return id == that.id && + version == that.version && + system.equals(that.system) && + provider.equals(that.provider) && + endOfValidity.equals(that.endOfValidity) && + Objects.equals(metadata, that.metadata) && + createdAt.equals(that.createdAt) && + updatedAt.equals(that.updatedAt); + } + + @Override + public int hashCode() { + return Objects.hash(id, system, provider, endOfValidity, metadata, version, createdAt, updatedAt); + } + + @Override + public String toString() { + return new StringJoiner(", ", SystemRegistryResponseDTO.class.getSimpleName() + "[", "]") + .add("id=" + id) + .add("system=" + system) + .add("provider=" + provider) + .add("endOfValidity='" + endOfValidity + "'") + .add("metadata=" + metadata) + .add("version=" + version) + .add("createdAt='" + createdAt + "'") + .add("updatedAt='" + updatedAt + "'") + .toString(); + } +} \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRequestDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRequestDTO.java index 75b9e99b2..7351268fa 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRequestDTO.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemRequestDTO.java @@ -2,6 +2,7 @@ import java.io.Serializable; import java.util.Objects; +import java.util.StringJoiner; public class SystemRequestDTO implements Serializable { @@ -17,7 +18,18 @@ public class SystemRequestDTO implements Serializable { //================================================================================================= // methods - + + + public SystemRequestDTO() { + } + + public SystemRequestDTO(final String systemName, final String address, final Integer port, final String authenticationInfo) { + this.systemName = systemName; + this.address = address; + this.port = port; + this.authenticationInfo = authenticationInfo; + } + //------------------------------------------------------------------------------------------------- public String getSystemName() { return systemName; } public String getAddress() { return address; } @@ -42,14 +54,27 @@ public boolean equals(final Object obj) { if (this == obj) { return true; } + if (obj == null) { return false; } + if (getClass() != obj.getClass()) { return false; } + final SystemRequestDTO other = (SystemRequestDTO) obj; return Objects.equals(address, other.address) && Objects.equals(port, other.port) && Objects.equals(systemName, other.systemName); } + + @Override + public String toString() { + return new StringJoiner(", ", SystemRequestDTO.class.getSimpleName() + "[", "]") + .add("systemName='" + systemName + "'") + .add("address='" + address + "'") + .add("port=" + port) + .add("authenticationInfo='" + authenticationInfo + "'") + .toString(); + } } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemResponseDTO.java b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemResponseDTO.java index 2e6e037de..d6a1e885d 100644 --- a/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemResponseDTO.java +++ b/core-common/src/main/java/eu/arrowhead/common/dto/shared/SystemResponseDTO.java @@ -2,6 +2,7 @@ import java.io.Serializable; import java.util.Objects; +import java.util.StringJoiner; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.annotation.JsonInclude.Include; @@ -69,14 +70,30 @@ public boolean equals(final Object obj) { if (this == obj) { return true; } + if (obj == null) { return false; } + if (getClass() != obj.getClass()) { return false; } + final SystemResponseDTO other = (SystemResponseDTO) obj; return Objects.equals(address, other.address) && Objects.equals(port, other.port) && Objects.equals(systemName, other.systemName); } + + @Override + public String toString() { + return new StringJoiner(", ", SystemResponseDTO.class.getSimpleName() + "[", "]") + .add("id=" + id) + .add("systemName='" + systemName + "'") + .add("address='" + address + "'") + .add("port=" + port) + .add("authenticationInfo='" + authenticationInfo + "'") + .add("createdAt='" + createdAt + "'") + .add("updatedAt='" + updatedAt + "'") + .toString(); + } } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/exception/ArrowheadException.java b/core-common/src/main/java/eu/arrowhead/common/exception/ArrowheadException.java index 0ada2bca5..3a69dd774 100644 --- a/core-common/src/main/java/eu/arrowhead/common/exception/ArrowheadException.java +++ b/core-common/src/main/java/eu/arrowhead/common/exception/ArrowheadException.java @@ -68,5 +68,5 @@ public ArrowheadException(final String msg) { public String getOrigin() { return origin; } //------------------------------------------------------------------------------------------------- - void setExceptionType(final ExceptionType exceptionType) { this.exceptionType = exceptionType; } + protected void setExceptionType(final ExceptionType exceptionType) { this.exceptionType = exceptionType; } } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/http/ArrowheadHttpClientResponseErrorHandler.java b/core-common/src/main/java/eu/arrowhead/common/http/ArrowheadHttpClientResponseErrorHandler.java index 0ddbd57d0..ceebca435 100644 --- a/core-common/src/main/java/eu/arrowhead/common/http/ArrowheadHttpClientResponseErrorHandler.java +++ b/core-common/src/main/java/eu/arrowhead/common/http/ArrowheadHttpClientResponseErrorHandler.java @@ -39,13 +39,13 @@ public void handleError(final URI url, final HttpMethod method, final ClientHttp logger.debug("Unable to deserialize error message: {}", ex.getMessage()); logger.debug("Exception: ", ex); logger.error("Request failed at {}, response status code: {}", url, response.getRawStatusCode()); - throw new ArrowheadException("Unknown error occurred at " + url + ". Check log for possibly more information.", ex); + throw new ArrowheadException("Unknown error occurred at " + url + ". Check log for possibly more information.", response.getRawStatusCode(), ex); } if (dto.getExceptionType() == null) { logger.error("Request failed at {}, response status code: {}", url, response.getRawStatusCode()); logger.error("Request failed, error message: {}", dto.getErrorMessage()); - throw new ArrowheadException("Unknown error occurred at " + url + ". Check log for possibly more information."); + throw new ArrowheadException("Unknown error occurred at " + url + ". Check log for possibly more information.", response.getRawStatusCode()); } logger.debug("Error occured at {}. Returned with {}", url, response.getRawStatusCode()); diff --git a/core-common/src/main/java/eu/arrowhead/common/log4j2/JDBCConnectionFactoryForLog4J2.java b/core-common/src/main/java/eu/arrowhead/common/log4j2/JDBCConnectionFactoryForLog4J2.java index 8252cde94..1ff7e0b01 100644 --- a/core-common/src/main/java/eu/arrowhead/common/log4j2/JDBCConnectionFactoryForLog4J2.java +++ b/core-common/src/main/java/eu/arrowhead/common/log4j2/JDBCConnectionFactoryForLog4J2.java @@ -57,7 +57,7 @@ public static Connection getConnection() throws SQLException { //------------------------------------------------------------------------------------------------- private static void init() throws IOException { InputStream propStream = null; - File propertiesFile = new File(CoreCommonConstants.APPLICATION_PROPERTIES); + final File propertiesFile = new File(CoreCommonConstants.APPLICATION_PROPERTIES); if (!propertiesFile.exists()) { propStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(CoreCommonConstants.APPLICATION_PROPERTIES); } else { diff --git a/core-common/src/main/java/eu/arrowhead/common/quartz/uricrawler/UriCrawlerTask.java b/core-common/src/main/java/eu/arrowhead/common/quartz/uricrawler/UriCrawlerTask.java index 32b001593..ac93c9db9 100644 --- a/core-common/src/main/java/eu/arrowhead/common/quartz/uricrawler/UriCrawlerTask.java +++ b/core-common/src/main/java/eu/arrowhead/common/quartz/uricrawler/UriCrawlerTask.java @@ -168,7 +168,7 @@ private boolean findCoreSystemServiceUri(final CoreSystemService coreSystemServi final ResponseEntity response = httpService.sendRequest(queryUri, HttpMethod.POST, ServiceQueryResultDTO.class, form); final ServiceQueryResultDTO result = response.getBody(); if (!result.getServiceQueryData().isEmpty()) { - final int lastIdx = result.getServiceQueryData().size() - 1; // to make sure we use the newest one if some entries stucked in the DB + final int lastIdx = result.getServiceQueryData().size() - 1; // to make sure we use the newest one if some old entries are in the DB final ServiceRegistryResponseDTO entry = result.getServiceQueryData().get(lastIdx); final String scheme = entry.getSecure() == ServiceSecurityType.NOT_SECURE ? CommonConstants.HTTP : CommonConstants.HTTPS; final UriComponents uri = Utilities.createURI(scheme, entry.getProvider().getAddress(), entry.getProvider().getPort(), entry.getServiceUri()); diff --git a/core-common/src/main/java/eu/arrowhead/common/security/AccessControlFilter.java b/core-common/src/main/java/eu/arrowhead/common/security/AccessControlFilter.java index cab939cb0..d18b68fe6 100644 --- a/core-common/src/main/java/eu/arrowhead/common/security/AccessControlFilter.java +++ b/core-common/src/main/java/eu/arrowhead/common/security/AccessControlFilter.java @@ -11,6 +11,8 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; +import eu.arrowhead.common.SecurityUtilities; +import org.apache.http.HttpStatus; import org.springframework.lang.Nullable; import org.springframework.util.Assert; @@ -67,13 +69,13 @@ public void doFilter(final ServletRequest request, final ServletResponse respons protected void checkClientAuthorized(final String clientCN, final String method, final String requestTarget, final String requestJSON, final Map queryParams) { if (!Utilities.isKeyStoreCNArrowheadValid(clientCN)) { log.debug("{} is not a valid common name, access denied!", clientCN); - throw new AuthException(clientCN + " is unauthorized to access " + requestTarget); + throw new AuthException(clientCN + " is unauthorized to access " + requestTarget, HttpStatus.SC_UNAUTHORIZED, requestTarget); } // All requests from the local cloud are allowed if (!Utilities.isKeyStoreCNArrowheadValid(clientCN, getServerCloudCN())) { log.debug("{} is unauthorized to access {}", clientCN, requestTarget); - throw new AuthException(clientCN + " is unauthorized to access " + requestTarget); + throw new AuthException(clientCN + " is unauthorized to access " + requestTarget, HttpStatus.SC_UNAUTHORIZED, requestTarget); } } @@ -89,12 +91,6 @@ protected String getServerCloudCN() { //------------------------------------------------------------------------------------------------- @Nullable private String getCertificateCNFromRequest(final HttpServletRequest request) { - final X509Certificate[] certificates = (X509Certificate[]) request.getAttribute(CommonConstants.ATTR_JAVAX_SERVLET_REQUEST_X509_CERTIFICATE); - if (certificates != null && certificates.length != 0) { - final X509Certificate cert = certificates[0]; - return Utilities.getCertCNFromSubject(cert.getSubjectDN().getName()); - } - - return null; + return SecurityUtilities.getCertificateCNFromRequest(request); } } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/token/TokenSecurityFilter.java b/core-common/src/main/java/eu/arrowhead/common/token/TokenSecurityFilter.java index 963a7efd4..53d7d85aa 100644 --- a/core-common/src/main/java/eu/arrowhead/common/token/TokenSecurityFilter.java +++ b/core-common/src/main/java/eu/arrowhead/common/token/TokenSecurityFilter.java @@ -11,6 +11,7 @@ import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; +import eu.arrowhead.common.SecurityUtilities; import org.springframework.lang.Nullable; import eu.arrowhead.common.CommonConstants; @@ -81,12 +82,6 @@ protected TokenInfo checkToken(final String clientCN, final String token, final //------------------------------------------------------------------------------------------------- @Nullable private String getCertificateCNFromRequest(final HttpServletRequest request) { - final X509Certificate[] certificates = (X509Certificate[]) request.getAttribute(CommonConstants.ATTR_JAVAX_SERVLET_REQUEST_X509_CERTIFICATE); - if (certificates != null && certificates.length != 0) { - final X509Certificate cert = certificates[0]; - return Utilities.getCertCNFromSubject(cert.getSubjectDN().getName()); - } - - return null; + return SecurityUtilities.getCertificateCNFromRequest(request); } } \ No newline at end of file diff --git a/core-common/src/main/java/eu/arrowhead/common/token/TokenUtilities.java b/core-common/src/main/java/eu/arrowhead/common/token/TokenUtilities.java index 506f1f982..601875a92 100644 --- a/core-common/src/main/java/eu/arrowhead/common/token/TokenUtilities.java +++ b/core-common/src/main/java/eu/arrowhead/common/token/TokenUtilities.java @@ -38,7 +38,7 @@ public class TokenUtilities { public static TokenInfo validateTokenAndExtractTokenInfo(final String token, final PublicKey authorizationPublicKey, final PrivateKey privateKey) { logger.debug("validateTokenAndExtractTokenInfo started..."); Assert.notNull(authorizationPublicKey, "Authorization public key is null."); - Assert.notNull(privateKey, "Caller's private key is null."); + Assert.notNull(privateKey, "Private key is null."); if (Utilities.isEmpty(token)) { throw new InvalidParameterException("No token is provided."); diff --git a/deviceregistry/pom.xml b/deviceregistry/pom.xml new file mode 100644 index 000000000..f58eb7910 --- /dev/null +++ b/deviceregistry/pom.xml @@ -0,0 +1,141 @@ + + 4.0.0 + + eu.arrowhead + core + ${revision} + + + arrowhead-deviceregistry + jar + Arrowhead Device Registry + SQL-based Device Registry core service + + + + eu.arrowhead + arrowhead-core-common + ${revision} + + + com.h2database + h2 + test + + + + + + + maven-resources-plugin + ${mvn.resources.version} + + + copy-resources + + validate + + copy-resources + + + ${basedir}/target + + + src/main/resources + + application.properties + log4j2.xml + + + + + + + + + + jdeb + org.vafer + 1.8 + + + package + + jdeb + + + true + + [YYMMddHHmm].${git.commit.id.abbrev} + target/${project.artifactId}_${revision}.deb + true + ${basedir}/src/deb/control + + + file + ${project.build.directory}/${project.build.finalName}.jar + + perm + /usr/share/arrowhead/device_registry + 755 + + + + + link + /usr/share/arrowhead/device_registry/${project.artifactId}.jar + /usr/share/arrowhead/device_registry/${project.build.finalName}.jar + + + + file + ${project.build.directory}/log4j2.xml + + perm + /etc/arrowhead/systems/device_registry + 644 + + + + + file + ${project.build.directory}/application.properties + + perm + /etc/arrowhead/systems/device_registry + 644 + + + + + link + /usr/share/arrowhead/device_registry/application.properties + /etc/arrowhead/systems/device_registry/application.properties + + + + file + ${project.basedir}/src/deb/arrowhead-deviceregistry.service + + perm + /etc/systemd/system + 644 + + + + + file + ${project.basedir}/../scripts/device_registry_privileges.sql + + perm + /usr/share/arrowhead/conf + + + + + + + + + + \ No newline at end of file diff --git a/deviceregistry/src/deb/arrowhead-deviceregistry.service b/deviceregistry/src/deb/arrowhead-deviceregistry.service new file mode 100644 index 000000000..093ccb411 --- /dev/null +++ b/deviceregistry/src/deb/arrowhead-deviceregistry.service @@ -0,0 +1,15 @@ +[Unit] +Description=arrowhead-deviceregistry +After=network.target + +[Service] +WorkingDirectory=/etc/arrowhead/systems/device_registry +ExecStart=/usr/bin/java -Dlog4j.configurationFile=file:/etc/arrowhead/systems/device_registry/log4j2.xml -jar /usr/share/arrowhead/device_registry/arrowhead-deviceregistry.jar +ExecStartPost=/bin/bash -c 'sleep 10' +TimeoutStopSec=5 +Type=simple +User=arrowhead +Group=arrowhead + +[Install] +WantedBy=default.target diff --git a/deviceregistry/src/deb/control/config b/deviceregistry/src/deb/control/config new file mode 100644 index 000000000..49782702b --- /dev/null +++ b/deviceregistry/src/deb/control/config @@ -0,0 +1,19 @@ +#!/bin/sh -e + +. /usr/share/debconf/confmodule + +if logname 2>/dev/null; then + USER=$(logname) + HOME=$(eval echo "~$USER") +else + USER="root" + HOME="/root" +fi + +# Get installation type +db_input high arrowhead-core-common/db_host || true +db_input high arrowhead-core-common/mysql_password_dr || true + +# Run dialogs +db_go || true + diff --git a/deviceregistry/src/deb/control/control b/deviceregistry/src/deb/control/control new file mode 100644 index 000000000..f1bd1eeef --- /dev/null +++ b/deviceregistry/src/deb/control/control @@ -0,0 +1,10 @@ +Package: arrowhead-device-registry +Version: [[version]] +Section: contrib/java +Priority: optional +Architecture: all +Maintainer: Mario Zsilak +Homepage: http://www.arrowhead.eu +Description: Arrowhead Device Registry +Distribution: development +Depends: java-runtime-headless, openssl, virtual-mysql-server, arrowhead-core-common diff --git a/deviceregistry/src/deb/control/postinst b/deviceregistry/src/deb/control/postinst new file mode 100644 index 000000000..f58726b71 --- /dev/null +++ b/deviceregistry/src/deb/control/postinst @@ -0,0 +1,103 @@ +#!/bin/sh +# postinst script for arrowhead-deviceregistry +# +# see: dh_installdeb(1) + +set -e + +. /usr/share/debconf/confmodule + +SYSTEM_NAME="device_registry" +PKG_NAME="arrowhead-deviceregistry" + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + +case "$1" in + configure) + dos2unix -q /etc/systemd/system/${PKG_NAME}.service + + . /usr/share/arrowhead/conf/ahconf.sh + + SYSTEM_DIR="${AH_SYSTEMS_DIR}/${SYSTEM_NAME}" + + db_get arrowhead-core-common/mysql_password_dr; system_passwd=$RET || true + db_unregister arrowhead-core-common/mysql_password_dr + + # Generate password (if required) + if [ -z "${system_passwd}" ]; then + system_passwd="$(openssl rand -base64 12)" + fi + + echo "Configuring MySQL database..." >&2 + ah_db_tables_and_user ${SYSTEM_NAME} ${SYSTEM_NAME}_privileges.sql ${system_passwd} + + if [ ! -d "${SYSTEM_DIR}" ]; then + mkdir -p ${SYSTEM_DIR} + fi + + domain_name=${AH_DOMAIN_NAME} + if [ -z ${domain_name} ]; then + domain_name=${OWN_IP} + fi + + ah_cert_signed_system ${SYSTEM_NAME} + + # modify log config and application.properties + + ah_transform_log_file ${SYSTEM_DIR} + + db_get arrowhead-core-common/sr_host; sr_host=$RET || true + + if [ -z ${sr_host} ]; then + sr_host=${OWN_IP} + fi + + db_get arrowhead-core-common/db_host; db_host=$RET || true + + mv ${SYSTEM_DIR}/application.properties ${SYSTEM_DIR}/application.properties.orig + cat ${SYSTEM_DIR}/application.properties.orig | \ + sed -r -e "\#^.*spring\.datasource\.url=#s#.*\$#spring.datasource.url=jdbc:mysql://"${db_host}":3306/arrowhead?serverTimezone=Europe/Budapest#" \ + -e "\#^.*spring\.datasource\.password=#s#.*\$#spring.datasource.password=${system_passwd}#" \ + -e "\#^.*domain\.name=#s#.*\$#domain.name=${domain_name}#" \ + -e "\#^.*sr_address=#s#.*\$#sr_address=${sr_host}#" \ + -e "\#^.*server\.ssl\.key-store=#s#.*\$#server.ssl.key-store=file:${SYSTEM_DIR}/${SYSTEM_NAME}.p12#" \ + -e "\#^.*server\.ssl\.key-store-password=#s#.*\$#server.ssl.key-store-password=${AH_PASS_CERT}#" \ + -e "\#^.*server\.ssl\.key-password=#s#.*\$#server.ssl.key-password=${AH_PASS_CERT}#" \ + -e "\#^.*server\.ssl\.trust-store=#s#.*\$#server.ssl.trust-store=file:${AH_CONF_DIR}/truststore.p12#" \ + -e "\#^.*server\.ssl\.trust-store-password=#s#.*\$#server.ssl.trust-store-password=${AH_PASS_CERT}#" > ${SYSTEM_DIR}/application.properties + + rm ${SYSTEM_DIR}/application.properties.orig + chown arrowhead:arrowhead ${SYSTEM_DIR}/application.properties + chmod 640 ${SYSTEM_DIR}/application.properties + + echo "Starting ${PKG_NAME}..." >&2 + systemctl daemon-reload + systemctl enable ${PKG_NAME}.service + systemctl start ${PKG_NAME}.service + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/deviceregistry/src/deb/control/postrm b/deviceregistry/src/deb/control/postrm new file mode 100644 index 000000000..199816d2d --- /dev/null +++ b/deviceregistry/src/deb/control/postrm @@ -0,0 +1,56 @@ +#!/bin/sh +# postrm script for arrowhead-deviceregistry +# +# see: dh_installdeb(1) + +set -e + +. /usr/share/debconf/confmodule + +SYSTEM_NAME="device_registry" + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + purge) + AH_CONF_DIR="/etc/arrowhead" + AH_SYSTEMS_DIR="${AH_CONF_DIR}/systems" + SYSTEM_DIR="${AH_SYSTEMS_DIR}/${SYSTEM_NAME}" + + rm -f \ + /var/log/arrowhead/${SYSTEM_NAME}*.log \ + ${SYSTEM_DIR}/log4j2.xml \ + ${SYSTEM_DIR}/application.properties \ + ${SYSTEM_DIR}/${SYSTEM_NAME}.p12 + rmdir ${SYSTEM_DIR} 2>/dev/null || true + rmdir ${AH_SYSTEMS_DIR}/sysop 2>/dev/null || true + db_purge + ;; + + remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/deviceregistry/src/deb/control/preinst b/deviceregistry/src/deb/control/preinst new file mode 100644 index 000000000..e6d28cf8d --- /dev/null +++ b/deviceregistry/src/deb/control/preinst @@ -0,0 +1,35 @@ +#!/bin/sh +# preinst script for arrowhead-deviceregistry +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `install' +# * `install' +# * `upgrade' +# * `abort-upgrade' +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + install|upgrade) + ;; + + abort-upgrade) + ;; + + *) + echo "preinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/deviceregistry/src/deb/control/prerm b/deviceregistry/src/deb/control/prerm new file mode 100644 index 000000000..3e2adee46 --- /dev/null +++ b/deviceregistry/src/deb/control/prerm @@ -0,0 +1,45 @@ +#!/bin/sh +# prerm script for arrowhead-deviceregistry +# +# see: dh_installdeb(1) + +set -e + +PKG_NAME="arrowhead-deviceregistry" + +# summary of how this script can be called: +# * `remove' +# * `upgrade' +# * `failed-upgrade' +# * `remove' `in-favour' +# * `deconfigure' `in-favour' +# `removing' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + remove) + systemctl stop ${PKG_NAME}.service + systemctl disable ${PKG_NAME}.service + ;; + + upgrade|deconfigure) + ;; + + failed-upgrade) + ;; + + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/Constants.java b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/Constants.java new file mode 100644 index 000000000..74fc77680 --- /dev/null +++ b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/Constants.java @@ -0,0 +1,15 @@ +package eu.arrowhead.core.deviceregistry; + +class Constants { + + //================================================================================================= + // members + static final String PATH_VARIABLE_ID = "deviceId"; + static final String PATH_VARIABLE_DEVICE_NAME = "deviceName"; + + static final String DEVICES_URI = "/devices"; + static final String DEVICE_BY_ID_URI = "/device/{" + PATH_VARIABLE_ID + "}"; + static final String DEVICES_BY_ID_URI = "/devices/{" + PATH_VARIABLE_ID + "}"; + + protected Constants() { super(); } +} diff --git a/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryApplicationInitListener.java b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryApplicationInitListener.java new file mode 100644 index 000000000..81bde44d8 --- /dev/null +++ b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryApplicationInitListener.java @@ -0,0 +1,29 @@ +package eu.arrowhead.core.deviceregistry; + +import eu.arrowhead.common.ApplicationInitListener; +import eu.arrowhead.common.core.CoreSystemService; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +import java.util.Base64; +import java.util.List; + +@Component +public class DeviceRegistryApplicationInitListener extends ApplicationInitListener { + + //================================================================================================= + // members + + //------------------------------------------------------------------------------------------------- + @Override + protected void customInit(final ContextRefreshedEvent event) { + if (sslProperties.isSslEnabled()) { + logger.debug("AuthInfo: {}", Base64.getEncoder().encodeToString(publicKey.getEncoded())); + } + } + + @Override + protected List getRequiredCoreSystemServiceUris() { + return List.of(CoreSystemService.ORCHESTRATION_SERVICE, CoreSystemService.CERTIFICATE_AUTHORITY_SIGN_SERVICE); + } +} \ No newline at end of file diff --git a/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryController.java b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryController.java new file mode 100644 index 000000000..699f10cc1 --- /dev/null +++ b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryController.java @@ -0,0 +1,221 @@ +package eu.arrowhead.core.deviceregistry; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.Defaults; +import eu.arrowhead.common.SecurityUtilities; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.dto.shared.CertificateType; +import eu.arrowhead.common.dto.shared.DeviceQueryFormDTO; +import eu.arrowhead.common.dto.shared.DeviceQueryResultDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.DeviceRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceResponseDTO; +import eu.arrowhead.common.exception.BadPayloadException; +import eu.arrowhead.core.deviceregistry.database.service.DeviceRegistryDBService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +@Api(tags = {CoreCommonConstants.SWAGGER_TAG_ALL}) +@CrossOrigin(maxAge = Defaults.CORS_MAX_AGE, allowCredentials = Defaults.CORS_ALLOW_CREDENTIALS, + allowedHeaders = {HttpHeaders.ORIGIN, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT, HttpHeaders.AUTHORIZATION} +) +@RestController +@RequestMapping(CommonConstants.DEVICE_REGISTRY_URI) +public class DeviceRegistryController { + + private static final String DEVICE_REGISTRY_REGISTER_DESCRIPTION = "Registers a device"; + private static final String DEVICE_REGISTRY_REGISTER_201_MESSAGE = "Device registered"; + private static final String DEVICE_REGISTRY_REGISTER_400_MESSAGE = "Could not register device"; + private static final String DEVICE_REGISTRY_UNREGISTER_DESCRIPTION = "Remove a registered device"; + private static final String DEVICE_REGISTRY_UNREGISTER_200_MESSAGE = "Registered device removed"; + private static final String DEVICE_REGISTRY_UNREGISTER_400_MESSAGE = "Could not remove device"; + private static final String DEVICE_REGISTRY_QUERY_DESCRIPTION = "Return Device Registry data that fits the specification"; + private static final String DEVICE_REGISTRY_QUERY_200_MESSAGE = "Device Registry data returned"; + private static final String DEVICE_REGISTRY_QUERY_400_MESSAGE = "Could not query Device Registry"; + private static final String DEVICE_REGISTRY_QUERY_BY_DEVICE_ID_DESCRIPTION = "Return device by requested deviceId"; + private static final String DEVICE_REGISTRY_QUERY_BY_DEVICE_ID_200_MESSAGE = "Device data by deviceId returned"; + private static final String DEVICE_REGISTRY_QUERY_BY_DEVICE_ID_400_MESSAGE = "Could not query Device Registry by Consumer device deviceId"; + private static final String DEVICE_REGISTRY_QUERY_BY_DEVICE_DTO_DESCRIPTION = "Return Device by requested dto"; + private static final String DEVICE_REGISTRY_QUERY_BY_DEVICE_DTO_200_MESSAGE = "Consumer Device data by requestDTO returned"; + private static final String DEVICE_REGISTRY_QUERY_BY_DEVICE_DTO_400_MESSAGE = "Could not query Device Registry by Consumer device requestDTO"; + //================================================================================================= + // members + private final Logger logger = LogManager.getLogger(DeviceRegistryController.class); + private final DeviceRegistryDBService deviceRegistryDBService; + private final SecurityUtilities securityUtilities; + private final Validation validation; + + @Autowired + public DeviceRegistryController(final DeviceRegistryDBService deviceRegistryDBService, + final SecurityUtilities securityUtilities) { + this.deviceRegistryDBService = deviceRegistryDBService; + this.securityUtilities = securityUtilities; + this.validation = new Validation(); + } + + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return an echo message with the purpose of testing the core device availability", response = String.class, tags = {CoreCommonConstants.SWAGGER_TAG_CLIENT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = CoreCommonConstants.SWAGGER_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = CommonConstants.ECHO_URI) + public String echoDevice() { + return "Got it!"; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = DEVICE_REGISTRY_REGISTER_DESCRIPTION, response = DeviceRegistryResponseDTO.class, tags = + {CoreCommonConstants.SWAGGER_TAG_CLIENT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_CREATED, message = DEVICE_REGISTRY_REGISTER_201_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DEVICE_REGISTRY_REGISTER_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @ResponseStatus(value = org.springframework.http.HttpStatus.CREATED) + @PostMapping(path = {CommonConstants.OP_DEVICE_REGISTRY_REGISTER_URI, CoreCommonConstants.MGMT_URI}, + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public DeviceRegistryResponseDTO registerDevice(final HttpServletRequest httpServletRequest, + @RequestBody final DeviceRegistryRequestDTO request) { + logger.debug("New device registration request received"); + securityUtilities.authenticateCertificate(httpServletRequest, CertificateType.AH_DEVICE); + validation.checkDeviceRegistryRequest(request, getOrigin(CommonConstants.OP_DEVICE_REGISTRY_REGISTER_URI)); + final DeviceRegistryResponseDTO response = deviceRegistryDBService.registerDeviceRegistry(request); + logger.debug("{} successfully registers its device {}", request.getDevice().getDeviceName(), request.getDevice()); + + return response; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = DEVICE_REGISTRY_UNREGISTER_DESCRIPTION, tags = {CoreCommonConstants.SWAGGER_TAG_CLIENT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = DEVICE_REGISTRY_UNREGISTER_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DEVICE_REGISTRY_UNREGISTER_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @DeleteMapping(path = CommonConstants.OP_DEVICE_REGISTRY_UNREGISTER_URI) + public void unregisterDevice(final HttpServletRequest httpServletRequest, + @RequestParam(CommonConstants.OP_DEVICE_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_DEVICE_NAME) final String deviceName, + @RequestParam(CommonConstants.OP_DEVICE_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_MAC_ADDRESS) final String macAddress) { + logger.debug("Device removal request received"); + securityUtilities.authenticateCertificate(httpServletRequest, CertificateType.AH_ONBOARDING); + validation.checkUnregisterDeviceParameters(deviceName, macAddress); + deviceRegistryDBService.removeDeviceRegistryByNameAndMacAddress(deviceName, macAddress); + logger.debug("{} successfully removed", deviceName); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = DEVICE_REGISTRY_QUERY_DESCRIPTION, response = DeviceQueryResultDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_CLIENT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = DEVICE_REGISTRY_QUERY_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DEVICE_REGISTRY_QUERY_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(path = CommonConstants.OP_DEVICE_REGISTRY_QUERY_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public DeviceQueryResultDTO queryRegistry(final HttpServletRequest httpServletRequest, + @RequestBody final DeviceQueryFormDTO form) { + logger.debug("Device query request received"); + securityUtilities.authenticateCertificate(httpServletRequest, CertificateType.AH_SYSTEM); + + if (Utilities.isEmpty(form.getDeviceNameRequirements())) { + throw new BadPayloadException("Device definition requirement is null or blank", HttpStatus.SC_BAD_REQUEST, getOrigin( + CommonConstants.OP_DEVICE_REGISTRY_QUERY_URI)); + } + + final DeviceQueryResultDTO result = deviceRegistryDBService.queryRegistry(form); + logger.debug("Return {} providers for device {}", result.getDeviceQueryData().size(), form.getDeviceNameRequirements()); + + return result; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = DEVICE_REGISTRY_QUERY_BY_DEVICE_ID_DESCRIPTION, response = DeviceResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_PRIVATE}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = DEVICE_REGISTRY_QUERY_BY_DEVICE_ID_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DEVICE_REGISTRY_QUERY_BY_DEVICE_ID_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = CoreCommonConstants.OP_DEVICE_REGISTRY_QUERY_BY_DEVICE_ID_URI, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public DeviceResponseDTO queryRegistryByDeviceId(final HttpServletRequest httpServletRequest, + @PathVariable(value = Constants.PATH_VARIABLE_ID) final long deviceId) { + logger.debug("Device query by device deviceId request received"); + securityUtilities.authenticateCertificate(httpServletRequest, CertificateType.AH_SYSTEM); + validation.checkId(deviceId, getOrigin(CoreCommonConstants.OP_DEVICE_REGISTRY_QUERY_BY_DEVICE_ID_URI)); + final DeviceResponseDTO result = deviceRegistryDBService.getDeviceById(deviceId); + + logger.debug("Return device by deviceId: {}", deviceId); + return result; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = DEVICE_REGISTRY_QUERY_BY_DEVICE_DTO_DESCRIPTION, response = DeviceResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_PRIVATE}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = DEVICE_REGISTRY_QUERY_BY_DEVICE_DTO_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DEVICE_REGISTRY_QUERY_BY_DEVICE_DTO_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(path = CoreCommonConstants.OP_DEVICE_REGISTRY_QUERY_BY_DEVICE_DTO_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public DeviceResponseDTO queryRegistryByDeviceDTO(final HttpServletRequest httpServletRequest, + @RequestBody final DeviceRequestDTO request) { + logger.debug("Device query by DeviceRequestDTO request received"); + securityUtilities.authenticateCertificate(httpServletRequest, CertificateType.AH_SYSTEM); + validation.checkDeviceRequest(request, getOrigin(CoreCommonConstants.OP_DEVICE_REGISTRY_QUERY_BY_DEVICE_ID_URI)); + + final String deviceName = request.getDeviceName(); + final String macAddress = request.getMacAddress(); + + final DeviceResponseDTO result = deviceRegistryDBService.getDeviceDtoByNameAndMacAddress(deviceName, macAddress); + + logger.debug("Return device by name: {}, macAddress: {}", deviceName, macAddress); + return result; + } + + //================================================================================================= + // assistant methods + private String getBaseOrigin() { + return CommonConstants.DEVICE_REGISTRY_URI; + } + + private String getOrigin(final String postfix) { + Assert.notNull(postfix, "Internal error: Origin postfix not provided"); + return getBaseOrigin() + postfix; + } +} \ No newline at end of file diff --git a/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryMain.java b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryMain.java new file mode 100644 index 000000000..9facd3222 --- /dev/null +++ b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryMain.java @@ -0,0 +1,28 @@ +package eu.arrowhead.core.deviceregistry; + + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.database.repository.RefreshableRepositoryImpl; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@SpringBootApplication(scanBasePackages = CommonConstants.BASE_PACKAGE) +@EntityScan(CoreCommonConstants.DATABASE_ENTITY_PACKAGE) +@EnableJpaRepositories(basePackages = CoreCommonConstants.DATABASE_REPOSITORY_PACKAGE, repositoryBaseClass = RefreshableRepositoryImpl.class) +@EnableSwagger2 +public class DeviceRegistryMain +{ + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public static void main(final String[] args) { + SpringApplication.run(DeviceRegistryMain.class, args); + } +} diff --git a/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryManagementController.java b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryManagementController.java new file mode 100644 index 000000000..a5e648f7c --- /dev/null +++ b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryManagementController.java @@ -0,0 +1,355 @@ +package eu.arrowhead.core.deviceregistry; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.CoreDefaults; +import eu.arrowhead.common.CoreUtilities; +import eu.arrowhead.common.Defaults; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.dto.internal.DeviceListResponseDTO; +import eu.arrowhead.common.dto.internal.DeviceRegistryListResponseDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.DeviceRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceResponseDTO; +import eu.arrowhead.common.exception.BadPayloadException; +import eu.arrowhead.core.deviceregistry.database.service.DeviceRegistryDBService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +@Api(tags = {CoreCommonConstants.SWAGGER_TAG_ALL}) +@CrossOrigin(maxAge = Defaults.CORS_MAX_AGE, allowCredentials = Defaults.CORS_ALLOW_CREDENTIALS, + allowedHeaders = {HttpHeaders.ORIGIN, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT, HttpHeaders.AUTHORIZATION} +) +@RestController +@RequestMapping(CommonConstants.DEVICE_REGISTRY_URI + CoreCommonConstants.MGMT_URI) +public class DeviceRegistryManagementController { + + private static final String DEVICE_REGISTRY_BY_ID_URI = "/{" + Constants.PATH_VARIABLE_ID + "}"; + private static final String DEVICE_REGISTRY_BY_DEVICE_NAME_URI = "/devicename" + "/{" + Constants.PATH_VARIABLE_DEVICE_NAME + "}"; + + private static final String GET_DEVICE_REGISTRY_HTTP_200_MESSAGE = "Device Registry entries returned"; + private static final String GET_DEVICE_REGISTRY_HTTP_400_MESSAGE = "Could not retrieve device registry entries"; + private static final String PUT_DEVICE_REGISTRY_DESCRIPTION = "Update a device"; + private static final String PUT_DEVICE_REGISTRY_HTTP_200_MESSAGE = "Device updated"; + private static final String PUT_DEVICE_REGISTRY_HTTP_400_MESSAGE = "Could not update device"; + private static final String PATCH_DEVICE_REGISTRY_DESCRIPTION = "Merge/Patch a device"; + private static final String PATCH_DEVICE_REGISTRY_HTTP_200_MESSAGE = "Device merged"; + private static final String PATCH_DEVICE_REGISTRY_HTTP_400_MESSAGE = "Could not merge device"; + private static final String GET_DEVICE_BY_ID_HTTP_200_MESSAGE = "Device by requested deviceId returned"; + private static final String GET_DEVICE_BY_ID_HTTP_400_MESSAGE = "No Such Device by requested deviceId"; + private static final String GET_DEVICES_HTTP_200_MESSAGE = "Devices returned"; + private static final String GET_DEVICES_HTTP_400_MESSAGE = " Invalid parameters"; + private static final String POST_DEVICE_HTTP_201_MESSAGE = "Device created"; + private static final String POST_DEVICE_HTTP_400_MESSAGE = "Could not create device"; + private static final String PUT_DEVICE_HTTP_200_MESSAGE = "Device updated"; + private static final String PUT_DEVICE_HTTP_400_MESSAGE = "Could not update device"; + private static final String PATCH_DEVICE_HTTP_200_MESSAGE = "Device updated"; + private static final String PATCH_DEVICE_HTTP_400_MESSAGE = "Could not update device"; + private static final String DELETE_DEVICE_HTTP_200_MESSAGE = "Device deleted"; + private static final String DELETE_DEVICE_HTTP_400_MESSAGE = "Could not delete device"; + private static final String DELETE_DEVICE_REGISTRY_HTTP_200_MESSAGE = "Device Registry entry removed"; + private static final String DELETE_DEVICE_REGISTRY_HTTP_400_MESSAGE = "Could not remove device registry entry"; + + private final Logger logger = LogManager.getLogger(DeviceRegistryManagementController.class); + private final DeviceRegistryDBService deviceRegistryDBService; + private final Validation validation; + + @Autowired + public DeviceRegistryManagementController(final DeviceRegistryDBService deviceRegistryDBService) { + this.deviceRegistryDBService = deviceRegistryDBService; + this.validation = new Validation(); + } + + //================================================================================================= + // methods + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return device by deviceId", response = DeviceResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_DEVICE_BY_ID_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_DEVICE_BY_ID_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(Constants.DEVICE_BY_ID_URI) + @ResponseBody + public DeviceResponseDTO getDeviceById(@PathVariable(value = Constants.PATH_VARIABLE_ID) final long deviceId) { + logger.debug("getDeviceById started ..."); + validation.checkId(deviceId, getOrigin(Constants.DEVICE_BY_ID_URI)); + return deviceRegistryDBService.getDeviceById(deviceId); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return devices by given request parameters", response = DeviceListResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_DEVICES_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_DEVICES_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(Constants.DEVICES_URI) + @ResponseBody + public DeviceListResponseDTO getDevices( + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_PAGE, required = false) final Integer page, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_ITEM_PER_PAGE, required = false) final Integer size, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_DIRECTION, defaultValue = CoreDefaults.DEFAULT_REQUEST_PARAM_DIRECTION_VALUE) final String direction, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_SORT_FIELD, defaultValue = CoreCommonConstants.COMMON_FIELD_NAME_ID) final String sortField) { + logger.debug("New DeviceList get request received with page: {} and item_per page: {}", page, size); + + final CoreUtilities.ValidatedPageParams pageParameters = CoreUtilities + .validatePageParameters(page, size, direction, getOrigin(Constants.DEVICES_URI)); + final DeviceListResponseDTO deviceListResponseDTO = deviceRegistryDBService.getDeviceEntries(pageParameters, sortField); + logger.debug("DeviceList with page: {} and item_per page: {} successfully retrieved", page, size); + + return deviceListResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return created device", response = DeviceResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_CREATED, message = POST_DEVICE_HTTP_201_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = POST_DEVICE_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(path = Constants.DEVICES_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(org.springframework.http.HttpStatus.CREATED) + @ResponseBody + public DeviceResponseDTO addDevice(@RequestBody final DeviceRequestDTO dto) { + logger.debug("New device registration request received with name: {}", dto.getDeviceName()); + + validation.checkDeviceRequest(dto, getOrigin(Constants.DEVICES_URI)); + + final DeviceResponseDTO responseDTO = deviceRegistryDBService + .createDeviceDto(dto.getDeviceName(), dto.getAddress(), dto.getMacAddress(), dto.getAuthenticationInfo()); + logger.debug("{} successfully registered.", responseDTO); + + return responseDTO; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return updated device", response = DeviceResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_CREATED, message = PUT_DEVICE_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = PUT_DEVICE_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PutMapping(path = Constants.DEVICES_BY_ID_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public DeviceResponseDTO updateDevice(@PathVariable(value = Constants.PATH_VARIABLE_ID) final long deviceId, @RequestBody final DeviceRequestDTO dto) { + logger.debug("New device update request received with deviceId: {}, definition: {}", deviceId, dto); + validation.checkDevicePutRequest(dto, deviceId, getOrigin(Constants.DEVICE_BY_ID_URI)); + + final DeviceResponseDTO deviceResponseDTO = deviceRegistryDBService + .updateDeviceByIdResponse(deviceId, dto.getDeviceName(), dto.getAddress(), dto.getMacAddress(), dto.getAuthenticationInfo()); + logger.debug("Device with deviceId: '{}' successfully updated with definition '{}'.", deviceId, deviceResponseDTO); + + return deviceResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return device updated by fields", response = DeviceResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_CREATED, message = PATCH_DEVICE_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = PATCH_DEVICE_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PatchMapping(path = Constants.DEVICES_BY_ID_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public DeviceResponseDTO mergeDevice(@PathVariable(value = Constants.PATH_VARIABLE_ID) final long deviceId, @RequestBody final DeviceRequestDTO request) { + logger.debug("mergeDevice started..."); + + validation.checkDeviceMergeRequest(request, deviceId, getOrigin(Constants.DEVICES_BY_ID_URI)); + return deviceRegistryDBService.mergeDevice(deviceId, request); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Remove device", tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = DELETE_DEVICE_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DELETE_DEVICE_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @DeleteMapping(path = Constants.DEVICES_BY_ID_URI) + public void removeDevice(@PathVariable(value = Constants.PATH_VARIABLE_ID) final long id) { + logger.debug("New Device delete request received with deviceId: {}", id); + + validation.checkId(id, getOrigin(Constants.DEVICES_BY_ID_URI)); + + deviceRegistryDBService.removeDeviceById(id); + logger.debug("Device with deviceId: '{}' successfully deleted", id); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return requested device registry entries by the given parameters", response = DeviceRegistryListResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_DEVICE_REGISTRY_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_DEVICE_REGISTRY_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = CoreCommonConstants.MGMT_URI) + @ResponseBody + public DeviceRegistryListResponseDTO getDeviceRegistryEntries( + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_PAGE, required = false) final Integer page, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_ITEM_PER_PAGE, required = false) final Integer size, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_DIRECTION, defaultValue = CoreDefaults.DEFAULT_REQUEST_PARAM_DIRECTION_VALUE) final String direction, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_SORT_FIELD, defaultValue = CoreCommonConstants.COMMON_FIELD_NAME_ID) final String sortField) { + logger.debug("New Device Registry get request received with page: {} and item_per page: {}", page, size); + + final CoreUtilities.ValidatedPageParams params = CoreUtilities + .validatePageParameters(page, size, direction, getBaseOrigin()); + final DeviceRegistryListResponseDTO deviceRegistryEntriesResponse = deviceRegistryDBService + .getDeviceRegistryEntries(params, sortField); + logger.debug("Device Registry entries with page: {} and item_per page: {} successfully retrieved", page, size); + + return deviceRegistryEntriesResponse; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return requested device registry entry", response = DeviceRegistryResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_DEVICE_REGISTRY_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_DEVICE_REGISTRY_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = DEVICE_REGISTRY_BY_ID_URI) + @ResponseBody + public DeviceRegistryResponseDTO getDeviceRegistryEntryById(@PathVariable(value = Constants.PATH_VARIABLE_ID) final long id) { + logger.debug("New Device Registry get request received with deviceId: {}", id); + + validation.checkId(id, getOrigin(DEVICE_REGISTRY_BY_ID_URI)); + final DeviceRegistryResponseDTO deviceRegistryEntryByIdResponse = deviceRegistryDBService.getDeviceRegistryById(id); + logger.debug("Device Registry entry with deviceId: {} successfully retrieved", id); + + return deviceRegistryEntryByIdResponse; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return requested device registry entries by device definition based on the given parameters", response = DeviceRegistryListResponseDTO.class, + tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_DEVICE_REGISTRY_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_DEVICE_REGISTRY_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = DEVICE_REGISTRY_BY_DEVICE_NAME_URI) + @ResponseBody + public DeviceRegistryListResponseDTO getDeviceRegistryEntriesByDeviceName( + @PathVariable(value = Constants.PATH_VARIABLE_DEVICE_NAME) final String deviceName, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_PAGE, required = false) final Integer page, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_ITEM_PER_PAGE, required = false) final Integer size, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_DIRECTION, defaultValue = CoreDefaults.DEFAULT_REQUEST_PARAM_DIRECTION_VALUE) final String direction, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_SORT_FIELD, defaultValue = CoreCommonConstants.COMMON_FIELD_NAME_ID) final String sortField) { + logger.debug("New Device Registry get by Device Definition request received with page: {} and item_per page: {}", page, size); + + final String origin = getOrigin(DEVICE_REGISTRY_BY_DEVICE_NAME_URI); + if (Utilities.isEmpty(deviceName)) { + throw new BadPayloadException("Device name cannot be empty.", HttpStatus.SC_BAD_REQUEST, origin); + } + + final CoreUtilities.ValidatedPageParams pageParameters = CoreUtilities.validatePageParameters(page, size, direction, origin); + final DeviceRegistryListResponseDTO deviceRegistryEntries = deviceRegistryDBService + .getDeviceRegistryEntriesByDeviceName(deviceName, pageParameters, sortField); + logger.debug("Device Registry entries with page: {} and item_per page: {} successfully retrieved", page, size); + + return deviceRegistryEntries; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Remove the specified device registry entry", tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = DELETE_DEVICE_REGISTRY_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DELETE_DEVICE_REGISTRY_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @DeleteMapping(path = DEVICE_REGISTRY_BY_ID_URI) + public void removeDeviceRegistryEntryById(@PathVariable(value = Constants.PATH_VARIABLE_ID) final long id) { + logger.debug("New Device Registry delete request received with deviceId: {}", id); + validation.checkId(id, getOrigin(DEVICE_REGISTRY_BY_ID_URI)); + deviceRegistryDBService.removeDeviceRegistryEntryById(id); + logger.debug("Device Registry with deviceId: '{}' successfully deleted", id); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = PUT_DEVICE_REGISTRY_DESCRIPTION, response = DeviceRegistryResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = PUT_DEVICE_REGISTRY_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = PUT_DEVICE_REGISTRY_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PutMapping(path = DEVICE_REGISTRY_BY_ID_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody + DeviceRegistryResponseDTO updateDeviceRegistry(@PathVariable(value = Constants.PATH_VARIABLE_ID) final long id, + @RequestBody final DeviceRegistryRequestDTO request) { + logger.debug("New device registry update request received"); + validation.checkDeviceRegistryUpdateRequest(id, request, getOrigin(DEVICE_REGISTRY_BY_ID_URI)); + + final DeviceRegistryResponseDTO response = deviceRegistryDBService.updateDeviceRegistryById(id, request); + logger.debug("Device Registry entry {} is successfully updated with device {} and device {}", id, request.getDevice().getDeviceName(), + request.getDevice()); + + return response; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = PATCH_DEVICE_REGISTRY_DESCRIPTION, response = DeviceRegistryResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = PATCH_DEVICE_REGISTRY_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = PATCH_DEVICE_REGISTRY_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PatchMapping(path = DEVICE_REGISTRY_BY_ID_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody + DeviceRegistryResponseDTO mergeDeviceRegistry(@PathVariable(value = Constants.PATH_VARIABLE_ID) final long id, + @RequestBody final DeviceRegistryRequestDTO request) { + logger.debug("New device registry merge request received"); + validation.checkDeviceRegistryMergeRequest(id, request, getOrigin(DEVICE_REGISTRY_BY_ID_URI)); + + final DeviceRegistryResponseDTO response = deviceRegistryDBService.mergeDeviceRegistryById(id, request); + logger.debug("Device Registry entry {} is successfully merged witch device {} and device {}", id, response.getDevice(), request.getDevice()); + + return response; + } + + //================================================================================================= + // assistant methods + private String getBaseOrigin() { + return CommonConstants.DEVICE_REGISTRY_URI + CoreCommonConstants.MGMT_URI; + } + + private String getOrigin(final String postfix) { + Assert.notNull(postfix, "Internal error: Origin postfix not provided"); + return getBaseOrigin() + postfix; + } +} \ No newline at end of file diff --git a/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryOnboardingController.java b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryOnboardingController.java new file mode 100644 index 000000000..2d9178d94 --- /dev/null +++ b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/DeviceRegistryOnboardingController.java @@ -0,0 +1,120 @@ +package eu.arrowhead.core.deviceregistry; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.Defaults; +import eu.arrowhead.common.SecurityUtilities; +import eu.arrowhead.common.dto.shared.CertificateType; +import eu.arrowhead.common.dto.shared.DeviceRegistryOnboardingWithCsrRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryOnboardingWithCsrResponseDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryOnboardingWithNameRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryOnboardingWithNameResponseDTO; +import eu.arrowhead.core.deviceregistry.database.service.DeviceRegistryDBService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +@Api(tags = {CoreCommonConstants.SWAGGER_TAG_ALL}) +@CrossOrigin(maxAge = Defaults.CORS_MAX_AGE, allowCredentials = Defaults.CORS_ALLOW_CREDENTIALS, + allowedHeaders = {HttpHeaders.ORIGIN, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT, HttpHeaders.AUTHORIZATION} +) +@RestController +@RequestMapping(CommonConstants.DEVICE_REGISTRY_URI + CommonConstants.ONBOARDING_URI) +public class DeviceRegistryOnboardingController { + + private static final String DEVICE_REGISTRY_REGISTER_DESCRIPTION = "Onboards and registers a device"; + private static final String DEVICE_REGISTRY_REGISTER_201_MESSAGE = "Device registered"; + private static final String DEVICE_REGISTRY_REGISTER_400_MESSAGE = "Could not register device"; + + //================================================================================================= + // members + private final Logger logger = LogManager.getLogger(DeviceRegistryOnboardingController.class); + private final DeviceRegistryDBService deviceRegistryDBService; + private final Validation validation; + + @Autowired + public DeviceRegistryOnboardingController(final DeviceRegistryDBService deviceRegistryDBService) { + this.deviceRegistryDBService = deviceRegistryDBService; + this.validation = new Validation(); + } + + //================================================================================================= + // methods + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = DEVICE_REGISTRY_REGISTER_DESCRIPTION, response = DeviceRegistryOnboardingWithNameResponseDTO.class, tags = + {CoreCommonConstants.SWAGGER_TAG_CLIENT, CoreCommonConstants.SWAGGER_TAG_ONBOARDING}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_CREATED, message = DEVICE_REGISTRY_REGISTER_201_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DEVICE_REGISTRY_REGISTER_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @ResponseStatus(value = org.springframework.http.HttpStatus.CREATED) + @PostMapping(path = CommonConstants.OP_DEVICE_REGISTRY_ONBOARDING_WITH_NAME_URI, + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public DeviceRegistryOnboardingWithNameResponseDTO onboardDevice(final HttpServletRequest httpServletRequest, + @RequestBody final DeviceRegistryOnboardingWithNameRequestDTO request) { + logger.debug("New onboarding with name and device registration request received"); + validation.checkOnboardingRequest(request, getOrigin(CommonConstants.OP_DEVICE_REGISTRY_ONBOARDING_WITH_NAME_URI)); + + final String host = httpServletRequest.getRemoteHost(); + final String address = httpServletRequest.getRemoteAddr(); + final var response = deviceRegistryDBService.onboardAndRegisterDeviceRegistry(request, host, address); + logger.debug("{} successfully registers its device {}", request.getDevice().getDeviceName(), request.getDevice()); + + return response; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = DEVICE_REGISTRY_REGISTER_DESCRIPTION, response = DeviceRegistryOnboardingWithCsrResponseDTO.class, tags = + {CoreCommonConstants.SWAGGER_TAG_CLIENT, CoreCommonConstants.SWAGGER_TAG_ONBOARDING}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_CREATED, message = DEVICE_REGISTRY_REGISTER_201_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DEVICE_REGISTRY_REGISTER_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @ResponseStatus(value = org.springframework.http.HttpStatus.CREATED) + @PostMapping(path = CommonConstants.OP_DEVICE_REGISTRY_ONBOARDING_WITH_CSR_URI, + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public DeviceRegistryOnboardingWithCsrResponseDTO onboardDevice(final HttpServletRequest httpServletRequest, + @RequestBody final DeviceRegistryOnboardingWithCsrRequestDTO request) { + logger.debug("New onboarding with csr and device registration request received"); + validation.checkOnboardingRequest(request, getOrigin(CommonConstants.OP_DEVICE_REGISTRY_ONBOARDING_WITH_CSR_URI)); + + final var response = deviceRegistryDBService.onboardAndRegisterDeviceRegistry(request); + logger.debug("{} successfully registers its device {}", request.getDevice().getDeviceName(), request.getDevice()); + + return response; + } + + //================================================================================================= + // assistant methods + private String getBaseOrigin() { + return CommonConstants.DEVICE_REGISTRY_URI + CommonConstants.ONBOARDING_URI; + } + + private String getOrigin(final String postfix) { + Assert.notNull(postfix, "Internal error: Origin postfix not provided"); + return getBaseOrigin() + postfix; + } +} \ No newline at end of file diff --git a/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/Validation.java b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/Validation.java new file mode 100644 index 000000000..a70fba69c --- /dev/null +++ b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/Validation.java @@ -0,0 +1,210 @@ +package eu.arrowhead.core.deviceregistry; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.dto.shared.DeviceRegistryOnboardingWithCsrRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryOnboardingWithNameRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceRequestDTO; +import eu.arrowhead.common.exception.BadPayloadException; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.time.format.DateTimeParseException; +import java.util.Objects; + +public class Validation { + + private static final String ID_NOT_VALID_ERROR_MESSAGE = "Id must be greater than 0. "; + private static final String DEVICE_NAME_NULL_ERROR_MESSAGE = " Device name must have value "; + private static final String DEVICE_ADDRESS_NULL_ERROR_MESSAGE = " Device address must have value "; + private static final String DEVICE_MAC_ADDRESS_NULL_ERROR_MESSAGE = " Device MAC address must have value "; + + private final Logger logger = LogManager.getLogger(); + + Validation() { super(); } + + //------------------------------------------------------------------------------------------------- + void checkId(final Long id, final String origin) { + logger.debug("checkId started..."); + + if (id == null) { + throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (id < 1) { + throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, CommonConstants.DEVICE_REGISTRY_URI + + CoreCommonConstants.OP_DEVICE_REGISTRY_QUERY_BY_DEVICE_ID_URI); + } + } + + //------------------------------------------------------------------------------------------------- + void checkUnregisterDeviceParameters(final String deviceName, final String macAddress) { + // parameters can't be null, but can be empty + logger.debug("checkUnregisterDeviceParameters started..."); + + final String origin = CommonConstants.DEVICE_REGISTRY_URI + CommonConstants.OP_DEVICE_REGISTRY_UNREGISTER_URI; + + if (Utilities.isEmpty(deviceName)) { + throw new BadPayloadException("Name of the device is blank", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(macAddress)) { + throw new BadPayloadException("MAC Address of the device is blank", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (!Utilities.isValidMacAddress(macAddress)) { + throw new BadPayloadException("Unrecognized format of MAC Address", HttpStatus.SC_BAD_REQUEST, origin); + } + } + + //------------------------------------------------------------------------------------------------- + void checkDeviceMergeRequest(final DeviceRequestDTO request, final Long deviceId, final String origin) { + logger.debug("checkDeviceMergeRequest started..."); + + checkId(deviceId, origin); + + boolean needChange = false; + if (Utilities.notEmpty(request.getAddress())) { + needChange = true; + } + + if (Utilities.notEmpty(request.getDeviceName())) { + needChange = true; + } + + if (Utilities.notEmpty(request.getMacAddress())) { + needChange = true; + } + + if (Utilities.notEmpty(request.getAuthenticationInfo())) { + needChange = true; + } + + if (!needChange) { + throw new BadPayloadException("Patch request is empty.", HttpStatus.SC_BAD_REQUEST, origin); + } + } + + //------------------------------------------------------------------------------------------------- + void checkDevicePutRequest(final DeviceRequestDTO request, final Long deviceId, final String origin) { + logger.debug("checkDevicePutRequest started..."); + checkId(deviceId, origin); + checkDeviceRequest(request, origin); + } + + //------------------------------------------------------------------------------------------------- + void checkDeviceRequest(final DeviceRequestDTO request, final String origin) { + logger.debug("checkDeviceRequest started..."); + + if (request == null) { + throw new BadPayloadException("Device is null.", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(request.getDeviceName())) { + throw new BadPayloadException(DEVICE_NAME_NULL_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(request.getAddress())) { + throw new BadPayloadException(DEVICE_ADDRESS_NULL_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + if (Utilities.isEmpty(request.getMacAddress())) { + throw new BadPayloadException(DEVICE_MAC_ADDRESS_NULL_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + } + + //------------------------------------------------------------------------------------------------- + void checkOnboardingRequest(final DeviceRegistryOnboardingWithNameRequestDTO request, final String origin) { + logger.debug("checkOnboardingRequest started..."); + if (request == null) { + throw new BadPayloadException("Request is null.", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (request.getCertificateCreationRequest() == null) { + throw new BadPayloadException("Certificate creation request is null.", HttpStatus.SC_BAD_REQUEST, origin); + } + + checkDeviceRegistryRequest(request, origin); + } + + //------------------------------------------------------------------------------------------------- + void checkOnboardingRequest(final DeviceRegistryOnboardingWithCsrRequestDTO request, final String origin) { + logger.debug("checkOnboardingRequest started..."); + if (request == null) { + throw new BadPayloadException("Request is null.", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (request.getCertificateSigningRequest() == null) { + throw new BadPayloadException("Certificate signing request is null.", HttpStatus.SC_BAD_REQUEST, origin); + } + + checkDeviceRegistryRequest(request, origin); + } + + //------------------------------------------------------------------------------------------------- + void checkDeviceRegistryRequest(final DeviceRegistryRequestDTO request, final String origin) { + logger.debug("checkDeviceRegistryRequest started..."); + + checkDeviceRequest(request.getDevice(), origin); + + if (!Utilities.isEmpty(request.getEndOfValidity())) { + try { + Utilities.parseUTCStringToLocalZonedDateTime(request.getEndOfValidity().trim()); + } catch (final DateTimeParseException ex) { + throw new BadPayloadException( + "End of validity is specified in the wrong format. Please provide UTC time using " + Utilities.getDatetimePattern() + " pattern.", + HttpStatus.SC_BAD_REQUEST, origin); + } + } + } + + //------------------------------------------------------------------------------------------------- + void checkDeviceRegistryUpdateRequest(final Long id, final DeviceRegistryRequestDTO request, final String origin) { + logger.debug("checkDeviceRegistryUpdateRequest started..."); + + checkId(id, origin); + checkDeviceRegistryRequest(request, origin); + } + + //------------------------------------------------------------------------------------------------- + void checkDeviceRegistryMergeRequest(final Long id, final DeviceRegistryRequestDTO request, final String origin) { + logger.debug("checkDeviceRegistryMergeRequest started..."); + + checkId(id, origin); + + boolean needChange = false; + + if (Objects.nonNull(request.getDevice())) { + final DeviceRequestDTO device = request.getDevice(); + + if (Utilities.notEmpty(device.getDeviceName())) { + needChange = true; + } else if (Utilities.notEmpty(device.getAddress())) { + needChange = true; + } else if (Utilities.notEmpty(device.getMacAddress())) { + needChange = true; + } else if (Utilities.notEmpty(device.getAuthenticationInfo())) { + needChange = true; + } + } + + if (request.getEndOfValidity() != null) { + needChange = true; + } + + if (request.getMetadata() != null) { + needChange = true; + } + + if (request.getVersion() != null && request.getVersion() > 0) { + needChange = true; + } + + if (!needChange) { + throw new BadPayloadException("Patch request is empty.", HttpStatus.SC_BAD_REQUEST, origin); + } + } + +} diff --git a/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/database/service/DeviceRegistryDBService.java b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/database/service/DeviceRegistryDBService.java new file mode 100644 index 000000000..416388f1f --- /dev/null +++ b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/database/service/DeviceRegistryDBService.java @@ -0,0 +1,782 @@ +package eu.arrowhead.core.deviceregistry.database.service; + +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.CoreUtilities; +import eu.arrowhead.common.SecurityUtilities; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.database.entity.Device; +import eu.arrowhead.common.database.entity.DeviceRegistry; +import eu.arrowhead.common.database.entity.System; +import eu.arrowhead.common.database.repository.DeviceRegistryRepository; +import eu.arrowhead.common.database.repository.DeviceRepository; +import eu.arrowhead.common.drivers.CertificateAuthorityDriver; +import eu.arrowhead.common.dto.internal.CertificateSigningRequestDTO; +import eu.arrowhead.common.dto.internal.CertificateSigningResponseDTO; +import eu.arrowhead.common.dto.internal.DTOConverter; +import eu.arrowhead.common.dto.internal.DeviceListResponseDTO; +import eu.arrowhead.common.dto.internal.DeviceRegistryListResponseDTO; +import eu.arrowhead.common.dto.shared.CertificateCreationRequestDTO; +import eu.arrowhead.common.dto.shared.CertificateCreationResponseDTO; +import eu.arrowhead.common.dto.shared.CertificateType; +import eu.arrowhead.common.dto.shared.DeviceQueryFormDTO; +import eu.arrowhead.common.dto.shared.DeviceQueryResultDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryOnboardingWithCsrRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryOnboardingWithCsrResponseDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryOnboardingWithNameRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryOnboardingWithNameResponseDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.DeviceRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceResponseDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.common.exception.InvalidParameterException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; + +import java.security.KeyPair; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@Service +public class DeviceRegistryDBService { + + //================================================================================================= + // members + + private static final String COULD_NOT_DELETE_DEVICE_ERROR_MESSAGE = "Could not delete Device, with given parameters"; + + private final Logger logger = LogManager.getLogger(DeviceRegistryDBService.class); + + private final DeviceRegistryRepository deviceRegistryRepository; + private final DeviceRepository deviceRepository; + private final SecurityUtilities securityUtilities; + private final CertificateAuthorityDriver caDriver; + + @Autowired + public DeviceRegistryDBService(final DeviceRegistryRepository deviceRegistryRepository, + final DeviceRepository deviceRepository, + final SecurityUtilities securityUtilities, + final CertificateAuthorityDriver caDriver) { + this.deviceRegistryRepository = deviceRegistryRepository; + this.deviceRepository = deviceRepository; + this.securityUtilities = securityUtilities; + this.caDriver = caDriver; + } + + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public DeviceResponseDTO getDeviceById(long deviceId) { + logger.debug("getDeviceById started..."); + + try { + final Optional deviceOptional = deviceRepository.findById(deviceId); + if (deviceOptional.isEmpty()) { + throw new InvalidParameterException("Device with id " + deviceId + " not found."); + } + + return DTOConverter.convertDeviceToDeviceResponseDTO(deviceOptional.get()); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceRegistryOnboardingWithNameResponseDTO onboardAndRegisterDeviceRegistry(final DeviceRegistryOnboardingWithNameRequestDTO request, + final String host, final String address) { + logger.debug("onboardAndRegisterDeviceRegistry started..."); + Assert.notNull(request, "DeviceRegistryOnboardingWithNameRequestDTO must not be null"); + + final CertificateCreationRequestDTO creationRequestDTO = request.getCertificateCreationRequest(); + final KeyPair keyPair = securityUtilities.extractOrGenerateKeyPair(creationRequestDTO); + final String certificateSigningRequest; + + try { + certificateSigningRequest = securityUtilities + .createCertificateSigningRequest(creationRequestDTO.getCommonName(), keyPair, CertificateType.AH_DEVICE, host, address); + } catch (final Exception e) { + logger.error(e.getMessage(), e); + throw new ArrowheadException("Unable to create certificate signing request: " + e.getMessage()); + } + + final CertificateCreationResponseDTO signingResponse = signCertificate(certificateSigningRequest); + signingResponse.setKeyPairDTO(securityUtilities.encodeKeyPair(keyPair)); + + final DeviceRegistryOnboardingWithNameResponseDTO retValue = new DeviceRegistryOnboardingWithNameResponseDTO(); + retValue.setCertificateResponse(signingResponse); + retValue.load(registerDeviceRegistry(request)); + return retValue; + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceRegistryOnboardingWithCsrResponseDTO onboardAndRegisterDeviceRegistry(final DeviceRegistryOnboardingWithCsrRequestDTO request) { + + logger.debug("onboardAndRegisterDeviceRegistry started..."); + Assert.notNull(request, "DeviceRegistryOnboardingWithCsrRequestDTO must not be null"); + + final CertificateCreationResponseDTO signingResponse = signCertificate(request.getCertificateSigningRequest()); + securityUtilities.extractAndSetPublicKey(signingResponse); + + final DeviceRegistryOnboardingWithCsrResponseDTO retValue = new DeviceRegistryOnboardingWithCsrResponseDTO(); + retValue.setCertificateResponse(signingResponse); + retValue.load(registerDeviceRegistry(request)); + return retValue; + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceListResponseDTO getDeviceEntries(final CoreUtilities.ValidatedPageParams pageParams, final String sortField) { + logger.debug("getDeviceList started..."); + Assert.notNull(pageParams, "ValidatedPageParams must not be null"); + + final String validatedSortField = Utilities.isEmpty(sortField) ? CoreCommonConstants.COMMON_FIELD_NAME_ID : sortField.trim(); + + if (!System.SORTABLE_FIELDS_BY.contains(validatedSortField)) { + throw new InvalidParameterException("Sortable field with reference '" + validatedSortField + "' is not available"); + } + + try { + final Page devices = deviceRepository.findAll(PageRequest.of(pageParams.getValidatedPage(), pageParams.getValidatedSize(), + pageParams.getValidatedDirection(), validatedSortField)); + return DTOConverter.convertDeviceEntryListToDeviceListResponseDTO(devices); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceResponseDTO createDeviceDto(final String name, final String address, final String macAddress, final String authenticationInfo) { + return DTOConverter.convertDeviceToDeviceResponseDTO(createDevice(name, address, macAddress, authenticationInfo)); + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceResponseDTO updateDeviceByIdResponse(final long id, final String name, final String address, final String macAddress, + final String authenticationInfo) { + + logger.debug("updateDeviceByIdResponse started..."); + + try { + + final long validatedId = validateId(id); + final Device newDevice = validateNonNullDeviceParameters(name, address, macAddress, authenticationInfo); + + final Optional optionalDevice = deviceRepository.findById(validatedId); + final Device device = optionalDevice.orElseThrow(() -> new InvalidParameterException("No device with id : " + id)); + + device.setDeviceName(newDevice.getDeviceName()); + device.setAddress(newDevice.getAddress()); + device.setMacAddress(newDevice.getMacAddress()); + device.setAuthenticationInfo(newDevice.getAuthenticationInfo()); + + return DTOConverter.convertDeviceToDeviceResponseDTO(deviceRepository.saveAndFlush(device)); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public void removeDeviceById(final long id) { + logger.debug("removeDeviceById started..."); + + try { + if (!deviceRepository.existsById(id)) { + throw new InvalidParameterException(COULD_NOT_DELETE_DEVICE_ERROR_MESSAGE); + } + + deviceRepository.deleteById(id); + deviceRepository.flush(); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceResponseDTO mergeDevice(final long deviceId, final DeviceRequestDTO request) { + logger.debug("mergeDevice started..."); + Assert.notNull(request, "DeviceRequestDTO must not be null"); + + try { + final Optional deviceOptional = deviceRepository.findById(deviceId); + final Device device = deviceOptional.orElseThrow(() -> new InvalidParameterException("Device with id " + deviceId + " not found.")); + + return DTOConverter.convertDeviceToDeviceResponseDTO(mergeDevice(request, device)); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceRegistryListResponseDTO getDeviceRegistryEntries(final CoreUtilities.ValidatedPageParams params, final String sortField) { + logger.debug("getDeviceRegistryEntries started..."); + Assert.notNull(params, "ValidatedPageParams must not be null"); + + final String validatedSortField = sortField == null ? CoreCommonConstants.COMMON_FIELD_NAME_ID : sortField.trim(); + + if (!DeviceRegistry.SORTABLE_FIELDS_BY.contains(validatedSortField)) { + throw new InvalidParameterException("Sortable field with reference '" + validatedSortField + "' is not available"); + } + + try { + final PageRequest pageRequest = PageRequest.of(params.getValidatedPage(), + params.getValidatedSize(), + params.getValidatedDirection(), + validatedSortField); + final Page deviceRegistryPage = deviceRegistryRepository.findAll(pageRequest); + return DTOConverter.convertDeviceRegistryListToDeviceRegistryListResponseDTO(deviceRegistryPage); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceRegistryListResponseDTO getDeviceRegistryEntriesByDeviceName(final String deviceName, + final CoreUtilities.ValidatedPageParams params, + final String sortField) { + logger.debug("getDeviceRegistryEntriesByDeviceName started..."); + Assert.notNull(params, "ValidatedPageParams must not be null"); + + final String validatedSortField = sortField == null ? CoreCommonConstants.COMMON_FIELD_NAME_ID : sortField.trim(); + + if (!DeviceRegistry.SORTABLE_FIELDS_BY.contains(validatedSortField)) { + throw new InvalidParameterException("Sortable field with reference '" + validatedSortField + "' is not available"); + } + + try { + final List devices = deviceRepository.findByDeviceName(Utilities.lowerCaseTrim(deviceName)); + + final PageRequest pageRequest = PageRequest.of(params.getValidatedPage(), + params.getValidatedSize(), + params.getValidatedDirection(), + validatedSortField); + final Page deviceRegistryPage = deviceRegistryRepository.findAllByDeviceIsIn(devices, pageRequest); + return DTOConverter.convertDeviceRegistryListToDeviceRegistryListResponseDTO(deviceRegistryPage); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceRegistryResponseDTO getDeviceRegistryById(final long id) { + logger.debug("getDeviceRegistryById started..."); + + return DTOConverter.convertDeviceRegistryToDeviceRegistryResponseDTO(getDeviceRegistryEntryById(id)); + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public void removeDeviceRegistryEntryById(final long id) { + logger.debug("removeDeviceRegistryEntryById started..."); + + try { + if (!deviceRegistryRepository.existsById(id)) { + throw new InvalidParameterException("Device Registry entry with id '" + id + "' does not exist"); + } + + deviceRegistryRepository.deleteById(id); + deviceRegistryRepository.flush(); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceRegistryResponseDTO registerDeviceRegistry(final DeviceRegistryRequestDTO request) { + logger.debug("registerDeviceRegistry started..."); + checkDeviceRegistryRequest(request); + + try { + final Device deviceDb = findOrCreateDevice(request.getDevice()); + + final ZonedDateTime endOfValidity = getZonedDateTime(request); + final String metadataStr = Utilities.map2Text(request.getMetadata()); + final int version = (request.getVersion() != null) ? request.getVersion() : 1; + final DeviceRegistry drEntry = createDeviceRegistry(deviceDb, endOfValidity, metadataStr, version); + + return DTOConverter.convertDeviceRegistryToDeviceRegistryResponseDTO(drEntry); + } catch (final DateTimeParseException ex) { + logger.debug(ex.getMessage(), ex); + throw new InvalidParameterException( + "End of validity is specified in the wrong format. Please provide UTC time using " + Utilities.getDatetimePattern() + " pattern.", ex); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceRegistryResponseDTO updateDeviceRegistryById(final long id, final DeviceRegistryRequestDTO request) { + logger.debug("updateDeviceRegistryById started..."); + + Assert.isTrue(0 < id, "id is not greater than zero"); + checkDeviceRegistryRequest(request); + + try { + final DeviceRegistry drEntry; + final DeviceRegistry updateDrEntry; + + final Optional drEntryOptional = deviceRegistryRepository.findById(id); + drEntry = drEntryOptional.orElseThrow(() -> new InvalidParameterException("Device Registry entry with id '" + id + "' does not exist")); + + final Device deviceDb = findOrCreateDevice(request.getDevice()); + + final ZonedDateTime endOfValidity = getZonedDateTime(request); + final String metadataStr = Utilities.map2Text(request.getMetadata()); + final int version = (request.getVersion() != null) ? request.getVersion() : 1; + updateDrEntry = updateDeviceRegistry(drEntry, deviceDb, endOfValidity, metadataStr, version); + + return DTOConverter.convertDeviceRegistryToDeviceRegistryResponseDTO(updateDrEntry); + } catch (final DateTimeParseException ex) { + logger.debug(ex.getMessage(), ex); + throw new InvalidParameterException( + "End of validity is specified in the wrong format. Please provide UTC time using " + Utilities.getDatetimePattern() + " pattern.", ex); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceRegistryResponseDTO mergeDeviceRegistryById(final long id, final DeviceRegistryRequestDTO request) { + logger.debug("mergeDeviceRegistryById started..."); + Assert.notNull(request, "request is null."); + Assert.isTrue(0 < id, "id is not greater than zero"); + + try { + final DeviceRegistry drEntry; + final DeviceRegistry updateDrEntry; + + final Optional drEntryOptional = deviceRegistryRepository.findById(id); + drEntry = drEntryOptional.orElseThrow(() -> new InvalidParameterException("System Registry entry with id '" + id + "' does not exist")); + + final Device deviceDb = mergeDevice(request.getDevice(), drEntry.getDevice()); + + final ZonedDateTime endOfValidity = Utilities.notEmpty(request.getEndOfValidity()) ? + Utilities.parseUTCStringToLocalZonedDateTime(request.getEndOfValidity().trim()) : + drEntry.getEndOfValidity(); + + final String validatedMetadataStr = Objects.nonNull(request.getMetadata()) ? + Utilities.map2Text(request.getMetadata()) : + drEntry.getMetadata(); + + final int validatedVersion = (request.getVersion() != null) ? request.getVersion() : drEntry.getVersion(); + + updateDrEntry = updateDeviceRegistry(drEntry, deviceDb, endOfValidity, validatedMetadataStr, validatedVersion); + + return DTOConverter.convertDeviceRegistryToDeviceRegistryResponseDTO(updateDrEntry); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final DateTimeParseException ex) { + logger.debug(ex.getMessage(), ex); + throw new InvalidParameterException( + "End of validity is specified in the wrong format. Please provide UTC time using " + Utilities.getDatetimePattern() + " pattern.", ex); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceResponseDTO getDeviceDtoByNameAndMacAddress(final String deviceName, final String macAddress) { + final Device device = getDeviceByNameAndMacAddress(deviceName, macAddress); + return DTOConverter.convertDeviceToDeviceResponseDTO(device); + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public void removeDeviceRegistryByNameAndMacAddress(final String deviceName, final String macAddress) { + logger.debug("removeDeviceRegistryByNameAndMacAddress is started..."); + final Device device = getDeviceByNameAndMacAddress(deviceName, macAddress); + + final Optional optionalDeviceRegistry = deviceRegistryRepository.findByDevice(device); + final DeviceRegistry deviceRegistry = optionalDeviceRegistry.orElseThrow( + () -> new InvalidParameterException( + "Device Registry entry for System with name '" + deviceName + + "' and MAC address '" + macAddress + "' does not exist")); + + deviceRegistryRepository.delete(deviceRegistry); + deviceRegistryRepository.flush(); + } + + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceQueryResultDTO queryRegistry(final DeviceQueryFormDTO form) { + logger.debug("queryRegistry is started..."); + Assert.notNull(form, "Form is null."); + + try { + final List devices; + final List registryList; + final int unfilteredHits; + + if (Utilities.isEmpty(form.getDeviceNameRequirements())) { + throw new InvalidParameterException("Device Name must not be null"); + } + + final String deviceName = Utilities.lowerCaseTrim(form.getDeviceNameRequirements()); + + if (Utilities.notEmpty(form.getMacAddressRequirement())) { + // exact match or no match + final String macAddress = Utilities.lowerCaseTrim(form.getMacAddressRequirement()); + final Optional optionalDevice = deviceRepository.findByDeviceNameAndMacAddress(deviceName, macAddress); + + if (optionalDevice.isPresent()) { + devices = new ArrayList<>(); + devices.add(optionalDevice.get()); + } else { + return DTOConverter.convertDeviceRegistryListToDeviceQueryResultDTO(List.of()); + } + } else { + devices = deviceRepository.findByDeviceName(deviceName); + + if (devices.isEmpty()) { + logger.debug("Device not found: {}", deviceName); + return DTOConverter.convertDeviceRegistryListToDeviceQueryResultDTO(List.of()); + } + } + + registryList = deviceRegistryRepository.findAllByDeviceIsIn(devices); + unfilteredHits = registryList.size(); + + if (Utilities.notEmpty(form.getAddressRequirement())) { + final String address = Utilities.lowerCaseTrim(form.getAddressRequirement()); + devices.removeIf(e -> !e.getAddress().startsWith(address)); + } + + // filter on version + if (Objects.nonNull(form.getVersionRequirement())) { + registryList.removeIf(e -> Objects.equals(form.getVersionRequirement(), e.getVersion())); + } else if (Objects.nonNull(form.getMinVersionRequirement()) || Objects.nonNull(form.getMaxVersionRequirement())) { + final int minVersion = form.getMinVersionRequirement() == null ? 1 : form.getMinVersionRequirement(); + final int maxVersion = form.getMaxVersionRequirement() == null ? Integer.MAX_VALUE : form.getMaxVersionRequirement(); + + registryList.removeIf(e -> (e.getVersion() < minVersion) || (e.getVersion() > maxVersion)); + } + + // filter on metadata + if (form.getMetadataRequirements() != null && !form.getMetadataRequirements().isEmpty()) { + final Map requiredMetadata = normalizeMetadata(form.getMetadataRequirements()); + registryList.removeIf(e -> + { + final Map metadata = Utilities.text2Map(e.getMetadata()); + if (Objects.isNull(metadata)) { + // we have requirements but no metadata -> remove + return true; + } + + return !metadata.entrySet().containsAll(requiredMetadata.entrySet()); + }); + } + + logger.debug("Potential devices after filtering: {}", registryList.size()); + return DTOConverter.convertListOfDeviceRegistryEntriesToDeviceQueryResultDTO(registryList, unfilteredHits); + } catch (final IllegalStateException e) { + throw new InvalidParameterException("Invalid keys in the metadata requirements (whitespace only differences)"); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //================================================================================================= + // assistant methods + //------------------------------------------------------------------------------------------------- + private Device getDeviceByNameAndMacAddress(final String deviceName, final String macAddress) { + final Optional optionalDevice = deviceRepository.findByDeviceNameAndMacAddress(deviceName, macAddress); + return optionalDevice.orElseThrow(() -> new InvalidParameterException( + "Device entry with name '" + deviceName + "' and MAC address '" + macAddress + "' does not exist")); + } + + //------------------------------------------------------------------------------------------------- + private Map normalizeMetadata(final Map metadata) throws IllegalStateException { + logger.debug("normalizeMetadata started..."); + if (metadata == null) { + return Map.of(); + } + + final Map map = new HashMap<>(); + + metadata.forEach((k, v) -> + { + if (Objects.nonNull(v)) { + map.put(k.trim(), v.trim()); + } + }); + + return map; + } + + //------------------------------------------------------------------------------------------------- + private void checkConstraintsOfDeviceTable(final String validatedDeviceName, final String validatedMacAddress) { + logger.debug("checkConstraintsOfDeviceTable started..."); + + try { + final Optional find = deviceRepository.findByDeviceNameAndMacAddress(validatedDeviceName, validatedMacAddress); + if (find.isPresent()) { + throw new InvalidParameterException( + "Device with name: " + validatedDeviceName + ", MAC address: " + validatedMacAddress + " already exists."); + } + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + private Device validateNonNullDeviceParameters(final String deviceName, final String address, final String macAddress, final String authenticationInfo) { + logger.debug("validateNonNullDeviceParameters started..."); + + if (Utilities.isEmpty(deviceName)) { + throw new InvalidParameterException("Name is null or empty"); + } + + if (Utilities.isEmpty(macAddress)) { + throw new InvalidParameterException("MAC address is null or empty"); + } else { + if (!Utilities.isValidMacAddress(macAddress)) { + throw new InvalidParameterException("Unrecognized format of MAC Address"); + } + } + + if (deviceName.contains(".")) { + throw new InvalidParameterException("Name can't contain dot (.)"); + } + + final String validatedDeviceName = Utilities.lowerCaseTrim(deviceName); + final String validatedAddress = Utilities.lowerCaseTrim(address); + final String validatedMacAddress = Utilities.lowerCaseTrim(macAddress); + + checkConstraintsOfDeviceTable(validatedDeviceName, validatedMacAddress); + + return new Device(validatedDeviceName, validatedAddress, validatedMacAddress, authenticationInfo); + } + + //------------------------------------------------------------------------------------------------- + private long validateId(final long id) { + logger.debug("validateId started..."); + + if (id < 1) { + throw new IllegalArgumentException("Id must be greater than zero"); + } + + return id; + } + + //------------------------------------------------------------------------------------------------- + private DeviceRegistry getDeviceRegistryEntryById(final long id) { + logger.debug("getDeviceRegistryEntryById started..."); + try { + final Optional deviceRegistry = deviceRegistryRepository.findById(id); + return deviceRegistry.orElseThrow(() -> new InvalidParameterException("Device Registry with id of '" + id + "' does not exist")); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + private Device findOrCreateDevice(DeviceRequestDTO requestDeviceDto) { + return findOrCreateDevice(requestDeviceDto.getDeviceName(), + requestDeviceDto.getAddress(), + requestDeviceDto.getMacAddress(), + requestDeviceDto.getAuthenticationInfo()); + } + + //------------------------------------------------------------------------------------------------- + private Device findOrCreateDevice(String deviceName, String address, String macAddress, String authenticationInfo) { + + final String validateName = Utilities.lowerCaseTrim(deviceName); + final String validateAddress = Utilities.lowerCaseTrim(address); + final String validatedMacAddress = Utilities.lowerCaseTrim(macAddress); + + final Optional optDevice = deviceRepository.findByDeviceNameAndMacAddress(validateName, validatedMacAddress); + Device device; + + if (optDevice.isPresent()) { + device = optDevice.get(); + if (!Objects.equals(authenticationInfo, device.getAuthenticationInfo()) || + !Objects.equals(validateAddress, device.getAddress())) { // authentication info or device has changed + device.setAuthenticationInfo(authenticationInfo); + device.setAddress(validateAddress); + device = deviceRepository.saveAndFlush(device); + } + } else { + device = createDevice(validateName, validateAddress, validatedMacAddress, authenticationInfo); + } + return device; + } + + //------------------------------------------------------------------------------------------------- + private CertificateCreationResponseDTO signCertificate(final String signingRequest) { + logger.debug("Contact CertificateAuthority ..."); + final CertificateSigningRequestDTO csrDTO = new CertificateSigningRequestDTO(signingRequest); + final CertificateSigningResponseDTO signingResponse = caDriver.signCertificate(csrDTO); + + logger.debug("Processing response from Certificate Authority ..."); + final CertificateCreationResponseDTO certificateResponseDTO = new CertificateCreationResponseDTO(); + certificateResponseDTO.setCertificate(signingResponse.getCertificateChain().get(0)); + certificateResponseDTO.setCertificateFormat(CoreCommonConstants.CERTIFICATE_FORMAT); + certificateResponseDTO.setCertificateType(CertificateType.AH_DEVICE); + return certificateResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + private Device createDevice(final String name, final String address, final String macAddress, final String authenticationInfo) { + final Device device = validateNonNullDeviceParameters(name, address, macAddress, authenticationInfo); + return deviceRepository.saveAndFlush(device); + } + + //------------------------------------------------------------------------------------------------- + private void checkDeviceRegistryRequest(final DeviceRegistryRequestDTO request) { + logger.debug("checkDeviceRegistryRequest started..."); + Assert.notNull(request, "Request is null."); + + Assert.notNull(request.getDevice(), "Device is not specified."); + Assert.isTrue(Utilities.notEmpty(request.getDevice().getDeviceName()), "Device name is not specified."); + Assert.isTrue(Utilities.notEmpty(request.getDevice().getMacAddress()), "Device MAC address is not specified."); + } + + //------------------------------------------------------------------------------------------------- + private void checkConstraintsOfDeviceRegistryTable(final Device deviceDb) { + logger.debug("checkConstraintOfDeviceRegistryTable started..."); + + try { + final Optional find = deviceRegistryRepository.findByDevice(deviceDb); + if (find.isPresent()) { + throw new InvalidParameterException("Device Registry entry with provider: (" + + deviceDb.getDeviceName() + ", " + + deviceDb.getMacAddress() + + ") already exists."); + } + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + private Device mergeDevice(final DeviceRequestDTO request, final Device device) { + final String name = Utilities.firstNotNullIfExists(request.getDeviceName(), device.getDeviceName()); + final String address = Utilities.firstNotNullIfExists(request.getAddress(), device.getAddress()); + final String macAddress = Utilities.firstNotNullIfExists(request.getDeviceName(), device.getDeviceName()); + final String authenticationInfo = Utilities.firstNotNullIfExists(request.getAuthenticationInfo(), device.getAuthenticationInfo()); + return findOrCreateDevice(name, address, macAddress, authenticationInfo); + } + + //------------------------------------------------------------------------------------------------- + private DeviceRegistry createDeviceRegistry(final Device deviceDb, final ZonedDateTime endOfValidity, final String metadataStr, final int version) { + logger.debug("createDeviceRegistry started..."); + + checkConstraintsOfDeviceRegistryTable(deviceDb); + + try { + return deviceRegistryRepository.saveAndFlush(new DeviceRegistry(deviceDb, endOfValidity, metadataStr, version)); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + private boolean checkDeviceRegistryIfUniqueValidationNeeded(final DeviceRegistry drEntry, final Device device) { + logger.debug("checkDeviceRegistryIfUniqueValidationNeeded started..."); + + return drEntry.getDevice().getId() != device.getId(); + + } + + //------------------------------------------------------------------------------------------------- + private DeviceRegistry updateDeviceRegistry(final DeviceRegistry drEntry, final Device device, + final ZonedDateTime endOfValidity, final String metadataStr, final int version) { + logger.debug("updateDeviceRegistry started..."); + Assert.notNull(drEntry, "DeviceRegistry Entry is not specified."); + Assert.notNull(device, "Device is not specified."); + + if (checkDeviceRegistryIfUniqueValidationNeeded(drEntry, device)) { + checkConstraintsOfDeviceRegistryTable(device); + } + + return setModifiedValuesOfDeviceRegistryEntryFields(drEntry, device, endOfValidity, metadataStr, version); + } + + //------------------------------------------------------------------------------------------------- + private ZonedDateTime getZonedDateTime(DeviceRegistryRequestDTO request) { + return Utilities.isEmpty(request.getEndOfValidity()) ? null : Utilities.parseUTCStringToLocalZonedDateTime(request.getEndOfValidity().trim()); + } + + //------------------------------------------------------------------------------------------------- + private DeviceRegistry setModifiedValuesOfDeviceRegistryEntryFields(final DeviceRegistry drEntry, final Device device, + final ZonedDateTime endOfValidity, final String metadataStr, final int version) { + + logger.debug("setModifiedValuesOfDeviceRegistryEntryFields started..."); + + try { + drEntry.setDevice(device); + drEntry.setEndOfValidity(endOfValidity); + drEntry.setMetadata(metadataStr); + drEntry.setVersion(version); + + return deviceRegistryRepository.saveAndFlush(drEntry); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } +} diff --git a/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/security/DeviceRegistryAccessControlFilter.java b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/security/DeviceRegistryAccessControlFilter.java new file mode 100644 index 000000000..ca65b33c5 --- /dev/null +++ b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/security/DeviceRegistryAccessControlFilter.java @@ -0,0 +1,43 @@ +package eu.arrowhead.core.deviceregistry.security; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.SecurityUtilities; +import eu.arrowhead.common.dto.shared.CertificateType; +import eu.arrowhead.common.security.CoreSystemAccessControlFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@ConditionalOnProperty(name = CommonConstants.SERVER_SSL_ENABLED, matchIfMissing = true) +public class DeviceRegistryAccessControlFilter extends CoreSystemAccessControlFilter { + + //================================================================================================= + // assistant methods + private final SecurityUtilities securityUtilities; + + @Autowired + public DeviceRegistryAccessControlFilter(final SecurityUtilities securityUtilities) {this.securityUtilities = securityUtilities;} + + //------------------------------------------------------------------------------------------------- + @Override + protected void checkClientAuthorized(final String clientCN, final String method, final String requestTarget, final String requestJSON, + final Map queryParams) { + + if (requestTarget.contains(CommonConstants.ONBOARDING_URI) || requestTarget.contains(CommonConstants.OP_DEVICE_REGISTRY_UNREGISTER_URI)) { + securityUtilities.authenticateCertificate(clientCN, requestTarget, CertificateType.AH_ONBOARDING); + return; + } + + super.checkClientAuthorized(clientCN, method, requestTarget, requestJSON, queryParams); + final String cloudCN = getServerCloudCN(); + + if (requestTarget.contains(CoreCommonConstants.MGMT_URI)) { + // Only the local System Operator can use these methods + checkIfLocalSystemOperator(clientCN, cloudCN, requestTarget); + } + } +} \ No newline at end of file diff --git a/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/security/DeviceRegistrySecurityConfig.java b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/security/DeviceRegistrySecurityConfig.java new file mode 100644 index 000000000..749ca524f --- /dev/null +++ b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/security/DeviceRegistrySecurityConfig.java @@ -0,0 +1,11 @@ +package eu.arrowhead.core.deviceregistry.security; + +import eu.arrowhead.common.security.DefaultSecurityConfig; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + +@Configuration +@EnableWebSecurity +public class DeviceRegistrySecurityConfig extends DefaultSecurityConfig { + +} \ No newline at end of file diff --git a/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/swagger/DeviceRegistrySwaggerConfig.java b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/swagger/DeviceRegistrySwaggerConfig.java new file mode 100644 index 000000000..2470296e9 --- /dev/null +++ b/deviceregistry/src/main/java/eu/arrowhead/core/deviceregistry/swagger/DeviceRegistrySwaggerConfig.java @@ -0,0 +1,27 @@ +package eu.arrowhead.core.deviceregistry.swagger; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.swagger.DefaultSwaggerConfig; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@EnableSwagger2 +@Configuration +public class DeviceRegistrySwaggerConfig extends DefaultSwaggerConfig { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public DeviceRegistrySwaggerConfig() { + super(CommonConstants.CORE_SYSTEM_DEVICE_REGISTRY); + } + + //------------------------------------------------------------------------------------------------- + @Bean + public Docket customizeSwagger() { + return configureSwaggerForCoreSystem(this.getClass().getPackageName()); + } +} \ No newline at end of file diff --git a/deviceregistry/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/deviceregistry/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..16e979ed4 --- /dev/null +++ b/deviceregistry/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,27 @@ +{"properties": [ + { + "name": "disable.hostname.verifier", + "type": "java.lang.Boolean", + "description": "A description for 'disable.hostname.verifier'" + }, + { + "name": "log_all_request_and_response", + "type": "java.lang.Boolean", + "description": "A description for 'log_all_request_and_response'" + }, + { + "name": "core_system_name", + "type": "java.lang.String", + "description": "A description for 'core_system_name'" + }, + { + "name": "domain.name", + "type": "java.lang.String", + "description": "A description for 'domain.name'" + }, + { + "name": "domain.port", + "type": "java.lang.Integer", + "description": "A description for 'domain.port'" + } +]} \ No newline at end of file diff --git a/deviceregistry/src/main/resources/application.properties b/deviceregistry/src/main/resources/application.properties new file mode 100644 index 000000000..9949ee6f0 --- /dev/null +++ b/deviceregistry/src/main/resources/application.properties @@ -0,0 +1,59 @@ +############################################ +### APPLICATION PARAMETERS ### +############################################ + +# Database connection (mandatory) +# Change the server timezone if necessary +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/arrowhead?serverTimezone=Europe/Budapest +spring.datasource.username=device_registry +spring.datasource.password=iooHU87hNGUalht +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +# use true only for debugging +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.hibernate.ddl-auto=none + +# Device Registry web-server parameters +server.address=0.0.0.0 +server.port=8439 +domain.name=127.0.0.1 +domain.port=8439 + +############################################ +### CUSTOM PARAMETERS ### +############################################ + +# Name of the core system +core_system_name=DEVICE_REGISTRY + +# Show all request/response in debug log +log_all_request_and_response=false + +# Service Registry web-server parameters (to register the Authorization services) +sr_address=127.0.0.1 +sr_port=8443 + +############################################ +### SECURE MODE ### +############################################ + +# configure secure mode + +# Set this to false to disable https mode +server.ssl.enabled=true + +server.ssl.key-store-type=JKS +server.ssl.key-store=classpath:certificates/device_registry.p12 +server.ssl.key-store-password=123456 +server.ssl.key-alias=device_registry +server.ssl.key-password=123456 +server.ssl.client-auth=need +server.ssl.trust-store-type=JKS +server.ssl.trust-store=classpath:certificates/truststore.p12 +server.ssl.trust-store-password=123456 + +#If true, http client does not check whether the hostname is match one of the server's SAN in its certificate +#Just for testing, DO NOT USE this feature in production environment +disable.hostname.verifier=false diff --git a/deviceregistry/src/main/resources/certificates/device_registry.p12 b/deviceregistry/src/main/resources/certificates/device_registry.p12 new file mode 100644 index 000000000..dcd55a150 Binary files /dev/null and b/deviceregistry/src/main/resources/certificates/device_registry.p12 differ diff --git a/deviceregistry/src/main/resources/certificates/truststore.p12 b/deviceregistry/src/main/resources/certificates/truststore.p12 new file mode 100644 index 000000000..57c1c5f43 Binary files /dev/null and b/deviceregistry/src/main/resources/certificates/truststore.p12 differ diff --git a/deviceregistry/src/main/resources/log4j2.xml b/deviceregistry/src/main/resources/log4j2.xml new file mode 100644 index 000000000..8d3f4329b --- /dev/null +++ b/deviceregistry/src/main/resources/log4j2.xml @@ -0,0 +1,49 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex + + INFO + DEBUG + INFO + . + + + + + + + + ${LOG_PATTERN} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/deviceregistry/src/main/resources/swagger/swagger-ui.html b/deviceregistry/src/main/resources/swagger/swagger-ui.html new file mode 100644 index 000000000..fd92ae0f4 --- /dev/null +++ b/deviceregistry/src/main/resources/swagger/swagger-ui.html @@ -0,0 +1,75 @@ + + + + + + Device Registry + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/deviceregistry/src/test/java/eu/arrowhead/common/database/service/DatabaseTestContext.java b/deviceregistry/src/test/java/eu/arrowhead/common/database/service/DatabaseTestContext.java new file mode 100644 index 000000000..e8c11b927 --- /dev/null +++ b/deviceregistry/src/test/java/eu/arrowhead/common/database/service/DatabaseTestContext.java @@ -0,0 +1,14 @@ +package eu.arrowhead.common.database.service; + +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.database.repository.RefreshableRepositoryImpl; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +@SpringBootConfiguration +@EntityScan(basePackages = CoreCommonConstants.DATABASE_ENTITY_PACKAGE) +@EnableJpaRepositories(basePackages = CoreCommonConstants.DATABASE_REPOSITORY_PACKAGE, repositoryBaseClass = RefreshableRepositoryImpl.class) +public class DatabaseTestContext { + public DatabaseTestContext() { super(); } +} diff --git a/deviceregistry/src/test/java/eu/arrowhead/common/database/service/DeviceRepositoryTest.java b/deviceregistry/src/test/java/eu/arrowhead/common/database/service/DeviceRepositoryTest.java new file mode 100644 index 000000000..ddf647dc1 --- /dev/null +++ b/deviceregistry/src/test/java/eu/arrowhead/common/database/service/DeviceRepositoryTest.java @@ -0,0 +1,66 @@ +package eu.arrowhead.common.database.service; + +import eu.arrowhead.common.database.entity.Device; +import eu.arrowhead.common.database.entity.System; +import eu.arrowhead.common.database.repository.DeviceRepository; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; +import java.util.Optional; + +@RunWith(SpringRunner.class) +@DataJpaTest +@TestPropertySource(properties = { + "spring.jpa.hibernate.ddl-auto=create" +}) +@Sql(scripts = "classpath:/sql/devices.sql") +public class DeviceRepositoryTest { + + @Autowired + private DeviceRepository deviceRepository; + + @Test + public void injectedComponentsAreNotNull() { + Assert.assertNotNull(deviceRepository); + } + + @Test + public void findByDeviceNameAndMacAddress() { + final Optional device1 = deviceRepository.findByDeviceNameAndMacAddress("device1", "01:23:45:67:89:AB"); + Assert.assertTrue(device1.isPresent()); + } + + @Test + public void findByDeviceNameAndMacAddress_nonExistentName() { + final Optional device1 = deviceRepository.findByDeviceNameAndMacAddress("device", "01:23:45:67:89:AB"); + Assert.assertFalse(device1.isPresent()); + } + + @Test + public void findByDeviceNameAndMacAddress_nonExistentMacAddress() { + final Optional device1 = deviceRepository.findByDeviceNameAndMacAddress("device1", "FF:FF:FF:FF:FF:FF"); + Assert.assertFalse(device1.isPresent()); + } + + @Test + public void findByDeviceName() { + final List device2 = deviceRepository.findByDeviceName("device2"); + Assert.assertEquals(2, device2.size()); + + final List device3 = deviceRepository.findByDeviceName("device3"); + Assert.assertEquals(2, device3.size()); + } + + @Test + public void findByDeviceName_nonExistent() { + final List devices = deviceRepository.findByDeviceName("device"); + Assert.assertEquals(0, devices.size()); + } +} \ No newline at end of file diff --git a/deviceregistry/src/test/java/eu/arrowhead/core/deviceregistry/DeviceRegistryControllerDeviceRegistryTest.java b/deviceregistry/src/test/java/eu/arrowhead/core/deviceregistry/DeviceRegistryControllerDeviceRegistryTest.java new file mode 100644 index 000000000..da4a5e69d --- /dev/null +++ b/deviceregistry/src/test/java/eu/arrowhead/core/deviceregistry/DeviceRegistryControllerDeviceRegistryTest.java @@ -0,0 +1,426 @@ +package eu.arrowhead.core.deviceregistry; + +import com.fasterxml.jackson.databind.ObjectMapper; +import eu.arrowhead.common.database.service.CommonDBService; +import eu.arrowhead.common.dto.internal.DeviceRegistryListResponseDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.DeviceRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceResponseDTO; +import eu.arrowhead.common.exception.InvalidParameterException; +import eu.arrowhead.core.deviceregistry.database.service.DeviceRegistryDBService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@SpringBootTest +@ContextConfiguration(classes = {DeviceRegistryTestContext.class}) +public class DeviceRegistryControllerDeviceRegistryTest { + + + //================================================================================================= + // test data + private final static String DATE_STRING = "2020-01-01T00:00:00"; + + private final static long VALID_DEVICE_ID = 1L; + + private final static long VALID_DEVICE_REGISTRY_ID = 1L; + private final static long UNKNOWN_DEVICE_REGISTRY_ID = 2L; + private final static long INVALID_DEVICE_REGISTRY_ID = -1L; + + private final static String VALID_DEVICE_NAME = "device"; + private final static String UNKNOWN_DEVICE_NAME = "unknown"; + private final static String INVALID_DEVICE_NAME = ""; + + private static final DeviceRequestDTO VALID_DEVICE_REQUEST = + new DeviceRequestDTO("device", "address", "macAddress", "authenticationInfo"); + private final static DeviceResponseDTO VALID_DEVICE = + new DeviceResponseDTO(VALID_DEVICE_ID, VALID_DEVICE_NAME, "address", "macAddress", + "authenticationInfo", DATE_STRING, DATE_STRING); + + private final static DeviceRegistryResponseDTO VALID_DEVICE_REGISTRY = + new DeviceRegistryResponseDTO(VALID_DEVICE_REGISTRY_ID, VALID_DEVICE, DATE_STRING, + null, 1, DATE_STRING, DATE_STRING); + + + //================================================================================================= + // members + + @Autowired + private WebApplicationContext wac; + + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean(name = "mockDeviceRegistryDBService") + private DeviceRegistryDBService deviceRegistryDBService; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Before + public void setup() { + reset(deviceRegistryDBService); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } + + @Test + public void getDeviceRegistryEntriesWithoutParameter() throws Exception { + final DeviceRegistryListResponseDTO deviceListResponseDTO = new DeviceRegistryListResponseDTO(List.of(VALID_DEVICE_REGISTRY), 1); + when(deviceRegistryDBService.getDeviceRegistryEntries(any(), any())).thenReturn(deviceListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get("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/deviceregistry/mgmt") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final DeviceRegistryListResponseDTO responseBody = readResponse(response, DeviceRegistryListResponseDTO.class); + assertEquals(1, responseBody.getCount()); + } + + @Test + public void getDeviceRegistryEntriesWithPageAndSizeParameter() throws Exception { + final DeviceRegistryListResponseDTO deviceListResponseDTO = new DeviceRegistryListResponseDTO(List.of(VALID_DEVICE_REGISTRY), 1); + when(deviceRegistryDBService.getDeviceRegistryEntries(any(), any())).thenReturn(deviceListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get("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/deviceregistry/mgmt") + .param("page", "0") + .param("item_per_page", String.valueOf(5)) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final DeviceRegistryListResponseDTO responseBody = readResponse(response, DeviceRegistryListResponseDTO.class); + assertEquals(1, responseBody.getCount()); + } + + @Test + public void getDeviceRegistryEntryById() throws Exception { + when(deviceRegistryDBService.getDeviceRegistryById(VALID_DEVICE_REGISTRY_ID)).thenReturn(VALID_DEVICE_REGISTRY); + final MvcResult response = this.mockMvc.perform(get("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/deviceregistry/mgmt/" + VALID_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final DeviceRegistryResponseDTO responseDTO = readResponse(response, DeviceRegistryResponseDTO.class); + assertEquals(VALID_DEVICE_REGISTRY, responseDTO); + } + + @Test + public void getDeviceRegistryEntryByIdUnknownId() throws Exception { + when(deviceRegistryDBService.getDeviceRegistryById(UNKNOWN_DEVICE_REGISTRY_ID)).thenThrow( + new InvalidParameterException("Device Registry with id " + UNKNOWN_DEVICE_REGISTRY_ID + " not found.")); + + this.mockMvc.perform(get("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/deviceregistry/mgmt/" + UNKNOWN_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void getDeviceRegistryEntryByIdNegativeId() throws Exception { + this.mockMvc.perform(get("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/deviceregistry/mgmt/" + INVALID_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void getDeviceRegistryEntriesByDeviceName() throws Exception { + final DeviceRegistryListResponseDTO deviceListResponseDTO = new DeviceRegistryListResponseDTO(List.of(VALID_DEVICE_REGISTRY), 1); + when(deviceRegistryDBService.getDeviceRegistryEntriesByDeviceName(eq(VALID_DEVICE_NAME), any(), any())) + .thenReturn(deviceListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get("/deviceregistry/mgmt/devicename/" + VALID_DEVICE_NAME) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final DeviceRegistryListResponseDTO responseBody = readResponse(response, DeviceRegistryListResponseDTO.class); + assertEquals(1, responseBody.getCount()); + } + + @Test + public void getDeviceRegistryEntriesByUnknownDeviceName() throws Exception { + final DeviceRegistryListResponseDTO deviceListResponseDTO = new DeviceRegistryListResponseDTO(List.of(), 0); + when(deviceRegistryDBService.getDeviceRegistryEntriesByDeviceName(eq(UNKNOWN_DEVICE_NAME), any(), any())) + .thenReturn(deviceListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get("/deviceregistry/mgmt/devicename/" + UNKNOWN_DEVICE_NAME) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final DeviceRegistryListResponseDTO responseBody = readResponse(response, DeviceRegistryListResponseDTO.class); + assertEquals(0, responseBody.getCount()); + } + + @Test + public void getDeviceRegistryEntriesByInvalidDeviceName() throws Exception { + this.mockMvc.perform(get("/deviceregistry/mgmt/devicename/" + INVALID_DEVICE_NAME) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void removeDeviceRegistryEntryByInvalidId() throws Exception { + this.mockMvc.perform(delete("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/deviceregistry/mgmt/" + INVALID_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void removeDeviceRegistryEntryByUnknownId() throws Exception { + doThrow(new InvalidParameterException("No device registry with id : " + UNKNOWN_DEVICE_REGISTRY_ID)) + .when(deviceRegistryDBService) + .removeDeviceRegistryEntryById(eq(UNKNOWN_DEVICE_REGISTRY_ID)); + + this.mockMvc.perform(delete("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/deviceregistry/mgmt/" + UNKNOWN_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void removeDeviceRegistryEntryById() throws Exception { + + this.mockMvc.perform(delete("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/deviceregistry/mgmt/" + VALID_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + } + + @Test + public void updateDeviceRegistryRequest() throws Exception { + final DeviceRegistryRequestDTO dto = new DeviceRegistryRequestDTO(VALID_DEVICE_REQUEST,null, null, 1); + when(deviceRegistryDBService.updateDeviceRegistryById(eq(VALID_DEVICE_REGISTRY_ID), any())).thenReturn(VALID_DEVICE_REGISTRY); + + final MvcResult result = this.mockMvc.perform(put("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/deviceregistry/mgmt/" + VALID_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + assertEquals(VALID_DEVICE_REGISTRY, objectMapper.readValue(result.getResponse().getContentAsString(), DeviceRegistryResponseDTO.class)); + } + + @Test + public void updateDeviceRegistryUnknownId() throws Exception { + final DeviceRegistryRequestDTO dto = new DeviceRegistryRequestDTO(VALID_DEVICE_REQUEST,null, null, 1); + when(deviceRegistryDBService.updateDeviceRegistryById(eq(UNKNOWN_DEVICE_REGISTRY_ID), any())) + .thenThrow(new InvalidParameterException("No device registry with id : " + UNKNOWN_DEVICE_REGISTRY_ID)); + + this.mockMvc.perform(put("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/deviceregistry/mgmt/" + UNKNOWN_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateDeviceRegistryInvalidId() throws Exception { + final DeviceRegistryRequestDTO dto = new DeviceRegistryRequestDTO(VALID_DEVICE_REQUEST,null, null, 1); + this.mockMvc.perform(put("/deviceregistry/mgmt/devices/" + INVALID_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateDeviceRegistryNullPayload() throws Exception { + when(deviceRegistryDBService.updateDeviceRegistryById(eq(VALID_DEVICE_REGISTRY_ID), any())).thenReturn(VALID_DEVICE_REGISTRY); + this.mockMvc.perform(put("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(null))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void mergeDeviceWithOneField() throws Exception { + DeviceRegistryRequestDTO dto = null; + when(deviceRegistryDBService.mergeDeviceRegistryById(eq(VALID_DEVICE_REGISTRY_ID), any())).thenReturn(VALID_DEVICE_REGISTRY); + + dto = new DeviceRegistryRequestDTO(); + dto.setDevice(VALID_DEVICE_REQUEST); + this.mockMvc.perform(patch("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/deviceregistry/mgmt/" + VALID_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + + dto = new DeviceRegistryRequestDTO(); + dto.setEndOfValidity(DATE_STRING); + this.mockMvc.perform(patch("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/deviceregistry/mgmt/" + VALID_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + + dto = new DeviceRegistryRequestDTO(); + dto.setMetadata(Map.of()); + this.mockMvc.perform(patch("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/deviceregistry/mgmt/" + VALID_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + + dto = new DeviceRegistryRequestDTO(); + dto.setVersion(2); + this.mockMvc.perform(patch("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/deviceregistry/mgmt/" + VALID_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + } + + @Test + public void mergeDeviceWithEmpty() throws Exception { + final DeviceRegistryRequestDTO dto = new DeviceRegistryRequestDTO(); + when(deviceRegistryDBService.mergeDeviceRegistryById(eq(VALID_DEVICE_REGISTRY_ID), any())).thenReturn(VALID_DEVICE_REGISTRY); + + this.mockMvc.perform(patch("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/deviceregistry/mgmt/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void mergeDeviceUnknownId() throws Exception { + final DeviceRegistryRequestDTO dto = new DeviceRegistryRequestDTO(VALID_DEVICE_REQUEST, DATE_STRING, null, 1); + when(deviceRegistryDBService.mergeDeviceRegistryById(eq(UNKNOWN_DEVICE_REGISTRY_ID), any())) + .thenThrow(new InvalidParameterException("No device with id : " + UNKNOWN_DEVICE_REGISTRY_ID)); + + this.mockMvc.perform(patch("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/deviceregistry/mgmt/" + UNKNOWN_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void mergeDeviceInvalidId() throws Exception { + final DeviceRegistryRequestDTO dto = new DeviceRegistryRequestDTO(VALID_DEVICE_REQUEST, DATE_STRING, null, 1); + + this.mockMvc.perform(patch("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/deviceregistry/mgmt/" + INVALID_DEVICE_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void registerDeviceNullPayload() throws Exception { + when(deviceRegistryDBService.registerDeviceRegistry(any())).thenReturn(VALID_DEVICE_REGISTRY); + + this.mockMvc.perform(post("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/deviceregistry/register") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(null))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void registerDeviceNullEndOfValidity() throws Exception { + final DeviceRegistryRequestDTO deviceRegistryRequestDTO = + new DeviceRegistryRequestDTO(VALID_DEVICE_REQUEST, null, null, 1); + + when(deviceRegistryDBService.registerDeviceRegistry(any())).thenReturn(VALID_DEVICE_REGISTRY); + + this.mockMvc.perform(post("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/deviceregistry/register") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(deviceRegistryRequestDTO))) + .andExpect(status().isCreated()) + .andReturn(); + } + + @Test + public void registerDeviceInvalidEndOfValidity() throws Exception { + final DeviceRegistryRequestDTO deviceRegistryRequestDTO = + new DeviceRegistryRequestDTO(VALID_DEVICE_REQUEST, "not parsable", null, 1); + + when(deviceRegistryDBService.registerDeviceRegistry(any())).thenReturn(VALID_DEVICE_REGISTRY); + + this.mockMvc.perform(post("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/deviceregistry/register") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(deviceRegistryRequestDTO))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void unregisterDeviceNullDeviceName() throws Exception { + this.mockMvc.perform(delete("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/deviceregistry/unregister") + .param("device_name", "") + .param("mac_address", "macAddress")) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void unregisterDeviceNullMacAddress() throws Exception { + this.mockMvc.perform(delete("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/deviceregistry/unregister") + .param("device_name", "device") + .param("mac_address", "")) + .andExpect(status().isBadRequest()) + .andReturn(); + } + //================================================================================================= + // Tests of device registry + + private T readResponse(final MvcResult result, final Class clz) throws IOException { + return objectMapper.readValue(result.getResponse().getContentAsString(), clz); + } +} \ No newline at end of file diff --git a/deviceregistry/src/test/java/eu/arrowhead/core/deviceregistry/DeviceRegistryControllerDeviceTest.java b/deviceregistry/src/test/java/eu/arrowhead/core/deviceregistry/DeviceRegistryControllerDeviceTest.java new file mode 100644 index 000000000..3873b07e0 --- /dev/null +++ b/deviceregistry/src/test/java/eu/arrowhead/core/deviceregistry/DeviceRegistryControllerDeviceTest.java @@ -0,0 +1,487 @@ +package eu.arrowhead.core.deviceregistry; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import eu.arrowhead.common.database.service.CommonDBService; +import eu.arrowhead.common.dto.internal.DeviceListResponseDTO; +import eu.arrowhead.common.dto.shared.DeviceRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceResponseDTO; +import eu.arrowhead.common.exception.InvalidParameterException; +import eu.arrowhead.core.deviceregistry.database.service.DeviceRegistryDBService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mockito; +import org.mockito.stubbing.OngoingStubbing; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import java.util.List; + +@RunWith(SpringRunner.class) +@SpringBootTest +@ContextConfiguration(classes = {DeviceRegistryTestContext.class}) +public class DeviceRegistryControllerDeviceTest { + + + //================================================================================================= + // test data + private final static long VALID_DEVICE_ID = 1L; + private final static long UNKNOWN_DEVICE_ID = 2L; + private final static long NEGATIVE_DEVICE_ID = -1L; + + private final static DeviceResponseDTO VALID_DEVICE = new DeviceResponseDTO(VALID_DEVICE_ID, "device", "address", "macAddress", + "authenticationInfo", "2020-01-01T00:00:00", "2020-01-01T00:00:00"); + + + //================================================================================================= + // members + + @Autowired + private WebApplicationContext wac; + + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean(name = "mockDeviceRegistryDBService") + private DeviceRegistryDBService deviceRegistryDBService; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Before + public void setup() { + reset(deviceRegistryDBService); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } + + //================================================================================================= + // Tests of device registry + + @Test + public void echoOnboarding() throws Exception { + final MvcResult response = this.mockMvc.perform(get("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/deviceregistry/echo") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + assertEquals("Got it!", response.getResponse().getContentAsString()); + } + + @Test + public void getDeviceById() throws Exception { + when(deviceRegistryDBService.getDeviceById(1)).thenReturn(VALID_DEVICE); + final MvcResult response = this.mockMvc.perform(get("/deviceregistry/mgmt/device/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final DeviceResponseDTO responseDTO = objectMapper.readValue(response.getResponse().getContentAsString(), DeviceResponseDTO.class); + assertEquals(VALID_DEVICE, responseDTO); + } + + @Test + public void getDeviceByIdUnknownId() throws Exception { + when(deviceRegistryDBService.getDeviceById(UNKNOWN_DEVICE_ID)).thenThrow(new InvalidParameterException("Device with id " + UNKNOWN_DEVICE_ID + " not found.")); + + this.mockMvc.perform(get("/deviceregistry/mgmt/device/" + UNKNOWN_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void getDeviceByIdNegativeId() throws Exception { + this.mockMvc.perform(get("/deviceregistry/mgmt/device/" + NEGATIVE_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void getDevicesWithoutParameter() throws Exception { + final DeviceListResponseDTO deviceListResponseDTO = new DeviceListResponseDTO(List.of(VALID_DEVICE), 1); + when(deviceRegistryDBService.getDeviceEntries(any(), any())).thenReturn(deviceListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get("/deviceregistry/mgmt/devices") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final DeviceListResponseDTO responseBody = objectMapper.readValue(response.getResponse().getContentAsString(), DeviceListResponseDTO.class); + assertEquals(1, responseBody.getCount()); + } + + @Test + public void getDevicesWithPageAndSizeParameter() throws Exception { + final DeviceListResponseDTO deviceListResponseDTO = new DeviceListResponseDTO(List.of(VALID_DEVICE), 1); + when(deviceRegistryDBService.getDeviceEntries(any(), any())).thenReturn(deviceListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get("/deviceregistry/mgmt/devices") + .param("page", "0") + .param("item_per_page", String.valueOf(5)) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final DeviceListResponseDTO responseBody = objectMapper.readValue(response.getResponse().getContentAsString(), DeviceListResponseDTO.class); + assertEquals(1, responseBody.getCount()); + } + + @Test + public void createDeviceRequest() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", "address", "macAddress", "authenticationInfo"); + when(deviceRegistryDBService.createDeviceDto(anyString(), anyString(), anyString(), anyString())).thenReturn(VALID_DEVICE); + + final MvcResult result = this.mockMvc.perform(post("/deviceregistry/mgmt/devices") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isCreated()) + .andReturn(); + assertEquals(VALID_DEVICE, objectMapper.readValue(result.getResponse().getContentAsString(), DeviceResponseDTO.class)); + } + + @Test + public void createDeviceRequestNullPayload() throws Exception { + when(deviceRegistryDBService.createDeviceDto(anyString(), anyString(), anyString(), anyString())).thenReturn(VALID_DEVICE); + + this.mockMvc.perform(post("/deviceregistry/mgmt/devices") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(null))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void createDeviceRequestNullDeviceName() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO(null, "address", "macAddress", "authenticationInfo"); + when(deviceRegistryDBService.createDeviceDto(anyString(), anyString(), anyString(), anyString())).thenReturn(VALID_DEVICE); + + this.mockMvc.perform(post("/deviceregistry/mgmt/devices") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void createDeviceRequestEmptyDeviceName() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("", "address", "macAddress", "authenticationInfo"); + when(deviceRegistryDBService.createDeviceDto(anyString(), anyString(), anyString(), anyString())).thenReturn(VALID_DEVICE); + + this.mockMvc.perform(post("/deviceregistry/mgmt/devices") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void createDeviceRequestNullAddress() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", null, "macAddress", "authenticationInfo"); + when(deviceRegistryDBService.createDeviceDto(anyString(), anyString(), anyString(), anyString())).thenReturn(VALID_DEVICE); + + this.mockMvc.perform(post("/deviceregistry/mgmt/devices") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void createDeviceRequestEmptyAddress() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", "", "macAddress", "authenticationInfo"); + when(deviceRegistryDBService.createDeviceDto(anyString(), anyString(), anyString(), anyString())).thenReturn(VALID_DEVICE); + + this.mockMvc.perform(post("/deviceregistry/mgmt/devices") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void createDeviceRequestNullMacAddress() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", "address", null, "authenticationInfo"); + when(deviceRegistryDBService.createDeviceDto(anyString(), anyString(), anyString(), anyString())).thenReturn(VALID_DEVICE); + + this.mockMvc.perform(post("/deviceregistry/mgmt/devices") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void createDeviceRequestEmptyMacAddress() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", "address", " ", "authenticationInfo"); + when(deviceRegistryDBService.createDeviceDto(anyString(), anyString(), anyString(), anyString())).thenReturn(VALID_DEVICE); + + this.mockMvc.perform(post("/deviceregistry/mgmt/devices/") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateDeviceRequest() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", "address", "macAddress", "authenticationInfo"); + when(deviceRegistryDBService.updateDeviceByIdResponse(eq(VALID_DEVICE_ID), anyString(), anyString(), anyString(), anyString())).thenReturn(VALID_DEVICE); + + final MvcResult result = this.mockMvc.perform(put("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + assertEquals(VALID_DEVICE, objectMapper.readValue(result.getResponse().getContentAsString(), DeviceResponseDTO.class)); + } + + @Test + public void updateDeviceUnknownId() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", "address", "macAddress", "authenticationInfo"); + when(deviceRegistryDBService.updateDeviceByIdResponse(eq(UNKNOWN_DEVICE_ID), anyString(), anyString(), anyString(), anyString())).thenThrow(new InvalidParameterException("No device with id : " + UNKNOWN_DEVICE_ID)); + + this.mockMvc.perform(put("/deviceregistry/mgmt/devices/" + UNKNOWN_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateDeviceInvalidId() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", "address", "macAddress", "authenticationInfo"); + + this.mockMvc.perform(put("/deviceregistry/mgmt/devices/" + NEGATIVE_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateDeviceRequestNullPayload() throws Exception { + when(deviceRegistryDBService.updateDeviceByIdResponse(eq(VALID_DEVICE_ID), anyString(), anyString(), anyString(), anyString())).thenReturn(VALID_DEVICE); + this.mockMvc.perform(put("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(null))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateDeviceRequestNullDeviceName() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO(null, "address", "macAddress", "authenticationInfo"); + this.mockMvc.perform(put("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateDeviceRequestEmptyDeviceName() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("", "address", "macAddress", "authenticationInfo"); + this.mockMvc.perform(put("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateDeviceRequestNullAddress() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", null, "macAddress", "authenticationInfo"); + this.mockMvc.perform(put("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateDeviceRequestEmptyAddress() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", "", "macAddress", "authenticationInfo"); + this.mockMvc.perform(put("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateDeviceRequestNullMacAddress() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", "address", null, "authenticationInfo"); + this.mockMvc.perform(put("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateDeviceRequestEmptyMacAddress() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", "address", " ", "authenticationInfo"); + this.mockMvc.perform(put("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void mergeDeviceWithOneField() throws Exception { + DeviceRequestDTO dto = null; + when(deviceRegistryDBService.mergeDevice(eq(VALID_DEVICE_ID), any())).thenReturn(VALID_DEVICE); + + dto = new DeviceRequestDTO(); + dto.setDeviceName("not empty"); + this.mockMvc.perform(patch("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + + dto = new DeviceRequestDTO(); + dto.setMacAddress("not empty"); + this.mockMvc.perform(patch("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + + dto = new DeviceRequestDTO(); + dto.setAddress("not empty"); + this.mockMvc.perform(patch("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + + dto = new DeviceRequestDTO(); + dto.setAuthenticationInfo("not empty"); + this.mockMvc.perform(patch("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + } + + @Test + public void mergeDeviceWithEmpty() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO(); + when(deviceRegistryDBService.mergeDevice(eq(VALID_DEVICE_ID), any())).thenReturn(VALID_DEVICE); + + this.mockMvc.perform(patch("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void mergeDeviceUnknownId() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", "address", "macAddress", "authenticationInfo"); + when(deviceRegistryDBService.mergeDevice(eq(UNKNOWN_DEVICE_ID), any())).thenThrow(new InvalidParameterException("No device with id : " + UNKNOWN_DEVICE_ID)); + + this.mockMvc.perform(patch("/deviceregistry/mgmt/devices/" + UNKNOWN_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void mergeDeviceInvalidId() throws Exception { + final DeviceRequestDTO dto = new DeviceRequestDTO("device", "address", "macAddress", "authenticationInfo"); + + this.mockMvc.perform(patch("/deviceregistry/mgmt/devices/" + NEGATIVE_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void removeDeviceInvalidId() throws Exception { + this.mockMvc.perform(delete("/deviceregistry/mgmt/devices/" + NEGATIVE_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void removeDeviceUnknownId() throws Exception { + doThrow(new InvalidParameterException("No device with id : " + UNKNOWN_DEVICE_ID)) + .when(deviceRegistryDBService) + .removeDeviceById(eq(UNKNOWN_DEVICE_ID)); + + this.mockMvc.perform(delete("/deviceregistry/mgmt/devices/" + UNKNOWN_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void removeDevice() throws Exception { + + this.mockMvc.perform(delete("/deviceregistry/mgmt/devices/" + VALID_DEVICE_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + } +} \ No newline at end of file diff --git a/deviceregistry/src/test/java/eu/arrowhead/core/deviceregistry/DeviceRegistryTestContext.java b/deviceregistry/src/test/java/eu/arrowhead/core/deviceregistry/DeviceRegistryTestContext.java new file mode 100644 index 000000000..7f4b897d4 --- /dev/null +++ b/deviceregistry/src/test/java/eu/arrowhead/core/deviceregistry/DeviceRegistryTestContext.java @@ -0,0 +1,74 @@ +package eu.arrowhead.core.deviceregistry; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.database.repository.CloudRepository; +import eu.arrowhead.common.database.repository.DeviceRegistryRepository; +import eu.arrowhead.common.database.repository.DeviceRepository; +import eu.arrowhead.common.database.repository.SystemRepository; +import eu.arrowhead.common.database.service.CommonDBService; +import eu.arrowhead.core.deviceregistry.database.service.DeviceRegistryDBService; +import org.mockito.Mockito; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.Primary; + +@Configuration +@ComponentScan(basePackages = CommonConstants.BASE_PACKAGE, + excludeFilters = { + @ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*database.*"), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = DeviceRegistryMain.class), + }) +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) +public class DeviceRegistryTestContext { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Bean + @Primary // This bean is primary only in test context + public DeviceRegistryDBService mockDeviceRegistryDBService() { + return Mockito.mock(DeviceRegistryDBService.class); + } + + //------------------------------------------------------------------------------------------------- + @Bean + @Primary // This bean is primary only in test context + public CommonDBService mockCommonDBService() { + return Mockito.mock(CommonDBService.class); + } + + //------------------------------------------------------------------------------------------------- + @Bean + @Primary // This bean is primary only in test context + public CloudRepository mockCloudRepository() { + return Mockito.mock(CloudRepository.class); + } + + //------------------------------------------------------------------------------------------------- + @Bean + @Primary // This bean is primary only in test context + public DeviceRegistryRepository mockDeviceRegistryRepository() { + return Mockito.mock(DeviceRegistryRepository.class); + } + + //------------------------------------------------------------------------------------------------- + @Bean + @Primary // This bean is primary only in test context + public DeviceRepository mockDeviceRepository() { + return Mockito.mock(DeviceRepository.class); + } + + //------------------------------------------------------------------------------------------------- + @Bean + @Primary // This bean is primary only in test context + public SystemRepository mockSystemRepository() { + return Mockito.mock(SystemRepository.class); + } +} \ No newline at end of file diff --git a/deviceregistry/src/test/java/eu/arrowhead/core/deviceregistry/StandaloneModeInDeviceRegistryTests.java b/deviceregistry/src/test/java/eu/arrowhead/core/deviceregistry/StandaloneModeInDeviceRegistryTests.java new file mode 100644 index 000000000..7296b1731 --- /dev/null +++ b/deviceregistry/src/test/java/eu/arrowhead/core/deviceregistry/StandaloneModeInDeviceRegistryTests.java @@ -0,0 +1,9 @@ +package eu.arrowhead.core.deviceregistry; + +import eu.arrowhead.common.testhelper.StandaloneModeInTests; +import org.springframework.stereotype.Component; + +@Component +public class StandaloneModeInDeviceRegistryTests extends StandaloneModeInTests { + +} \ No newline at end of file diff --git a/deviceregistry/src/test/resources/banner.txt b/deviceregistry/src/test/resources/banner.txt new file mode 100644 index 000000000..e69de29bb diff --git a/deviceregistry/src/test/resources/log4j2.xml b/deviceregistry/src/test/resources/log4j2.xml new file mode 100644 index 000000000..4a4d9932d --- /dev/null +++ b/deviceregistry/src/test/resources/log4j2.xml @@ -0,0 +1,31 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex + + OFF + + + + + + + + ${LOG_PATTERN} + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/deviceregistry/src/test/resources/sql/devices.sql b/deviceregistry/src/test/resources/sql/devices.sql new file mode 100644 index 000000000..e6ab7fa20 --- /dev/null +++ b/deviceregistry/src/test/resources/sql/devices.sql @@ -0,0 +1,7 @@ +insert into device (id, device_name, address, mac_address, authentication_info, created_at, updated_at) +values (1, 'device1', '192.168.1.1', '01:23:45:67:89:AB', null, '2020-01-01 00:00:00', '2020-01-01 00:00:00'), + (2, 'device1', '192.168.1.2', '02:23:45:67:89:AB', null, '2020-01-02 00:00:00', '2020-01-02 00:00:00'), + (3, 'device2', '192.168.2.3', '03:23:45:67:89:AB', null, '2020-01-03 00:00:00', '2020-01-03 00:00:00'), + (4, 'device2', '192.168.2.4', '04:23:45:67:89:AB', null, '2020-01-04 00:00:00', '2020-01-04 00:00:00'), + (5, 'device3', '192.168.3.5', '05:23:45:67:89:AB', null, '2020-01-05 00:00:00', '2020-01-05 00:00:00'), + (6, 'device3', '192.168.3.6', '06:23:45:67:89:AB', null, '2020-01-06 00:00:00', '2020-01-06 00:00:00'); \ No newline at end of file diff --git a/deviceregistry/src/test/resources/sql/systems.sql b/deviceregistry/src/test/resources/sql/systems.sql new file mode 100644 index 000000000..a4d351902 --- /dev/null +++ b/deviceregistry/src/test/resources/sql/systems.sql @@ -0,0 +1,7 @@ +insert into system_ (id, address, authentication_info, created_at, port, system_name, updated_at) +values (1, '192.168.1.1', null, '2020-01-01 00:00:00', 1, 'system1', '2020-01-01 00:00:00'), + (2, '192.168.1.2', null, '2020-01-02 00:00:00', 2, 'system2', '2020-01-02 00:00:00'), + (3, '192.168.2.2', null, '2020-01-03 00:00:00', 2, 'system2', '2020-01-03 00:00:00'), + (4, '192.168.1.3', null, '2020-01-04 00:00:00', 3, 'system3', '2020-01-04 00:00:00'), + (5, '192.168.2.3', null, '2020-01-05 00:00:00', 3, 'system3', '2020-01-05 00:00:00'), + (6, '192.168.3.3', null, '2020-01-06 00:00:00', 3, 'system3', '2020-01-06 00:00:00'); \ No newline at end of file diff --git a/docker-all/.gitignore b/docker-all/.gitignore new file mode 100644 index 000000000..b83d22266 --- /dev/null +++ b/docker-all/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/docker-all/Dockerfile b/docker-all/Dockerfile new file mode 100644 index 000000000..c363ff1d5 --- /dev/null +++ b/docker-all/Dockerfile @@ -0,0 +1,8 @@ +FROM openjdk:11-jre-slim + +WORKDIR /opt/arrowhead-core + +COPY target/*.jar ./ +COPY run.sh run.sh + +CMD ["./run.sh"] \ No newline at end of file diff --git a/docker-all/README.md b/docker-all/README.md new file mode 100644 index 000000000..e960e37d5 --- /dev/null +++ b/docker-all/README.md @@ -0,0 +1,36 @@ +# Docker Image of All Core Systems + +In certain scenarios, such as for development, demonstration or testing, it might be preferred to have one Docker image containing all Arrowhead Core systems instead of having one image for each system. +Most significantly, having a single container reduces memory overhead, both in terms of RAM and disk usage. +Note, however, that using this image is _NOT_ recommended for most kinds of production scenarios. + +## Evaluating Image + +To try this image, first make sure that the [`target`](target) folder, located in this directory, contains the `.jar` files of all core systems. +If not, they can be assembled and collected via the following Maven command: + +```sh +$ mvn -DskipTests=true package -pl docker-all -am +``` + +If you are using an IDE, running the maven `package` goal should also cause the [`target`](target) folder to be populated. + +Secondly, change the current directory to the [`example`](example) folder located in this directory, and then execute the following terminal commands: + +```sh +$ docker volume create arrowhead_core_mysql +$ docker-compose up --build +``` + +This should start up a Docker network called `example_default` with both a MySQL database and the image containing the Arrowhead Core systems. +Please refer to the [`example/docker-compose.yml`](example/docker-compose.yml) file for more details about how the latter image can be configured. + +## Building Image + +To build the image for use in other projects, the following command could be used: + +```sh +$ docker build . -t arrowhead-core-all +``` + +Please make sure the folder in which this file is located is the current working directory before executing the above command. diff --git a/docker-all/example/docker-compose.yml b/docker-all/example/docker-compose.yml new file mode 100644 index 000000000..3e193d153 --- /dev/null +++ b/docker-all/example/docker-compose.yml @@ -0,0 +1,42 @@ +version: "3" + +services: + arrowhead_core_mysql: + container_name: arrowhead_core_mysql + image: mysql:5.7 + environment: + - MYSQL_ROOT_PASSWORD=THIS_WILL_BE_YOUR_CONTAINERS_ROOT_PW + volumes: + - arrowhead_core_mysql:/var/lib/mysql + - ./sql:/docker-entrypoint-initdb.d/ + ports: + - 3306:3306 + + arrowhead_core: + container_name: arrowhead_core + build: ../ + depends_on: + - arrowhead_core_mysql + environment: + - JVM_FLAGS=-XX:+UseSerialGC -Xmx1G -Xms32m # Lowers memory usage of the services, but also lowers performance. + volumes: + # Only systems with provided .properties files will be started when the container stars. + - ./properties/serviceregistry.properties:/opt/arrowhead-core/serviceregistry/application.properties + - ./properties/authorization.properties:/opt/arrowhead-core/authorization/application.properties + - ./properties/orchestrator.properties:/opt/arrowhead-core/orchestrator/application.properties + #- ./properties/eventhandler.properties:/opt/arrowhead-core/eventhandler/application.properties + - ./properties/gatekeeper.properties:/opt/arrowhead-core/gatekeeper/application.properties + - ./properties/gateway.properties:/opt/arrowhead-core/gateway/application.properties + - ./properties/certificateauthority.properties:/opt/arrowhead-core/certificate-authority/application.properties + ports: + - 8443:8443 # Service Registry + - 8445:8445 # Authorization + - 8441:8441 # Orchestrator + #- 8455:8455 # Event Handler + - 8449:8449 # Gatekeeper + - 8453:8453 # Gateway + - 8448:8448 # Certificate Authority + +volumes: + arrowhead_core_mysql: + external: true diff --git a/docker-all/example/properties/authorization.properties b/docker-all/example/properties/authorization.properties new file mode 100644 index 000000000..2d4aedd48 --- /dev/null +++ b/docker-all/example/properties/authorization.properties @@ -0,0 +1,61 @@ +############################################ +### APPLICATION PARAMETERS ### +############################################ + +# Database connection +spring.datasource.url=jdbc:mysql://arrowhead_core_mysql:3306/arrowhead?serverTimezone=Europe/Stockholm +spring.datasource.username=authorization +spring.datasource.password=hqZFUkuHxhekio3 +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +# use true only for debugging +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.hibernate.ddl-auto=none + +# Authorization web-server parameters +domain.name=0.0.0.0 +domain.port=8445 +server.port=8445 + +############################################ +### CUSTOM PARAMETERS ### +############################################ + +# Name of the core system +core_system_name=AUTHORIZATION + +# Show all request/response in debug log +log_all_request_and_response=false + +# Service Registry web-server parameters (to register the Authorization services) +sr_address=127.0.0.1 +sr_port=8443 + +#Allow querying access to the authorization tables for application systems (true/false - only has effect in secure mode) +enable_auth_for_cloud=false + +# Interface names has to follow this format --, where security can be SECURE or INSECURE and protocol and format must be a sequence of letters, numbers and underscore. +# A regexp checker will verify that. If this setting is set to true then the PROTOCOL and FORMAT must come from a predefined set. +use_strict_service_intf_name_verifier=true + +# Event handler core system is present +eventhandler_is_present=true + +############################################ +### SECURE MODE ### +############################################ + +#server.ssl.enabled=true +#server.ssl.key-store-type=PKCS12 +#server.ssl.key-store=classpath:certificates/authorization.p12 +#server.ssl.key-store-password=123456 +#server.ssl.key-alias=authorization +#server.ssl.key-password=123456 +#server.ssl.client-auth=need +#server.ssl.trust-store-type=PKCS12 +#server.ssl.trust-store=classpath:certificates/truststore.p12 +#server.ssl.trust-store-password=123456 + +#disable.hostname.verifier=false diff --git a/docker-all/example/properties/certificateauthority.properties b/docker-all/example/properties/certificateauthority.properties new file mode 100644 index 000000000..93f325bd4 --- /dev/null +++ b/docker-all/example/properties/certificateauthority.properties @@ -0,0 +1,59 @@ +############################################ +### APPLICATION PARAMETERS ### +############################################ + +# Database connection (mandatory) +# Change the server timezone if neccessary +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/arrowhead?serverTimezone=Europe/Budapest +spring.datasource.username=certificate_authority +spring.datasource.password=FsdG6Kgf9QpPfv2 +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +# use true only for debugging +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.hibernate.ddl-auto=none + +# Certificate Authority web-server parameters +server.address=127.0.0.1 +server.port=8448 +domain.name=127.0.0.1 +domain.port=8448 + +############################################ +### CUSTOM PARAMETERS ### +############################################ + +# Name of the core system +core_system_name=certificate_authority + +# Show all request/response in debug log +log_all_request_and_response=false + +# Service Registry web-server parameters (to register the Certificate-Authority services) +sr_address=127.0.0.1 +sr_port=8443 + +############################################ +### SECURE MODE ### +############################################ + +# configure secure mode + +# Set this to false to disable https mode +server.ssl.enabled=true + +server.ssl.key-store-type=PKCS12 +server.ssl.key-store=classpath:certificates/certificate_authority.p12 +server.ssl.key-store-password=123456 +server.ssl.key-alias=certificate_authority +server.ssl.key-password=123456 +server.ssl.client-auth=need +server.ssl.trust-store-type=PKCS12 +server.ssl.trust-store=classpath:certificates/truststore.p12 +server.ssl.trust-store-password=123456 + +#If true, http client does not check whether the hostname is match one of the server's SAN in its certificate +#Just for testing, DO NOT USE this feature in production environment +disable.hostname.verifier=false diff --git a/docker-all/example/properties/eventhandler.properties b/docker-all/example/properties/eventhandler.properties new file mode 100644 index 000000000..62f77daff --- /dev/null +++ b/docker-all/example/properties/eventhandler.properties @@ -0,0 +1,61 @@ +############################################ +### APPLICATION PARAMETERS ### +############################################ + +# Database connection +spring.datasource.url=jdbc:mysql://arrowhead_core_mysql:3306/arrowhead?serverTimezone=Europe/Stockholm +spring.datasource.username=event_handler +spring.datasource.password=gRLjXbqu9YwYhfK +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +# use true only for debugging +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.hibernate.ddl-auto=none + +# Event handler web-server parameters +domain.name=0.0.0.0 +domain.port=8455 +server.port=8455 + +############################################ +### CUSTOM PARAMETERS ### +############################################ + +# Name of the core system +core_system_name=EVENT_HANDLER + +# Show all request/response in debug log +log_all_request_and_response=false + +# Service Registry web-server parameters (to register the Event Handler services) +sr_address=127.0.0.1 +sr_port=8443 + +# Publishing tolerance: clients can publish events with timestamps X number of minutes before or after the current time +# 0 means the tolerance is infinite (events can be published with any timestamp) +event_publishing_tolerance=60 + +# Removing old filters from the database based on the endDate field (true/false) +remove_old_filters=false + +# DB check interval in minutes, if "remove_old_filters" is true +check_interval=60 + +############################################ +### SECURE MODE ### +############################################ + +#server.ssl.enabled=true +#server.ssl.key-store-type=PKCS12 +#server.ssl.key-store=classpath:certificates/eventhandler.p12 +#server.ssl.key-store-password=123456 +#server.ssl.key-alias=eventhandler +#server.ssl.key-password=123456 +#server.ssl.client-auth=need +#server.ssl.trust-store-type=PKCS12 +#server.ssl.trust-store=classpath:certificates/truststore.p12 +#server.ssl.trust-store-password=123456 + +#disable.hostname.verifier=false diff --git a/docker-all/example/properties/gatekeeper.properties b/docker-all/example/properties/gatekeeper.properties new file mode 100644 index 000000000..8d3dc3404 --- /dev/null +++ b/docker-all/example/properties/gatekeeper.properties @@ -0,0 +1,60 @@ +############################################ +### APPLICATION PARAMETERS ### +############################################ + +# Database connection +spring.datasource.url=jdbc:mysql://arrowhead_core_mysql:3306/arrowhead?serverTimezone=Europe/Stockholm +spring.datasource.username=gatekeeper +spring.datasource.password=fbJKYzKhU5t8QtT +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +# use true only for debugging +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.hibernate.ddl-auto=none + +# Parameters of Gatekeeper web-server +domain.name=0.0.0.0 +domain.port=8449 +server.port=8449 + +############################################ +### CUSTOM PARAMETERS ### +############################################ + +# Name of the core system +core_system_name=GATEKEEPER + +# Show all request/response in debug log +log_all_request_and_response=false + +# Service Registry web-server parameters (to register the Gatekeeper services) +sr_address=127.0.0.1 +sr_port=8443 + +# Inter-Cloud communication timeout in milliseconds +timeout=30000 + +# If true, operational gateway must be present +gateway_is_present=true + +# Using the Gateway module is mandatory or not during Inter-Cloud orchestration (true/false) +gateway_is_mandatory=true + +############################################ +### SECURE MODE ### +############################################ + +#server.ssl.enabled=true +#server.ssl.key-store-type=PKCS12 +#server.ssl.key-store=classpath:certificates/gatekeeper.p12 +#server.ssl.key-store-password=123456 +#server.ssl.key-alias=gatekeeper +#server.ssl.key-password=123456 +#server.ssl.client-auth=need +#server.ssl.trust-store-type=PKCS12 +#server.ssl.trust-store=classpath:certificates/truststore.p12 +#server.ssl.trust-store-password=123456 + +#disable.hostname.verifier=false \ No newline at end of file diff --git a/docker-all/example/properties/gateway.properties b/docker-all/example/properties/gateway.properties new file mode 100644 index 000000000..810492eb8 --- /dev/null +++ b/docker-all/example/properties/gateway.properties @@ -0,0 +1,55 @@ +############################################ +### APPLICATION PARAMETERS ### +############################################ + +# Database connection +spring.datasource.url=jdbc:mysql://arrowhead_core_mysql:3306/arrowhead?serverTimezone=Europe/Stockholm +spring.datasource.username=gateway +spring.datasource.password=LfiSM9DpGfDEP5g +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +# use true only for debugging +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.hibernate.ddl-auto=none + +# Parameters of Gateway web-server +domain.name=0.0.0.0 +domain.port=8453 +server.port=8453 + +############################################ +### CUSTOM PARAMETERS ### +############################################ + +# Name of the core system +core_system_name=GATEWAY + +# Show all request/response in debug log +log_all_request_and_response=false + +# Service Registry web-server parameters (to register the Gateway services) +sr_address=127.0.0.1 +sr_port=8443 + +# Port range for socket openings (to facilitate inter-cloud communication between consumer and provider systems) +min_port=8001 +max_port=8100 + +############################################ +### SECURE MODE ### +############################################ + +#server.ssl.enabled=true +#server.ssl.key-store-type=PKCS12 +#server.ssl.key-store=classpath:certificates/gateway.p12 +#server.ssl.key-store-password=123456 +#server.ssl.key-alias=gateway +#server.ssl.key-password=123456 +#server.ssl.client-auth=need +#server.ssl.trust-store-type=PKCS12 +#server.ssl.trust-store=classpath:certificates/truststore.p12 +#server.ssl.trust-store-password=123456 + +#disable.hostname.verifier=false diff --git a/docker-all/example/properties/orchestrator.properties b/docker-all/example/properties/orchestrator.properties new file mode 100644 index 000000000..c04642afd --- /dev/null +++ b/docker-all/example/properties/orchestrator.properties @@ -0,0 +1,54 @@ +############################################ +### APPLICATION PARAMETERS ### +############################################ + +# Database connection +spring.datasource.url=jdbc:mysql://arrowhead_core_mysql:3306/arrowhead?serverTimezone=Europe/Stockholm +spring.datasource.username=orchestrator +spring.datasource.password=KbgD2mTr8DQ4vtc +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +# use true only for debugging +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.hibernate.ddl-auto=none + +# Orchestrator web-server parameters +domain.name=0.0.0.0 +domain.port=8441 +server.port=8441 + +############################################ +### CUSTOM PARAMETERS ### +############################################ + +# Name of the core system +core_system_name=ORCHESTRATOR + +# Show all request/response in debug log +log_all_request_and_response=false + +# Service Registry web-server parameters (to register the Orchestrator services) +sr_address=127.0.0.1 +sr_port=8443 + +#If true, operational gatekeeper must be present +gatekeeper_is_present=true + +############################################ +### SECURE MODE ### +############################################ + +#server.ssl.enabled=true +#server.ssl.key-store-type=PKCS12 +#server.ssl.key-store=classpath:certificates/orchestrator.p12 +#server.ssl.key-store-password=123456 +#server.ssl.key-alias=orchestrator +#server.ssl.key-password=123456 +#server.ssl.client-auth=need +#server.ssl.trust-store-type=PKCS12 +#server.ssl.trust-store=classpath:certificates/truststore.p12 +#server.ssl.trust-store-password=123456 + +#disable.hostname.verifier=false diff --git a/docker-all/example/properties/serviceregistry.properties b/docker-all/example/properties/serviceregistry.properties new file mode 100644 index 000000000..fac4899b3 --- /dev/null +++ b/docker-all/example/properties/serviceregistry.properties @@ -0,0 +1,67 @@ +############################################ +### APPLICATION PARAMETERS ### +############################################ + +# Database connection +spring.datasource.url=jdbc:mysql://arrowhead_core_mysql:3306/arrowhead?serverTimezone=Europe/Stockholm +spring.datasource.username=service_registry +spring.datasource.password=ZzNNpxrbZGVvfJ8 +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +# use true only for debugging +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.hibernate.ddl-auto=none + +# Service Registry web-server parameters +domain.name=0.0.0.0 +domain.port=8443 +server.port=8443 + +############################################ +### CUSTOM PARAMETERS ### +############################################ + +# Name of the core system +core_system_name=SERVICE_REGISTRY + +# Show all request/response in debug log +log_all_request_and_response=false + +# Service Registry has an optional feature to ping service providers in a fixed time interval, +# and remove service offerings where the service provider was not available +# use this feature (true/false) +ping_scheduled=false +# how much time the Service Registry should wait for the ping response (in milliseconds) +ping_timeout=5000 +# how frequently should the ping happen, in minutes +ping_interval=60 + +# Service Registry has an optional feature to automatically remove service offerings, where the endOfValidity +# timestamp field is in the past, meaning the offering expired +# use this feature (true/false) +ttl_scheduled=false +# how frequently the database should be checked for expired services, in minutes +ttl_interval=10 + +# Interface names has to follow this format --, where security can be SECURE or INSECURE and protocol and format must be a sequence of letters, numbers and underscore. +# A regexp checker will verify that. If this setting is set to true then the PROTOCOL and FORMAT must come from a predefined set. +use_strict_service_intf_name_verifier=true + +############################################ +### SECURE MODE ### +############################################ + +#server.ssl.enabled=true +#server.ssl.key-store-type=PKCS12 +#server.ssl.key-store=classpath:certificates/serviceregistry.p12 +#server.ssl.key-store-password=123456 +#server.ssl.key-alias=serviceregistry +#server.ssl.key-password=123456 +#server.ssl.client-auth=need +#server.ssl.trust-store-type=PKCS12 +#server.ssl.trust-store=classpath:certificates/truststore.p12 +#server.ssl.trust-store-password=123456 + +#disable.hostname.verifier=false diff --git a/docker-all/example/sql/setup.sql b/docker-all/example/sql/setup.sql new file mode 100644 index 000000000..8fc8e0225 --- /dev/null +++ b/docker-all/example/sql/setup.sql @@ -0,0 +1,549 @@ +DROP DATABASE IF EXISTS `arrowhead`; +CREATE DATABASE IF NOT EXISTS `arrowhead`; +USE `arrowhead`; + +-- Common + +DROP TABLE IF EXISTS `cloud`; +CREATE TABLE `cloud` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `operator` varchar(255) NOT NULL, + `name` varchar(255) NOT NULL, + `secure` int(1) NOT NULL DEFAULT 0 COMMENT 'Is secure?', + `neighbor` int(1) NOT NULL DEFAULT 0 COMMENT 'Is neighbor cloud?', + `own_cloud` int(1) NOT NULL DEFAULT 0 COMMENT 'Is own cloud?', + `authentication_info` varchar(2047) DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `cloud` (`operator`,`name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `relay`; +CREATE TABLE `relay` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `address` varchar(255) NOT NULL, + `port` int(11) NOT NULL, + `secure` int(1) NOT NULL DEFAULT 0, + `exclusive` int(1) NOT NULL DEFAULT 0, + `type` varchar(255) NOT NULL DEFAULT 'GENERAL_RELAY', + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `pair` (`address`, `port`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `cloud_gatekeeper_relay`; +CREATE TABLE `cloud_gatekeeper_relay` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `cloud_id` bigint(20) NOT NULL, + `relay_id` bigint(20) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `pair` (`cloud_id`,`relay_id`), + CONSTRAINT `gk_cloud_constr` FOREIGN KEY (`cloud_id`) REFERENCES `cloud` (`id`) ON DELETE CASCADE, + CONSTRAINT `gk_relay_constr` FOREIGN KEY (`relay_id`) REFERENCES `relay` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `cloud_gateway_relay`; +CREATE TABLE `cloud_gateway_relay` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `cloud_id` bigint(20) NOT NULL, + `relay_id` bigint(20) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `pair` (`cloud_id`,`relay_id`), + CONSTRAINT `gw_cloud_constr` FOREIGN KEY (`cloud_id`) REFERENCES `cloud` (`id`) ON DELETE CASCADE, + CONSTRAINT `gw_relay_constr` FOREIGN KEY (`relay_id`) REFERENCES `relay` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `system_`; +CREATE TABLE `system_` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `system_name` varchar(255) NOT NULL, + `address` varchar(255) NOT NULL, + `port` int(11) NOT NULL, + `authentication_info` varchar(2047) DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `triple` (`system_name`,`address`,`port`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `service_definition`; +CREATE TABLE `service_definition` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `service_definition` varchar(255) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `service_definition` (`service_definition`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `service_interface`; +CREATE TABLE `service_interface` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `interface_name` varchar(255) DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `interface` (`interface_name`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +INSERT INTO `service_interface` (interface_name) VALUES ('HTTP-SECURE-JSON'); +INSERT INTO `service_interface` (interface_name) VALUES ('HTTP-INSECURE-JSON'); + +-- Service Registry + +DROP TABLE IF EXISTS `service_registry`; +CREATE TABLE `service_registry` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `service_id` bigint(20) NOT NULL, + `system_id` bigint(20) NOT NULL, + `service_uri` varchar(255) DEFAULT NULL, + `end_of_validity` timestamp NULL DEFAULT NULL, + `secure` varchar(255) NOT NULL DEFAULT 'NOT_SECURE', + `metadata` text, + `version` int(11) DEFAULT 1, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `pair` (`service_id`,`system_id`), + KEY `system` (`system_id`), + CONSTRAINT `service` FOREIGN KEY (`service_id`) REFERENCES `service_definition` (`id`) ON DELETE CASCADE, + CONSTRAINT `system` FOREIGN KEY (`system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `service_registry_interface_connection`; +CREATE TABLE `service_registry_interface_connection` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `service_registry_id` bigint(20) NOT NULL, + `interface_id` bigint(20) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `pair` (`service_registry_id`,`interface_id`), + KEY `interface_sr` (`interface_id`), + CONSTRAINT `interface_sr` FOREIGN KEY (`interface_id`) REFERENCES `service_interface` (`id`) ON DELETE CASCADE, + CONSTRAINT `service_registry` FOREIGN KEY (`service_registry_id`) REFERENCES `service_registry` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Authorization + +DROP TABLE IF EXISTS `authorization_intra_cloud`; +CREATE TABLE `authorization_intra_cloud` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + `consumer_system_id` bigint(20) NOT NULL, + `provider_system_id` bigint(20) NOT NULL, + `service_id` bigint(20) NOT NULL, + PRIMARY KEY (`id`), + UNIQUE KEY `rule` (`consumer_system_id`,`provider_system_id`,`service_id`), + KEY `provider` (`provider_system_id`), + KEY `service_intra_auth` (`service_id`), + CONSTRAINT `service_intra_auth` FOREIGN KEY (`service_id`) REFERENCES `service_definition` (`id`) ON DELETE CASCADE, + CONSTRAINT `provider` FOREIGN KEY (`provider_system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE, + CONSTRAINT `consumer` FOREIGN KEY (`consumer_system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE + ) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `authorization_inter_cloud`; +CREATE TABLE `authorization_inter_cloud` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `consumer_cloud_id` bigint(20) NOT NULL, + `provider_system_id` bigint(20) NOT NULL, + `service_id` bigint(20) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `rule` (`consumer_cloud_id`, `provider_system_id`, `service_id`), + KEY `service_inter_auth` (`service_id`), + CONSTRAINT `cloud` FOREIGN KEY (`consumer_cloud_id`) REFERENCES `cloud` (`id`) ON DELETE CASCADE, + CONSTRAINT `service_inter_auth` FOREIGN KEY (`service_id`) REFERENCES `service_definition` (`id`) ON DELETE CASCADE, + CONSTRAINT `provider_inter_auth` FOREIGN KEY (`provider_system_id`) REFERENCES `system_` (id) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `authorization_inter_cloud_interface_connection`; +CREATE TABLE `authorization_inter_cloud_interface_connection` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `authorization_inter_cloud_id` bigint(20) NOT NULL, + `interface_id` bigint(20) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `pair` (`authorization_inter_cloud_id`,`interface_id`), + KEY `interface_inter` (`interface_id`), + CONSTRAINT `auth_inter_interface` FOREIGN KEY (`interface_id`) REFERENCES `service_interface` (`id`) ON DELETE CASCADE, + CONSTRAINT `auth_inter_cloud` FOREIGN KEY (`authorization_inter_cloud_id`) REFERENCES `authorization_inter_cloud` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `authorization_intra_cloud_interface_connection`; +CREATE TABLE `authorization_intra_cloud_interface_connection` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `authorization_intra_cloud_id` bigint(20) NOT NULL, + `interface_id` bigint(20) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `pair` (`authorization_intra_cloud_id`,`interface_id`), + KEY `interface_intra` (`interface_id`), + CONSTRAINT `auth_intra_interface` FOREIGN KEY (`interface_id`) REFERENCES `service_interface` (`id`) ON DELETE CASCADE, + CONSTRAINT `auth_intra_cloud` FOREIGN KEY (`authorization_intra_cloud_id`) REFERENCES `authorization_intra_cloud` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Orchestrator + +DROP TABLE IF EXISTS `orchestrator_store`; +CREATE TABLE `orchestrator_store` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `consumer_system_id` bigint(20) NOT NULL, + `provider_system_id` bigint(20) NOT NULL, + `foreign_` int(1) NOT NULL DEFAULT 0, + `service_id` bigint(20) NOT NULL, + `service_interface_id` bigint(20) NOT NULL, + `priority` int(11) NOT NULL, + `attribute` text, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `priority_rule` (`service_id`, `service_interface_id`, `consumer_system_id`,`priority`), + UNIQUE KEY `duplication_rule` (`service_id`, `service_interface_id`, `consumer_system_id`,`provider_system_id`, `foreign_`), + CONSTRAINT `consumer_orch` FOREIGN KEY (`consumer_system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE, + CONSTRAINT `service_orch` FOREIGN KEY (`service_id`) REFERENCES `service_definition` (`id`) ON DELETE CASCADE, + CONSTRAINT `service_intf_orch` FOREIGN KEY (`service_interface_id`) REFERENCES `service_interface` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `foreign_system`; +CREATE TABLE `foreign_system` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `provider_cloud_id` bigint(20) NOT NULL, + `system_name` varchar(255) NOT NULL, + `address` varchar(255) NOT NULL, + `port` int(11) NOT NULL, + `authentication_info` varchar(2047) DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `triple` (`system_name`,`address`,`port`), + CONSTRAINT `foreign_cloud` FOREIGN KEY (`provider_cloud_id`) REFERENCES `cloud` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Logs + +DROP TABLE IF EXISTS `logs`; +CREATE TABLE `logs` ( + `log_id` varchar(100) NOT NULL, + `entry_date` timestamp NULL DEFAULT NULL, + `logger` varchar(100) DEFAULT NULL, + `log_level` varchar(100) DEFAULT NULL, + `message` text, + `exception` text, + PRIMARY KEY (`log_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Event Handler + +DROP TABLE IF EXISTS `event_type`; + CREATE TABLE `event_type` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `event_type_name` varchar(255) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `eventtype` (`event_type_name`) +) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `subscription`; +CREATE TABLE `subscription` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `system_id` bigint(20) NOT NULL, + `event_type_id` bigint(20) NOT NULL, + `filter_meta_data` text, + `match_meta_data` int(1) NOT NULL DEFAULT 0, + `only_predefined_publishers` int(1) NOT NULL DEFAULT 0, + `notify_uri` text NOT NULL, + `start_date` timestamp NULL DEFAULT NULL, + `end_date` timestamp NULL DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `pair` (`event_type_id`,`system_id`), + CONSTRAINT `subscriber_system` FOREIGN KEY (`system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE, + CONSTRAINT `event_type` FOREIGN KEY (`event_type_id`) REFERENCES `event_type` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `subscription_publisher_connection`; +CREATE TABLE `subscription_publisher_connection` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `subscription_id` bigint(20) NOT NULL, + `system_id` bigint(20) NOT NULL, + `authorized` int(1) NOT NULL DEFAULT 0, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `pair` (`subscription_id`,`system_id`), + CONSTRAINT `subscription_constraint` FOREIGN KEY (`subscription_id`) REFERENCES `subscription` (`id`) ON DELETE CASCADE, + CONSTRAINT `system_constraint` FOREIGN KEY (`system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Choreographer + +DROP TABLE IF EXISTS `choreographer_action_plan`; +CREATE TABLE `choreographer_action_plan` ( + `id` bigint(20) PRIMARY KEY AUTO_INCREMENT, + `action_plan_name` varchar(255) UNIQUE NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +)ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `choreographer_action`; +CREATE TABLE `choreographer_action` ( + `id` bigint(20) PRIMARY KEY AUTO_INCREMENT, + `action_name` varchar(255) UNIQUE NOT NULL, + `next_action_id` bigint(20) DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + CONSTRAINT `next_action` FOREIGN KEY (`next_action_id`) REFERENCES `choreographer_action` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `choreographer_action_step`; +CREATE TABLE `choreographer_action_step` ( + `id` bigint(20) PRIMARY KEY AUTO_INCREMENT, + `name` varchar(255) UNIQUE NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP +) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `choreographer_action_plan_action_connection`; +CREATE TABLE `choreographer_action_plan_action_connection` ( + `id` bigint(20) PRIMARY KEY AUTO_INCREMENT, + `action_plan_id` bigint(20) NOT NULL, + `action_id` bigint(20) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + CONSTRAINT `action_plan_fk1` FOREIGN KEY (`action_plan_id`) REFERENCES `choreographer_action_plan` (`id`) ON DELETE CASCADE, + CONSTRAINT `action_fk1` FOREIGN KEY (`action_id`) REFERENCES `choreographer_action` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `choreographer_action_action_step_connection`; +CREATE TABLE `choreographer_action_action_step_connection` ( + `id` bigint(20) PRIMARY KEY AUTO_INCREMENT, + `action_id` bigint(20) NOT NULL, + `action_step_id` bigint(20) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + CONSTRAINT `action_fk2` FOREIGN KEY (`action_id`) REFERENCES `choreographer_action` (`id`) ON DELETE CASCADE, + CONSTRAINT `action_step_fk1` FOREIGN KEY (`action_step_id`) REFERENCES `choreographer_action_step` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `choreographer_action_step_service_definition_connection`; +CREATE TABLE `choreographer_action_step_service_definition_connection` ( + `id` bigint(20) PRIMARY KEY AUTO_INCREMENT, + `action_step_id` bigint(20) NOT NULL, + `service_definition_id` bigint(20) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + CONSTRAINT `service_definition` FOREIGN KEY (`service_definition_id`) REFERENCES `service_definition` (`id`) ON DELETE CASCADE, + CONSTRAINT `action_step` FOREIGN KEY (`action_step_id`) REFERENCES `choreographer_action_step` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +DROP TABLE IF EXISTS `choreographer_next_action_step`; +CREATE TABLE `choreographer_next_action_step` ( + `id` bigint(20) PRIMARY KEY AUTO_INCREMENT, + `action_step_id` bigint(20) NOT NULL, + `next_action_step_id` bigint(20) NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + CONSTRAINT `current_action_step` FOREIGN KEY (`action_step_id`) REFERENCES `choreographer_action_step` (`id`) ON DELETE CASCADE, + CONSTRAINT `next_action_step` FOREIGN KEY (`action_step_id`) REFERENCES `choreographer_action_step` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- Set up privileges + +-- Service Registry +DROP USER IF EXISTS 'service_registry'@'localhost'; +CREATE USER IF NOT EXISTS 'service_registry'@'localhost' IDENTIFIED BY 'ZzNNpxrbZGVvfJ8'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'service_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'service_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'service_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'service_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry` TO 'service_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry_interface_connection` TO 'service_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'service_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'service_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'service_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'service_registry'@'localhost'; + +DROP USER IF EXISTS 'service_registry'@'%'; +CREATE USER IF NOT EXISTS 'service_registry'@'%' IDENTIFIED BY 'ZzNNpxrbZGVvfJ8'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'service_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'service_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'service_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'service_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry` TO 'service_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry_interface_connection` TO 'service_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'service_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'service_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'service_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'service_registry'@'%'; + +-- Authorization +DROP USER IF EXISTS 'authorization'@'localhost'; +CREATE USER IF NOT EXISTS 'authorization'@'localhost' IDENTIFIED BY 'hqZFUkuHxhekio3'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'authorization'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'authorization'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'authorization'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'authorization'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'authorization'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'authorization'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'authorization'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'authorization'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'authorization'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'authorization'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'authorization'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'authorization'@'localhost'; + +DROP USER IF EXISTS 'authorization'@'%'; +CREATE USER IF NOT EXISTS 'authorization'@'%' IDENTIFIED BY 'hqZFUkuHxhekio3'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'authorization'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'authorization'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'authorization'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'authorization'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'authorization'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'authorization'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'authorization'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'authorization'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'authorization'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'authorization'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'authorization'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'authorization'@'%'; + +-- Orchestrator +DROP USER IF EXISTS 'orchestrator'@'localhost'; +CREATE USER IF NOT EXISTS 'orchestrator'@'localhost' IDENTIFIED BY 'KbgD2mTr8DQ4vtc'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'orchestrator'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'orchestrator'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'orchestrator'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'orchestrator'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'orchestrator'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'orchestrator'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`orchestrator_store` TO 'orchestrator'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'orchestrator'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`foreign_system` TO 'orchestrator'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'orchestrator'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`foreign_system` TO 'orchestrator'@'localhost'; + +DROP USER IF EXISTS 'orchestrator'@'%'; +CREATE USER IF NOT EXISTS 'orchestrator'@'%' IDENTIFIED BY 'KbgD2mTr8DQ4vtc'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'orchestrator'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'orchestrator'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'orchestrator'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'orchestrator'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'orchestrator'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'orchestrator'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`orchestrator_store` TO 'orchestrator'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'orchestrator'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`foreign_system` TO 'orchestrator'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'orchestrator'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`foreign_system` TO 'orchestrator'@'%'; + +-- Event Handler +DROP USER IF EXISTS 'event_handler'@'localhost'; +CREATE USER IF NOT EXISTS 'event_handler'@'localhost' IDENTIFIED BY 'gRLjXbqu9YwYhfK'; +GRANT ALL PRIVILEGES ON `arrowhead`.`subscription` TO 'event_handler'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`event_type` TO 'event_handler'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`subscription_publisher_connection` TO 'event_handler'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'event_handler'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'event_handler'@'localhost'; + +DROP USER IF EXISTS 'event_handler'@'%'; +CREATE USER IF NOT EXISTS 'event_handler'@'%' IDENTIFIED BY 'gRLjXbqu9YwYhfK'; +GRANT ALL PRIVILEGES ON `arrowhead`.`subscription` TO 'event_handler'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`event_type` TO 'event_handler'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`subscription_publisher_connection` TO 'event_handler'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'event_handler'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'event_handler'@'%'; + +-- Choreographer +DROP USER IF EXISTS 'choreographer'@'localhost'; +CREATE USER IF NOT EXISTS 'choreographer'@'localhost' IDENTIFIED BY 'Qa5yx4oBp4Y9RLX'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_plan` TO 'choreographer'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action` TO 'choreographer'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_step` TO 'choreographer'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_plan_action_connection` TO 'choreographer'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_action_step_connection` TO 'choreographer'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_step_service_definition_connection` TO 'choreographer'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_next_action_step` TO 'choreographer'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'choreographer'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'choreographer'@'localhost'; + +DROP USER IF EXISTS 'choreographer'@'%'; +CREATE USER IF NOT EXISTS 'choreographer'@'%' IDENTIFIED BY 'Qa5yx4oBp4Y9RLX'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_plan` TO 'choreographer'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action` TO 'choreographer'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_step` TO 'choreographer'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_plan_action_connection` TO 'choreographer'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_action_step_connection` TO 'choreographer'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_action_step_service_definition_connection` TO 'choreographer'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`choreographer_next_action_step` TO 'choreographer'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'choreographer'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'choreographer'@'%'; + +-- Gatekeeper +DROP USER IF EXISTS 'gatekeeper'@'localhost'; +CREATE USER IF NOT EXISTS 'gatekeeper'@'localhost' IDENTIFIED BY 'fbJKYzKhU5t8QtT'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'gatekeeper'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'gatekeeper'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'gatekeeper'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'gatekeeper'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'gatekeeper'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'gatekeeper'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'gatekeeper'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'gatekeeper'@'localhost'; + +DROP USER IF EXISTS 'gatekeeper'@'%'; +CREATE USER IF NOT EXISTS 'gatekeeper'@'%' IDENTIFIED BY 'fbJKYzKhU5t8QtT'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'gatekeeper'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'gatekeeper'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'gatekeeper'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'gatekeeper'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'gatekeeper'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'gatekeeper'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'gatekeeper'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'gatekeeper'@'%'; + +-- Gateway +DROP USER IF EXISTS 'gateway'@'localhost'; +CREATE USER IF NOT EXISTS 'gateway'@'localhost' IDENTIFIED BY 'LfiSM9DpGfDEP5g'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'gateway'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'gateway'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'gateway'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'gateway'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'gateway'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'gateway'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'gateway'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'gateway'@'localhost'; + +DROP USER IF EXISTS 'gateway'@'%'; +CREATE USER IF NOT EXISTS 'gateway'@'%' IDENTIFIED BY 'LfiSM9DpGfDEP5g'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud` TO 'gateway'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'gateway'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'gateway'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`relay` TO 'gateway'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'gateway'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'gateway'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'gateway'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'gateway'@'%'; + +-- Certificate Authority +DROP USER IF EXISTS 'certificate_authority'@'localhost'; +CREATE USER IF NOT EXISTS 'certificate_authority'@'localhost' IDENTIFIED BY 'FsdG6Kgf9QpPfv2'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'certificate_authority'@'localhost'; + +DROP USER IF EXISTS 'certificate_authority'@'%'; +CREATE USER IF NOT EXISTS 'certificate_authority'@'%' IDENTIFIED BY 'FsdG6Kgf9QpPfv2'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'certificate_authority'@'%'; + +FLUSH PRIVILEGES; diff --git a/docker-all/pom.xml b/docker-all/pom.xml new file mode 100644 index 000000000..3ac1745df --- /dev/null +++ b/docker-all/pom.xml @@ -0,0 +1,110 @@ + + + 4.0.0 + + eu.arrowhead + core + ${revision} + + pom + docker-all + docker-all + Docker image containing all core systems + + https://github.com/arrowhead-f/core-java-spring + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + + + + + + eu.arrowhead + arrowhead-authorization + ${revision} + + + eu.arrowhead + arrowhead-eventhandler + ${revision} + + + eu.arrowhead + arrowhead-gatekeeper + ${revision} + + + eu.arrowhead + arrowhead-gateway + ${revision} + + + eu.arrowhead + arrowhead-orchestrator + ${revision} + + + eu.arrowhead + arrowhead-serviceregistry + ${revision} + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + + + copy-jar + package + + copy + + + ${project.build.directory} + + + eu.arrowhead + arrowhead-authorization + jar + + + eu.arrowhead + arrowhead-eventhandler + jar + + + eu.arrowhead + arrowhead-gatekeeper + jar + + + eu.arrowhead + arrowhead-gateway + jar + + + eu.arrowhead + arrowhead-orchestrator + jar + + + eu.arrowhead + arrowhead-serviceregistry + jar + + + true + true + true + + + + + + + \ No newline at end of file diff --git a/docker-all/run.sh b/docker-all/run.sh new file mode 100755 index 000000000..f1528bc4c --- /dev/null +++ b/docker-all/run.sh @@ -0,0 +1,27 @@ +#!/bin/bash + +exit_script() { + echo -e "\e[1;31mExiting ...\e[0m" + trap - INT TERM + kill -$$ +} +trap exit_script INT TERM + +PIDS=() +for JAR in *.jar; do + NAME=$(echo "${JAR}" | sed 's/arrowhead-\([^-]*\)-.*/\1/') + PROPERTIES="${NAME}/application.properties" + if [[ -f "${PROPERTIES}" ]]; then + echo -e "\e[1;32mjava ${JVM_FLAGS} -jar ${JAR} &\e[0m" + cd "${NAME}" + java ${JVM_FLAGS} -jar "../${JAR}" & + PIDS+=" $!" + cd .. + else + echo -e "\e[1;31m${PROPERTIES} not provided; skipping ${JAR}" + fi +done + +for PID in ${PIDS[*]}; do + wait "${PID}" +done diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 000000000..3b9d52afa --- /dev/null +++ b/docker/README.md @@ -0,0 +1,45 @@ +# Docker Compose Example Files + +This folder contains various files for setting up a network of Arrowhead Core systems, each located in its own Docker container. +Using the files requires you to follow the below steps: + +## Create Container Volumes + +In order for data to persist after shutting down your containers, you must use a so-called _Docker Volume_. +The one needed by the [`docker-compose.yml`](docker-compose.yml) file in this folder requires one to exist with the name `mysql`. +The following terminal command may be used to create such a volume: + +```sh +$ docker volume create --name=mysql +``` + +## Copy Initialization Scripts for the MySQL Database + +When the database container of the [`docker-compose.yml`](docker-compose.yml) starts, its database will be empty. +As the Arrowhead Core systems do not attempt to create the database tables themselves if they do not exist, you must make sure that they are created by the database container when it is started for the first time. +The following terminal command may be used, given that the root directory of this repository is the current working directory, to copy database initialization scripts to a location from which they will be read by the [`docker-compose.yml`](docker-compose.yml) file: + +```sh +$ cp scripts/create_empty_arrowhead_db.sql docker/ +``` + +## Configuring the Core Systems + +The [`core_system_config`](core_system_config) folder contains a collection of `.properties` files, each of which is passed to an Arrowhead Core system when the network described in [`docker-compose.yml`](docker-compose.yml) is brought up. +You may want to look at, or perhaps even edit, some of those files to get a better understanding of how the Arrowhead Core systems can be configured. +Editing them is not required, however, for the example network to run. + +## Running the Compose Script + +Having completed the above steps, you are ready to execute the following command from this directory: + +```sh +$ docker-compose up --build +``` + +To shut down the `docker_default` network you just started, use `CTRL-C`, or whatever keyboard combination is used to send the interrupt signal to Docker. +Afterwards, you may use the following command to clean up any remaining resources: + +```sh +$ docker-compose down +``` diff --git a/docker/core_system_config/certificateauthority.properties b/docker/core_system_config/certificateauthority.properties new file mode 100644 index 000000000..93f325bd4 --- /dev/null +++ b/docker/core_system_config/certificateauthority.properties @@ -0,0 +1,59 @@ +############################################ +### APPLICATION PARAMETERS ### +############################################ + +# Database connection (mandatory) +# Change the server timezone if neccessary +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/arrowhead?serverTimezone=Europe/Budapest +spring.datasource.username=certificate_authority +spring.datasource.password=FsdG6Kgf9QpPfv2 +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +# use true only for debugging +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.hibernate.ddl-auto=none + +# Certificate Authority web-server parameters +server.address=127.0.0.1 +server.port=8448 +domain.name=127.0.0.1 +domain.port=8448 + +############################################ +### CUSTOM PARAMETERS ### +############################################ + +# Name of the core system +core_system_name=certificate_authority + +# Show all request/response in debug log +log_all_request_and_response=false + +# Service Registry web-server parameters (to register the Certificate-Authority services) +sr_address=127.0.0.1 +sr_port=8443 + +############################################ +### SECURE MODE ### +############################################ + +# configure secure mode + +# Set this to false to disable https mode +server.ssl.enabled=true + +server.ssl.key-store-type=PKCS12 +server.ssl.key-store=classpath:certificates/certificate_authority.p12 +server.ssl.key-store-password=123456 +server.ssl.key-alias=certificate_authority +server.ssl.key-password=123456 +server.ssl.client-auth=need +server.ssl.trust-store-type=PKCS12 +server.ssl.trust-store=classpath:certificates/truststore.p12 +server.ssl.trust-store-password=123456 + +#If true, http client does not check whether the hostname is match one of the server's SAN in its certificate +#Just for testing, DO NOT USE this feature in production environment +disable.hostname.verifier=false diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index a3692f5e6..ebeb3c0c3 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -14,7 +14,7 @@ services: serviceregistry: container_name: serviceregistry - image: portus.arrowhead-ci.tmit.bme.hu/arrowhead/serviceregistry:latest + image: svetlint/serviceregistry:latest depends_on: - mysql volumes: @@ -26,7 +26,7 @@ services: authorization: container_name: authorization - image: portus.arrowhead-ci.tmit.bme.hu/arrowhead/authorization:latest + image: svetlint/authorization:latest depends_on: - mysql volumes: @@ -36,7 +36,7 @@ services: orchestrator: container_name: orchestrator - image: portus.arrowhead-ci.tmit.bme.hu/arrowhead/orchestrator:latest + image: svetlint/orchestrator:latest depends_on: - mysql volumes: @@ -46,7 +46,7 @@ services: eventhandler: container_name: eventhandler - image: portus.arrowhead-ci.tmit.bme.hu/arrowhead/eventhandler:latest + image: svetlint/eventhandler:latest depends_on: - mysql volumes: @@ -56,7 +56,7 @@ services: gatekeeper: container_name: gatekeeper - image: portus.arrowhead-ci.tmit.bme.hu/arrowhead/gatekeeper:latest + image: svetlint/gatekeeper:latest depends_on: - mysql volumes: @@ -66,13 +66,23 @@ services: gateway: container_name: gateway - image: portus.arrowhead-ci.tmit.bme.hu/arrowhead/gateway:latest + image: svetlint/gateway:latest depends_on: - mysql volumes: - ./core_system_config/gateway.properties:/gateway/application.properties ports: - - 8453:8453 + - 8453:8453 + + certificateauthority: + container_name: certificateauthority + image: svetlint/certificateauthority:latest + depends_on: + - mysql + volumes: + - ./core_system_config/certificateauthority.properties:/certificateauthority/application.properties + ports: + - 8448:8448 volumes: mysql: diff --git a/documentation/certificate_authority/ReleaseNotes-4.1.3-CertificateAuthority.odt b/documentation/certificate_authority/ReleaseNotes-4.1.3-CertificateAuthority.odt new file mode 100644 index 000000000..eb222ba70 Binary files /dev/null and b/documentation/certificate_authority/ReleaseNotes-4.1.3-CertificateAuthority.odt differ diff --git a/documentation/certificates/docker_certificate_guide.md b/documentation/certificates/docker_certificate_guide.md new file mode 100644 index 000000000..a0a31a7dc --- /dev/null +++ b/documentation/certificates/docker_certificate_guide.md @@ -0,0 +1,81 @@ +# How to include certificate into docker + +## Prerequisites +1. You have certificates for **all** your core systems. If not, follow the [Certificate guide](/README.md#certificates) first. + + +## Steps +1. [Check you have all the necessary certificates](#step01) +2. [Edit your property file](#step02) +3. [Overwrite the Secure Mode properties](#step03) +4. [Edit your docker-compose.yml](#step04) +5. [Mount the certificates as a volume to the containers](#step04) + +
+ +## 1. Check you have all the necessary certificates + +Please make sure, you have already generated the certificates you wish to use. + +![Step 1](/documentation/images/images_docker_certificate_guide/step01.png) + + + + +## 2. Edit your property file + +Open the Core Systems `application.properties` file with your favorite editor. + +![Step 2](/documentation/images/images_docker_certificate_guide/step02.png) + + + +## 3. Overwrite the Secure Mode properties + +Scroll down to the **Secure Mode** part of the properties file and edit: + * `server.ssl-key-store` property + + By default its value is: `classpath:certificates/service_registry.p12`, it means it will search for the certificate **inside** the JAR file, we have to change it to `file: + +## 4. Edit your docker-compose.yml + +Open the `docker-compose.yml` file with your favorite editor. + +![Step 4](/documentation/images/images_docker_certificate_guide/step04.png) + + + +## 5. Mount the certificates as a volume to the containers + +Mount the certificate file as a volume inside the container. + +The syntax is: - outside_path/outside_certificate.name:inside_path/inside_certificate.name + +![Step 5](/documentation/images/images_docker_certificate_guide/step05.png) + +In the image you can see two examples. I'll explain the first one. + +`- ./tmit_certs/service_registry.p12:/serviceregistry/service_registry.p12` + +In [Step 1](#step1) we saw that our certificates were inside a folder called `tmit_certs`. We are mounting the `service_registry.p12` file from the `tmit_certs` folder on the host machine inside the Docker Container into the `serviceregistry` folder under the name of `service_registry.p12` + +> **Note:** The certificate name you specified in [Step 3](#step03) **MUST** match the `inside_certificate.name` specified in [Step 5](#step05), otherwise it won't work. + + +## Congratulations, you are all set! You can start your containers :) + + diff --git a/documentation/development/developer_tmp.txt b/documentation/development/developer_tmp.txt index 3d4a5b14a..7cf0d8b18 100644 --- a/documentation/development/developer_tmp.txt +++ b/documentation/development/developer_tmp.txt @@ -50,7 +50,7 @@ JMS Api and Apache ActiveMQ Client Every core system have basically the same general structure. We define three separate layers. -The first layer (web layer) is for the web service endpoints (in the controller classes) Here we define the REST endpoints, perform basic input validations and sometimes minor conversations on input parameters (i.e. create an enumeration value from a String). Basic validation means checking mandatory parameters are specified and valid, specified optional paramters are valid, the specified parameter combination is valid. We check everything in this layer that is possible without accessing the database (so no unique constraint checking here). +The first layer (web layer) is for the web service endpoints (in the controller classes) Here we define the REST endpoints, perform basic input validations and sometimes minor conversations on input parameters (i.e. create an enumeration value from a String). Basic validation means checking mandatory parameters are specified and valid, specified optional parameters are valid, the specified parameter combination is valid. We check everything in this layer that is possible without accessing the database (so no unique constraint checking here). In the web layer no business logic is implemented, endpoints call a method from the second layer after input validation and possible conversation steps and returns the value. Let's see an example for an endpoint: @RestController @@ -273,7 +273,7 @@ Let's see the contents of the module: - a predefined set of core systems can use query (/query URI) without limitations; - a predefined set of core systems can use query by system (/query/system/{id} URI); - * eu.arrowhead.core.serviceregistry.swagger.SRSwaggerConfig: it is a descendant class of DefaultSwaggerConfig. It configures and actives Swagger UI. See Swagger Documentation for details. + * eu.arrowhead.core.serviceregistry.swagger.SRSwaggerConfig: it is a descendant class of DefaultSwaggerConfig. It configures and activates Swagger UI. See Swagger Documentation for details. 9.3 Authorization Module @@ -290,18 +290,63 @@ Let's see the contents of the module: * eu.arrowhead.core.authorization.AuthorizationMain: the main class of the Authorization core system is the default implementation of the Spring Boot web server (see Spring Boot documentation). We using annotations to tell Spring this is a Spring Boot application (@SpringBootApplication) and where to search for Spring-managed classes (@ComponentScan), database entities (@EntityScan) and database repositories (@EnableJpaRepositories). And it enables Swagger UI (@EnableSwagger2 annotation) * eu.arrowhead.core.authorization.AuthorizationApplicationInitListener: it overrides the getRequiredCoreSystemServiceUris(), because if there is Event Handler in the local cloud the it needs one of the Event Handler's service URIs to be able to notify about authorization rule changes. * eu.arrowhead.core.authorization.AuthorizationController: it contains the web service endpoints of the Authorization core system, see Authorization API documentation. +* eu.arrowhead.core.authorization.database.service.AuthorizationDBService: this class implements the higher level database-related methods that handle inter-cloud and intra-cloud rule creation, deletion, reading and checking. +* eu.arrowhead.core.authorization.security.AuthSecurityConfig: it's an empty descendant of the DefaultSecurityConfig class. We use @EnableWebSecurity and @Configuration annotations to activate the security. +* eu.arrowhead.core.authorization.security.AuthAccessControlFilter: it is a descendant class of the CoreSystemAccessControlFilter and it enforces authentication requirements of the Authorization web services. Only works in secured mode (see @ConditionalOnProperty annotation). Implemented rules: + - web services are only accessible from the local cloud (inherited through the base class); + - management web services (/mgmt appears in the URI) are only accessible to the local system operator (sysop...arrowhead.eu); + - a predefined set of core systems can use authorization checking and token generation services; + +* eu.arrowhead.core.authorization.swagger.AuthSwaggerConfig: it is a descendant class of DefaultSwaggerConfig. It configures and activates Swagger UI. See Swagger Documentation for details. +* eu.arrowhead.core.authorization.token.TokenGenerationService: this class implements the token generation feature. The token is an additional security tool that Arrowhead providers can utilize to make sure that any consumer trying to use its services comes through the proper channel (using orchestration). A token is a long string identifier in which is signed (by the Authorization core system) and encrypted and contains information about the consumer (name, cloud), the service (so can't reuse token to access to a different service), the service interface (so can't reuse token to access the service in a different format/protocol) and optionally an expiration date (forcing consumers to orchestrate periodically). The consumer receives the token(s) in the orchestration results which can be passed to the provider as a query parameter (at least in case of HTTP(S) services). We are using JWT (JSON Web Tokens) standard (see jwt.io) and JOSE (JSON Object Signing and Encryption) specification suite (https://datatracker.ietf.org/wg/jose/charter/) to implement our token generation. We are using the jose4j (https://bitbucket.org/b_c/jose4j/wiki/Home) implementation (which relies solely on the Java Cryptography Architecture API for cryptography) of JOSE in this class. First, we generate the JSON object that contains the information about the consumer, service, etc.(and some other JWT-related data), then sign it using the Authorization core system's private key (the selected signing algorithm is "RS512" (RSA/SHA512). After that, we encrypt the signed JSON using the provider's public key (which is stored in the DB as authenticationInfo). The encryption algorithm is "A256CBC-HS512". We also need a key management encryption algorithm as well (hence the previous algorithm uses a generated secret key that need to include in the JSON in an encrypted format), which is "RSA-OAEP-256". It seems difficult, but the jose4j did most of the work: we just have to select the algorithms, provide the necessary keys and payload, and call some high-level methods. + +9.4 Orchestrator Module + +The Orchestration core system is responsible for storing orchestration rules and performs store (using the previously mentioned rules) and dynamic orchestration. In both cases, the orchestrator tries to find suitable providers for a consumer. These providers can be local ones or (if a gatekeeper is installed in the cloud) from an other cloud. + +The application.properties of the Orchestrator contains some custom property which are not used by (all) other core systems. + +use_strict_service_intf_name_verifier: Interface names has to follow this format --, where security can be SECURE or INSECURE and protocol and format must be a sequence of letters, numbers and underscore. A regexp checker will verify that. If this setting is set to true then the PROTOCOL and FORMAT must come from a predefined set. Currently, only HTTP and HTTPS are acceptable as PROTOCOL and JSON and XML as FORMAT. +gatekeeper_is_present: a flag that tells the Orchestrator whether a Gatekeeper core system is installed in the cloud or not. If the value is false, the Orchestrator can only search providers in the local cloud. + +Let's see the contents of the module: +* eu.arrowhead.core.orchestrator.OrchestratorMain: the main class of the Orchestrator core system is the default implementation of the Spring Boot web server (see Spring Boot documentation). We using annotations to tell Spring this is a Spring Boot application (@SpringBootApplication) and where to search for Spring-managed classes (@ComponentScan), database entities (@EntityScan) and database repositories (@EnableJpaRepositories). And it enables Swagger UI (@EnableSwagger2 annotation) +* eu.arrowhead.core.orchestrator.OrchestratorApplicationInitListener: it overrides the customInit() method to load the Service Registry query URTs to the Arrowhead context object. It also overrides getRequiredCoreSystemServiceUris() to tell the URI crawler task to load the necessary URIs from the Service Registry: intra-cloud authorization rule checking, token generation, global service discovery (only if the Gatekeeper is installed) and inter-cloud negotiation (only if Gatekeeper is installed). This class also defines +some beans which we will use in different matchmaking situations (see later). +* eu.arrowhead.core.orchestrator.OrchestratorStoreController: it contains the Orchestrator web service endpoints related to storing and accessing orchestration rules. See Orchestration API documentation for details. +* eu.arrowhead.core.orchestrator.OrchestratorController: it contains the Orchestrator web service endpoints related orchestration process. See Orchestration API documentation for details. +* eu.arrowhead.core.orchestrator.database.service.OrchestratorStoreDBService: this class implements the higher level database-related methods that handle orchestrator rule creation, modification, deletion and reading. +* eu.arrowhead.core.orchestrator.matchmaking package: matchmaking is the name of the process when the Orchestrator core system has to select one element (provider, cloud) from multiple suitable entities. Because matchmaking is possible using different strategies, we define an interface for all matchmaking situations and provide one or more implementations for each interface. CloudMatchmakingAlgorithm interface is used when the orchestrator has to choose a cloud when multiple clouds have the providers that are suitable for the consumer. The DefaultCloudMatchmaker simply returns the first preferred cloud. If no preferred cloud for the consumer, it returns the first cloud in the list. The RandomWeightedCloudMatchmaker implementation chooses randomly from the clouds but clouds with higher number of suitable providers have higher chance. This strategy also try to select from the preferred clouds first. An other matchmaking interface is IntraCloudProviderMatchmakingAlgorithm which is used when the orchestrator has to select one result from local providers. The DefaultIntraCloudProviderMatchmaker selects the first (preferred) provider, while the RandomIntraCloudProviderMatchmaker chooses randomly, if no preferred is available. The third matchmaking interface is InterCloudProviderMatchmakingAlgorithm, which selects one from foreign providers. Currently, only the DefaultInterCloudProviderMatchmaker implements this interface and returns the first (preferred) provider from the list. +* eu.arrowhead.core.orchestrator.security.OSecurityConfig: it's an empty descendant of the DefaultSecurityConfig class. We use @EnableWebSecurity and @Configuration annotations to activate the security. +* eu.arrowhead.core.orchestrator.security.OrchestratorAccessControlFilter: it is a descendant class of the CoreSystemAccessControlFilter and it enforces authentication requirements of the Orchestrator web services. Only works in secured mode (see @ConditionalOnProperty annotation). Implemented rules: + + - web services are only accessible from the local cloud (inherited through the base class); + - management web services (/mgmt appears in the URI) are only accessible to the local system operator (sysop...arrowhead.eu); + - external service request (marked with the flag externalServiceRequest=true) is only allowed to the local gatekeeper; + - in case of other type of dynamic orchestration the requester system's name (in the input JSON) has to match the first part of the requester's common name (in the certificate); + +* eu.arrowhead.core.orchestrator.service.OrchestratorDriver: it contains support methods for calling web services of other core systems: query from Service Registry, intra-cloud rule check and token generation from Authorization and global service discovery and inter-cloud negotiation from Gatekeeper. +* eu.arrowhead.core.orchestrator.service.OrchestratorService: this class implements the various orchestration features by using web services of other core systems (via the OrchestratorDriver class). + + - externalServiceRequest() handles the dynamic orchestration request comes from a different cloud (via the foreign and the local Gatekeepers). The main difference between an external service request and a local request that the first one skips the authorization checks (because that is handled by the local Gatekeeper). This could be a potential security issue so be sure that this version of orchestration is only called from the local Gatekeeper (currently the security filter ensures that). The implementation is pretty straightforward: collecting suitable providers by using Service Registry query; removing non-preferred providers if necessary; converting the result to the expected format; generating tokens if necessary using Authorization's service. + - triggerInterCloud() handles the orchestration in other clouds. It basically calls the global service discovery (GSD) and inter-cloud negotiation (ICN) services of the local Gatekeeper. Please note that the GSD can return multiple clouds and the implementation selects one using the appropriate matchmaking algorithm. The ICN only contacts the selected cloud, but can return with multiple providers (from the same cloud). If the matchMaking flag is set, then an other matchmaker will select from the returned providers. + - dynamicOrchestration() handles the local dynamic orchestration requests (comes from actual consumers). This methods first tries to find suitable providers in the local cloud, but if it can't (and the cloud configuration and ochestration flags allow it), the search will expand to other clouds (calling the triggerInterCloud() previously mentioned). The steps of the implementations are the following: collecting suitable providers by using Service Registry query; removing providers that the consumer can't use because of authorization rules (by calling the appropriate web service of the Authorization core system); removing non-preferred providers if necessary; select one provider if necessary by using a matchmaker algorithm; converting the result to the expected format; generating tokens if necessary using Authorization's service. + - topPriorityEntriesOrchestrationProcess() handles the local store orchestration when only a consumer system id is provided. In that case we have to orchestrate all necessary (local) providers using top priority (1) rules. The steps are the following: obtain the appropriate rules; remove foreign provider-related rules, because this method only works with local providers; query the Service Registry for the actual provider data (and to remove the unavailable providers); query Authorization core system to check permissions; converting the result to the expected format; generating tokens if necessary using Authorization's service. + - orchestrationFromStore() handles the store orchestration when a service requirement is specified. It's using all rules related to the service, and returns the one that has the highest priority, is currently working and accessible. Please note that this method works with foreign providers too (if gatekeeper is available in the cloud). + +* eu.arrowhead.core.orchestrator.swagger.OSwaggerConfig: it is a descendant class of DefaultSwaggerConfig. It configures and activates Swagger UI. See Swagger Documentation for details. + +9.5 Gatekeeper module -Orch -GK GW EH -Chor + diff --git a/documentation/device_registry/ReleaseNotes-4.1.3-DeviceRegistry.odt b/documentation/device_registry/ReleaseNotes-4.1.3-DeviceRegistry.odt new file mode 100644 index 000000000..0b96c40ce Binary files /dev/null and b/documentation/device_registry/ReleaseNotes-4.1.3-DeviceRegistry.odt differ diff --git a/documentation/device_registry/ReleaseNotes-4.1.3-DeviceRegistry.pdf b/documentation/device_registry/ReleaseNotes-4.1.3-DeviceRegistry.pdf new file mode 100644 index 000000000..0c00865df Binary files /dev/null and b/documentation/device_registry/ReleaseNotes-4.1.3-DeviceRegistry.pdf differ diff --git a/documentation/gatekeeper/GatekeeperSetup.md b/documentation/gatekeeper/GatekeeperSetup.md index 3abce9451..f5c08b30d 100644 --- a/documentation/gatekeeper/GatekeeperSetup.md +++ b/documentation/gatekeeper/GatekeeperSetup.md @@ -93,11 +93,11 @@ After you have the necessary certificate and trust store you have to install the ``` -- In the lines above we assume that the certificate file named `relay1.p12`, the trust store file named `relay-truststore.p12` and all the passwords are `123456`. If this is not true, please adjust the settings accordingly. +- In the lines above we assume that the certificate file named `relay1.p12`, the trust store file named `relay1_truststore.p12` and all the passwords are `123456`. If this is not true, please adjust the settings accordingly. #### 1.2.3 Configuring transport connector diff --git a/documentation/images/images_docker_certificate_guide/step01.png b/documentation/images/images_docker_certificate_guide/step01.png new file mode 100644 index 000000000..ae74a487d Binary files /dev/null and b/documentation/images/images_docker_certificate_guide/step01.png differ diff --git a/documentation/images/images_docker_certificate_guide/step02.png b/documentation/images/images_docker_certificate_guide/step02.png new file mode 100644 index 000000000..ce54d97c9 Binary files /dev/null and b/documentation/images/images_docker_certificate_guide/step02.png differ diff --git a/documentation/images/images_docker_certificate_guide/step03.png b/documentation/images/images_docker_certificate_guide/step03.png new file mode 100644 index 000000000..ccbe6e6dd Binary files /dev/null and b/documentation/images/images_docker_certificate_guide/step03.png differ diff --git a/documentation/images/images_docker_certificate_guide/step04.png b/documentation/images/images_docker_certificate_guide/step04.png new file mode 100644 index 000000000..9483579f4 Binary files /dev/null and b/documentation/images/images_docker_certificate_guide/step04.png differ diff --git a/documentation/images/images_docker_certificate_guide/step05.png b/documentation/images/images_docker_certificate_guide/step05.png new file mode 100644 index 000000000..54f0943cc Binary files /dev/null and b/documentation/images/images_docker_certificate_guide/step05.png differ diff --git a/documentation/onboarding/ReleaseNotes-4.1.3-Onboarding.odt b/documentation/onboarding/ReleaseNotes-4.1.3-Onboarding.odt new file mode 100644 index 000000000..11d343003 Binary files /dev/null and b/documentation/onboarding/ReleaseNotes-4.1.3-Onboarding.odt differ diff --git a/documentation/onboarding/ReleaseNotes-4.1.3-Onboarding.pdf b/documentation/onboarding/ReleaseNotes-4.1.3-Onboarding.pdf new file mode 100644 index 000000000..a53683ba0 Binary files /dev/null and b/documentation/onboarding/ReleaseNotes-4.1.3-Onboarding.pdf differ diff --git a/documentation/onboarding/onboarding_controller.png b/documentation/onboarding/onboarding_controller.png new file mode 100644 index 000000000..580105833 Binary files /dev/null and b/documentation/onboarding/onboarding_controller.png differ diff --git a/documentation/qos_monitor/sdd/overview.png b/documentation/qos_monitor/sdd/overview.png new file mode 100644 index 000000000..2142cfac0 Binary files /dev/null and b/documentation/qos_monitor/sdd/overview.png differ diff --git a/documentation/qos_monitor/sdd/overview.uxf b/documentation/qos_monitor/sdd/overview.uxf new file mode 100644 index 000000000..f3ccb7f31 --- /dev/null +++ b/documentation/qos_monitor/sdd/overview.uxf @@ -0,0 +1,39 @@ +10UMLState620530190110Provider +fontsize=24 +bg=grayUMLState38030480110ARROWHEAD FW +fontsize=24 +bg=cyanRelation6201503050lt=-()10;10;10;30Relation6201303060lt=[]- +bg=blue10;10;10;40Relation7001303060lt=[]- +bg=red10;10;10;40Relation7901303070lt=[]- +bg=green10;10;10;50Relation7901403060lt=-()10;10;10;40Relation7001403060lt=-()10;10;10;40Relation340370180140lt=-( +bg=#ac3300 +fg=#ac330010;10;150;10;150;110Relation650370250140lt=-( +bg=#ac3300 +fg=#ac330010;10;220;10;220;110Relation4701303080lt=[]- +bg=#ac3300 + +10;10;10;60Relation4701804030lt=-()20;10;10;10Relation42040430180lt=-( +bg=green +fg=green380;120;410;120;410;10;10;10;10;150;40;150Relation270160290350lt=-( +bg=#ac3300 +fg=#ac3300210;10;270;10;270;220;20;220;20;320Relation480370210140lt=-( +bg=#ac3300 +fg=#ac330010;10;180;10;180;110Relation8604903060lt=-()10;40;10;10Relation8605203030lt=[]- +bg=gray10;10;10;10Relation2804903060lt=[]- +bg=gray +group=210;40;10;10Relation2804903040lt=-() +group=210;20;10;10UMLState220530190110Provider +fontsize=24 +bg=gray +group=2Relation6505203030lt=[]- +bg=gray10;10;10;10Relation6504903050lt=-()10;30;10;10UMLState420530190110Provider +fontsize=24 +bg=gray +group=3Relation4804903040lt=-() +group=310;20;10;10Relation4805003050lt=[]- +bg=gray +group=310;30;10;10UMLState820530190110Provider +fontsize=24 +bg=grayRelation47015017060lt=-( +bg=#ac3300 +fg=#ac330010;10;100;10;100;30;140;30 \ No newline at end of file diff --git a/documentation/qos_monitor/sdd/qos_monitor_sdd.md b/documentation/qos_monitor/sdd/qos_monitor_sdd.md new file mode 100644 index 000000000..46db24866 --- /dev/null +++ b/documentation/qos_monitor/sdd/qos_monitor_sdd.md @@ -0,0 +1,217 @@ + + +# QOS MONITOR + + + +## System Design Description Overview + +The purpose of QoS Monitor supporting core system is providing qos measurements to the QoS Manager. + +![#1589F0](https://placehold.it/15/1589F0/000000?text=+) `AH Service Registry` +![#f03c15](https://placehold.it/15/f03c15/000000?text=+) `AH Authorization` +![#c5f015](https://placehold.it/15/c5f015/000000?text=+) `AH Orchestrator / QoS Manager` +![#ffcc44](https://placehold.it/15/a33c00/000000?text=+) `AH QoS Monitor` +![Alt text](/documentation/qos_monitor/sdd/overview.png) + + + +## System Design Overview +![Alt text](/documentation/qos_monitor/sysd/qos_monitor_sys_d.jpg) + + + +## Provided services + +The QoS Monitor provides the following services: +* [Echo](#qos_monitor_endpoints_get_echo) +* [Ping Measurement](#qos_monitor_endpoints_ping_measurement_by_system_id) + + + +## Consumed services + +The QoS Monitor consumes the following service: +* QueryAll private service from the ServiceRegistry core system + + + +## Use cases + +The QoS Monitor has the following use cases: +* [Ping Measurement](documentation/qos_monitor/use_cases/QoSMonitor_use_case_1.md) +![Alt text](/documentation/qos_monitor/use_cases/PingMeasurement.png) +* [Reset Counter](documentation/qos_monitor/use_cases/QoSMonitor_use_case_2.md) +![Alt text](/documentation/qos_monitor/use_cases/Reset_Counter.png) +* [Get Measurements](documentation/qos_monitor/use_cases/QoSMonitor_use_case_3.md) +![Alt text](/documentation/qos_monitor/use_cases/GetMeaurements.png) + + + +## Endpoints + + + +### Client endpoint description
+ +| Function | URL subpath | Method | Input | Output | +| -------- | ----------- | ------ | ----- | ------ | +| [Echo](#qos_monitor_endpoints_get_echo) | /echo | GET | - | OK | + +
+ +### Management endpoint description
+ +| Function | URL subpath | Method | Input | Output | +| -------- | ----------- | ------ | ----- | ------ | +| [Get ping measurements mgmt](#qos_monitor_endpoints_get_ping_measurements_list) | /mgmt/ping/measurements | GET | direction && item_per_page && page && sort_field | [PingMeasurement list response](#qos_monitor_ping_measurement_list_response) | +| [Get ping measurements by system id mgmt](#qos_monitor_mgmt_endpoints_get_ping_measurement_by_system_id) | /mgmt/ping/measurements/{id} | GET | id | [Ping Measurment response](#qos_monitor_ping_measurement_response) | + +
+ +### Private endpoint description
+ +| Function | URL subpath | Method | Input | Output | +| -------- | ----------- | ------ | ----- | ------ | +| [Get ping measurements by system id](#qos_monitor_endpoints_get_ping_measurement_by_system_id) | /ping/measurements/{id} | GET | id | [Ping Measurment response](#qos_monitor_ping_measurement_response) | + +
+ +### Echo +``` +GET /qos_monitor/echo +``` + +Returns a "Got it" message with the purpose of testing the core service availability. + +### Get ping measurements mgmt + +``` +GET /mgmt/ping/measurements +``` + +__Get subscriptions query parameters__ the input : + +`https://qos_monitor_ip:qos_monitor_port/qos_monitor/mgmt/ping/measurements?dirction=`ASC`&item_per_page=`100`&page=`0`&sort_field=`id + +| __Get ping measurements mgmt__ query parameters | +| ------------------------------------------------------- | + +| Parameter | Description | Necessity | Format/Limitations | +| --------- | ----------- | --------- | ----------- | +| `direction` | Direction of sorting. | optional | valid values: "ASC", "DESC" - default: "ASC"| +| `item_per_page` | Maximum number of items returned. | optional (mandatory, if page is defined)| integer | +| `page` | Zero based page index. | optional (mandatory, if item_per_page is defined)| integer | +| `sort_field` | The field to sort the results by. | optional | valid values: "id", "updatedAt", "createdAt" - default: "id" | + + + +__PingMeasurement list response__ the output : + +```json +{ + "data": [ + { + "id": 1, + "measurement": { + "id": 1, + "system": { + "id": 5, + "systemName": "testsystem", + "address": "testsystem.ai", + "port": 12345, + "createdAt": "2020-02-04 09:38:56", + "updatedAt": "2020-02-04 09:38:56" + }, + "measurementType": "PING", + "lastMeasurementAt": "2020-02-14T10:48:10+01:00", + "createdAt": "2020-02-04T10:42:04+01:00", + "updatedAt": "2020-02-14T10:48:47+01:00" + }, + "available": true, + "lastAccessAt": "2020-02-14T10:48:10+01:00", + "minResponseTime": 15, + "maxResponseTime": 26, + "meanResponseTimeWithTimeout": 18, + "meanResponseTimeWithoutTimeout": 18, + "jitterWithTimeout": 3, + "jitterWithoutTimeout": 3, + "lostPerMeasurementPercent": 0, + "sent": 12075, + "received": 12070, + "countStartedAt": "2020-02-07T00:00:00+01:00", + "sentAll": 63175, + "receivedAll": 56721, + "createdAt": "2020-02-14T10:48:47+01:00", + "updatedAt": "2020-02-14T10:48:47+01:00" + } + ], + "count": 1 +} +``` + + + +### Get ping measurements by system id mgmt + +``` +GET /mgmt/ping/measurements/{id} +``` + +__Get ping measurements by system id mgmt path parameter__ the input : + +`https://qos_monitor_ip:qos_monitor_port/qos_monitor/mgmt/ping/measurements/`1 + +| __Get ping measurement by system id__ path parameter | +| ------------------------------------------------------- | + +| Parameter | Description | Necessity | Format/Limitations | +| --------- | ----------- | --------- | ----------- | +| `id` | Id of measured system | mandatory | integer | + + + +__Ping Measurment response by system id__ the output : + +```json + { + "id": 1, + "measurement": { + "id": 1, + "system": { + "id": 5, + "systemName": "testsystem", + "address": "testsystem.ai", + "port": 12345, + "createdAt": "2020-02-04 09:38:56", + "updatedAt": "2020-02-04 09:38:56" + }, + "measurementType": "PING", + "lastMeasurementAt": "2020-02-14T10:48:10+01:00", + "createdAt": "2020-02-04T10:42:04+01:00", + "updatedAt": "2020-02-14T10:48:47+01:00" + }, + "available": true, + "lastAccessAt": "2020-02-14T10:48:10+01:00", + "minResponseTime": 15, + "maxResponseTime": 26, + "meanResponseTimeWithTimeout": 18, + "meanResponseTimeWithoutTimeout": 18, + "jitterWithTimeout": 3, + "jitterWithoutTimeout": 3, + "lostPerMeasurementPercent": 0, + "sent": 12075, + "received": 12070, + "countStartedAt": "2020-02-07T00:00:00+01:00", + "sentAll": 63175, + "receivedAll": 56721, + "createdAt": "2020-02-14T10:48:47+01:00", + "updatedAt": "2020-02-14T10:48:47+01:00" + } +``` + + + +### Get ping measurements by system id + +For private endpoints no detailed description available. \ No newline at end of file diff --git a/documentation/qos_monitor/sysd/qos_monitor_sys_d.jpg b/documentation/qos_monitor/sysd/qos_monitor_sys_d.jpg new file mode 100644 index 000000000..e4756d406 Binary files /dev/null and b/documentation/qos_monitor/sysd/qos_monitor_sys_d.jpg differ diff --git a/documentation/qos_monitor/sysd/qos_monitor_sys_d.ucls b/documentation/qos_monitor/sysd/qos_monitor_sys_d.ucls new file mode 100644 index 000000000..dc37f06fb --- /dev/null +++ b/documentation/qos_monitor/sysd/qos_monitor_sys_d.ucls @@ -0,0 +1,150 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/qos_monitor/use_cases/GetMeaurements.png b/documentation/qos_monitor/use_cases/GetMeaurements.png new file mode 100644 index 000000000..f5135783f Binary files /dev/null and b/documentation/qos_monitor/use_cases/GetMeaurements.png differ diff --git a/documentation/qos_monitor/use_cases/GetMeaurements.uxf b/documentation/qos_monitor/use_cases/GetMeaurements.uxf new file mode 100644 index 000000000..abea3fd0c --- /dev/null +++ b/documentation/qos_monitor/use_cases/GetMeaurements.uxf @@ -0,0 +1,42 @@ +10SERVICE REGISTRY DTOUMLSpecialState330402020type=initialRelation330503080lt=<-10;60;10;10Relation34056030110lt=<-10;90;10;10UMLState14020400610QoS Monitor Controller +valign=topUMLState27047017040call getPingMeasurements +bg=yellow +type=senderRelation350250430180lt=<- + +410;10;240;10;240;160;10;160UMLState640150420350QoS DB Service +valign=topUMLState76022022040getPingMeasurements called +bg=yellow +type=receiverUMLState79040020040getPingMeasurements + answer produced +bg=yellow +type=senderUMLSpecialState8401802020type=initialRelation8401903050lt=<-10;30;10;10Relation8402503080lt=<-10;60;10;10Relation430410700160lt=<- +10;140;680;140;680;10;560;10UMLState25011017050received +getPingMeasurements +request +bg=yellow +type=receiverUMLState78031019040getAllMeasurement +bg=blueRelation3303503060lt=<- +10;40;10;10UMLSpecialState3206506060type=final +bg=green +UMLState26032019040validate +request parameters +bg=blueRelation8403403080lt=<-10;60;10;10Relation3301503050lt=<-10;30;10;10UMLSpecialState3203904040type=decision +bg=orange +Relation33042018070lt=<- +request parameters are valid10;50;10;10UMLState27053017040getPingMeasurements +returned +bg=yellow +type=receiverRelation12039022040lt=<- +request parameters are invalid10;20;200;20UMLSpecialState3202404040type=decision +bg=orange +Relation33027017070lt=<- +request sender is the +Orchestrator Core System10;50;10;10Relation12024022050lt=<- +request sender is not the +Orchestrator Core System10;20;200;20UMLState25018019040validate +request parameters +bg=blueRelation3302103050lt=<-10;30;10;10UMLSpecialState703806060type=final +bg=red +UMLSpecialState702306060type=final +bg=red + \ No newline at end of file diff --git a/documentation/qos_monitor/use_cases/PingMeasurement.png b/documentation/qos_monitor/use_cases/PingMeasurement.png new file mode 100644 index 000000000..710cdda31 Binary files /dev/null and b/documentation/qos_monitor/use_cases/PingMeasurement.png differ diff --git a/documentation/qos_monitor/use_cases/PingMeasurement.uxf b/documentation/qos_monitor/use_cases/PingMeasurement.uxf new file mode 100644 index 000000000..3db702ce0 --- /dev/null +++ b/documentation/qos_monitor/use_cases/PingMeasurement.uxf @@ -0,0 +1,53 @@ +10SERVICE REGISTRY DTOUMLSpecialState330402020type=initialRelation3305030100lt=<-10;80;10;10UMLSpecialState3201604040bg=orange +type=decisionRelation35070170140lt=<- +m2=[Ping Task Still running]30;60;30;10;100;10;100;110;10;110UMLState270240190200getSystemsToMeasure +valign=top +bg=blue +bg=blueUMLSpecialState3205404040bg=orange +type=decisionRelation3304303080lt=<-10;60;10;10UMLState18010400850Ping Task +valign=topRelation3301203060lt=<-10;40;10;10UMLState28029017040call queryAll +bg=yellow +type=senderRelation440120350210lt=<. + +330;10;160;10;160;190;10;190Relation24017010030lt=<-80;10;10;10UMLSyncBarHorizontal29012010020{joinSpec= +date is on or +after July 1st +and the exam +is passed}UMLTimer19016012090Ping Task +Config Sequence +bg=blackUMLState65010420330ServiceRegistry +valign=topUMLState7709019040queryAll called +bg=yellow +type=receiverUMLState77026019040queryAll answer produced +bg=yellow +type=senderUMLSpecialState850502020type=initialRelation850603050lt=<-10;30;10;10Relation8501203070lt=<-10;50;10;10Relation420270750120lt=<. +10;100;10;80;730;80;730;10;540;10UMLState28037017040queryAll returned +bg=yellow +type=receiverRelation8502003080lt=<-10;60;10;10UMLState77017019040getServiceRegistryEntries +bg=blueRelation33019015070lt=<- +m2=[Ping Task not running]10;50;10;10UMLSyncBarHorizontal2704809020{joinSpec= +date is on or +after July 1st +and the exam +is passed}Relation3304803080lt=<-10;60;10;10Relation35054011050lt=<- +has more +system90;20;10;20UMLState44054010040ping system +bg=blueRelation33057070120lt=<- +has +no more +system10;100;10;10UMLSpecialState3306702020type=finalUMLState41061015040calculate measurement +bg=blueRelation4805703060lt=<-10;40;10;10UMLState40068016050save +measurements and logs +bg=yellow +type=senderUMLState40074016050measurements and logs +saved +bg=yellow +type=receiverRelation4606403060lt=<-10;40;10;10Relation220450260390lt=<-80;40;80;10;10;10;10;370;240;370;240;340UMLState650480420370QoS DB Service +valign=topUMLSpecialState8405202020type=initialUMLState77058016050measurements and logs +saved +bg=yellow +type=receiverUMLState78075016050save +measurements and logs +bg=yellow +type=senderUMLState78067015040save to DB +bg=blueRelation550620240110lt=<-220;10;60;10;60;90;10;90Relation550760620130lt=<-10;10;80;10;80;110;600;110;600;20;390;20Relation8406203070lt=<-10;50;10;10Relation8407003070lt=<-10;50;10;10 \ No newline at end of file diff --git a/documentation/qos_monitor/use_cases/QoSMonitor_use_case_1.md b/documentation/qos_monitor/use_cases/QoSMonitor_use_case_1.md new file mode 100644 index 000000000..1538505e6 --- /dev/null +++ b/documentation/qos_monitor/use_cases/QoSMonitor_use_case_1.md @@ -0,0 +1,10 @@ + + +## Use case: Ping Measurement +| Name | Description | +| ---- | --------- | +| ID | Ping Measurement | +| Brief Description | QosMonitors Ping Task process is tasked to measure the ping related values of all the availble systems | +| Primary Actors | QosMonitor - Ping Task process, QosMonitor - DB service, Service Registry | +| Preconditions | -  Service Registry has to be availble. +| Main Flow | - The Ping Task Configuration send a start signal to PingTask.
- If the PingTask is still working on the last task, it skips the start signal.
- If the PingTask is not working it starts working.
- PingTask call ServiceRegistry's for the list of registered systems.
- When list returned PingTask check if there are system on the list.
- If not, PingTask finish working.
- If there are systems, PingTask start:
-- Ping the system.
-- Calculate measurement results.
-- Logs results to DB.
-- Check for next system to measure. diff --git a/documentation/qos_monitor/use_cases/QoSMonitor_use_case_2.md b/documentation/qos_monitor/use_cases/QoSMonitor_use_case_2.md new file mode 100644 index 000000000..b1f88f689 --- /dev/null +++ b/documentation/qos_monitor/use_cases/QoSMonitor_use_case_2.md @@ -0,0 +1,10 @@ +
+ +## Use case: Reset Counter + +| Name | Description | +| ---- | --------- | +| ID | Reset Counter | +| Brief Description | QosMonitors Reset Counter Task process is tasked to reset the ping mesasurements sent, received and count-started-at fields | +| Primary Actors | QosMonitor - Reset Counter Task process, QosMonitor - DB service | +| Main Flow | - The Reset Counter Task Configuration send a start signal to PingTask.
- If the Reset Counter Task is still working on the last task, it skips the start signal.
- If the Reset Counter Task is not working it starts working.
- Reset Counter Task call QoS DB Service's to update ping measurments.
- QoS DB Service retrieve all ping measurement.
- QoS DB Service reset all ping mesasurements sent, received fields to 0 and reset count-started-at field to current date.
- Qos DB Service return ok to Reset Counter Task.
- Reset Counter Task stops working. diff --git a/documentation/qos_monitor/use_cases/QoSMonitor_use_case_3.md b/documentation/qos_monitor/use_cases/QoSMonitor_use_case_3.md new file mode 100644 index 000000000..92973d3da --- /dev/null +++ b/documentation/qos_monitor/use_cases/QoSMonitor_use_case_3.md @@ -0,0 +1,10 @@ +
+ +## Use case: Get Measurements + +| Name | Description | +| ---- | --------- | +| ID | Get Measurements| +| Brief Description | QosMonitors is tasked to retrieve ping measurements | +| Primary Actors | Orchestrator - QosManager, QosMonitor - Controller, QosMonitor - DB service | +| Main Flow | - QosManager sends a getPingMeasurements request to QoS Monitor.
- QoS Monitor checks if the request came from the Orchestrator.
- If not, QoS Monitor returns Authorization Exception.
- If the request came from the Orchestrator, QoSMonitor Controller validate the request parameter.
- If the parameter is not valid, the Controller returns BadRequest Exception.
- If the parameter is valid, the Controller call QoS DB Service for the ping measurement specified by the request parameter.
- Qos DB Service returns the ping measurement to the Controller.
- The Controller returns the ping measurement to the QoS Manager. diff --git a/documentation/qos_monitor/use_cases/Reset_Counter.png b/documentation/qos_monitor/use_cases/Reset_Counter.png new file mode 100644 index 000000000..2e6d8efad Binary files /dev/null and b/documentation/qos_monitor/use_cases/Reset_Counter.png differ diff --git a/documentation/qos_monitor/use_cases/Reset_Counter.uxf b/documentation/qos_monitor/use_cases/Reset_Counter.uxf new file mode 100644 index 000000000..ab0d6948a --- /dev/null +++ b/documentation/qos_monitor/use_cases/Reset_Counter.uxf @@ -0,0 +1,44 @@ +10SERVICE REGISTRY DTOUMLSpecialState330402020type=initialRelation3305030100lt=<-10;80;10;10UMLSpecialState3201604040bg=orange +type=decisionRelation35070220140lt=<- +m2=[Reset Counter Task Still running]30;60;30;10;100;10;100;110;10;110UMLState270250190200restrart counter +valign=top +bg=blue +bg=blueRelation3304403070lt=<-10;50;10;10UMLState18010400530Reset Counter Task +valign=topRelation3301203060lt=<-10;40;10;10UMLState28029017040call update measurement +bg=yellow +type=senderRelation440120350210lt=<- + +330;10;160;10;160;190;10;190Relation24017010030lt=<-80;10;10;10UMLSyncBarHorizontal29012010020{joinSpec= +date is on or +after July 1st +and the exam +is passed}UMLTimer19016012090Reset Counter Task +Config Sequence +bg=blackUMLState65020420480QoS DB Service +valign=topUMLState7709019040update measurement called +bg=yellow +type=receiverUMLState76044019040queryAll answer produced +bg=yellow +type=senderUMLSpecialState850502020type=initialRelation850603050lt=<-10;30;10;10Relation8001203070lt=<-10;50;10;10Relation420340710200lt=<- +10;30;10;10;210;10;210;180;690;180;690;120;530;120UMLState28037017040update measurement +returned +bg=yellow +type=receiverRelation8002003060lt=<-10;40;10;10UMLState72017019040getAllMeasurement +bg=blueRelation33019021080lt=<- +m2=[Reset Counter Task not running]10;60;10;10UMLSpecialState3304902020type=finalUMLSyncBarHorizontal77023010020{joinSpec= +date is on or +after July 1st +and the exam +is passed}UMLSpecialState7602704040bg=orange +type=decisionUMLState91027010040update +count started at +bg=blueRelation7702303060lt=<-10;40;10;10Relation79027014060lt=<- +has more +measurements +120;20;10;20UMLState91033010040update +sent +bg=blueUMLState91039010040update received +bg=blueRelation9503003050lt=<-10;30;10;10Relation9503603050lt=<-10;30;10;10Relation840210200220lt=<-10;30;10;10;180;10;180;200;170;200Relation770300110160lt=<- +has no more +measurements +10;140;10;10 \ No newline at end of file diff --git a/documentation/system_registry/ReleaseNotes-4.1.3-SystemRegistry.odt b/documentation/system_registry/ReleaseNotes-4.1.3-SystemRegistry.odt new file mode 100644 index 000000000..a9425d797 Binary files /dev/null and b/documentation/system_registry/ReleaseNotes-4.1.3-SystemRegistry.odt differ diff --git a/documentation/system_registry/ReleaseNotes-4.1.3-SystemRegistry.pdf b/documentation/system_registry/ReleaseNotes-4.1.3-SystemRegistry.pdf new file mode 100644 index 000000000..758f0179a Binary files /dev/null and b/documentation/system_registry/ReleaseNotes-4.1.3-SystemRegistry.pdf differ diff --git a/eventhandler/.classpath b/eventhandler/.classpath index 01997bb0d..e210343c4 100644 --- a/eventhandler/.classpath +++ b/eventhandler/.classpath @@ -45,5 +45,19 @@ + + + + + + + + + + + + + + diff --git a/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/EventHandlerController.java b/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/EventHandlerController.java index f02d43c18..9cc679155 100644 --- a/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/EventHandlerController.java +++ b/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/EventHandlerController.java @@ -1,418 +1,419 @@ -package eu.arrowhead.core.eventhandler; - -import java.time.ZonedDateTime; -import java.time.format.DateTimeParseException; - -import org.apache.http.HttpStatus; -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpHeaders; -import org.springframework.http.MediaType; -import org.springframework.web.bind.annotation.CrossOrigin; -import org.springframework.web.bind.annotation.DeleteMapping; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.PostMapping; -import org.springframework.web.bind.annotation.PutMapping; -import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import org.springframework.web.bind.annotation.ResponseBody; -import org.springframework.web.bind.annotation.RestController; - -import eu.arrowhead.common.CommonConstants; -import eu.arrowhead.common.CoreCommonConstants; -import eu.arrowhead.common.CoreDefaults; -import eu.arrowhead.common.CoreUtilities; -import eu.arrowhead.common.CoreUtilities.ValidatedPageParams; -import eu.arrowhead.common.Defaults; -import eu.arrowhead.common.Utilities; -import eu.arrowhead.common.dto.shared.EventPublishRequestDTO; -import eu.arrowhead.common.dto.shared.SubscriptionListResponseDTO; -import eu.arrowhead.common.dto.shared.SubscriptionRequestDTO; -import eu.arrowhead.common.dto.shared.SubscriptionResponseDTO; -import eu.arrowhead.common.dto.shared.SystemRequestDTO; -import eu.arrowhead.common.exception.BadPayloadException; -import eu.arrowhead.core.eventhandler.database.service.EventHandlerDBService; -import eu.arrowhead.core.eventhandler.service.EventHandlerService; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; -import io.swagger.annotations.ApiResponse; -import io.swagger.annotations.ApiResponses; - -@Api(tags = { CoreCommonConstants.SWAGGER_TAG_ALL }) -@CrossOrigin(maxAge = Defaults.CORS_MAX_AGE, allowCredentials = Defaults.CORS_ALLOW_CREDENTIALS, - allowedHeaders = { HttpHeaders.ORIGIN, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT, HttpHeaders.AUTHORIZATION } -) -@RestController -@RequestMapping(CommonConstants.EVENT_HANDLER_URI) -public class EventHandlerController { - - //================================================================================================= - // members - - private static final String PATH_VARIABLE_ID = "id"; - - private static final String EVENT_HANDLER_MGMT_URI = CoreCommonConstants.MGMT_URI + "/subscriptions"; - private static final String EVENTHANLER_BY_ID_MGMT_URI = EVENT_HANDLER_MGMT_URI + "/{" + PATH_VARIABLE_ID + "}"; - - private static final String GET_EVENT_HANDLER_MGMT_DESCRIPTION = "Return requested Subscription entries by the given parameters"; - private static final String GET_EVENT_HANDLER_MGMT_HTTP_200_MESSAGE = "Subscription entries returned"; - private static final String GET_EVENT_HANDLER_MGMT_HTTP_400_MESSAGE = "Could not retrieve Subscription entries"; - - private static final String GET_EVENT_HANDLER_BY_ID_MGMT_DESCRIPTION = "Return requested Subscription entry by the given id"; - private static final String GET_EVENT_HANDLER_BY_ID_MGMT_HTTP_200_MESSAGE = "Subscription entriy returned"; - private static final String GET_EVENT_HANDLER_BY_ID_MGMT_HTTP_400_MESSAGE = "Could not retrieve Subscription entry"; - - private static final String DELETE_EVENT_HANDLER_MGMT_DESCRIPTION = "Delete requested Subscription entry by the given id"; - private static final String DELETE_EVENT_HANDLER_MGMT_HTTP_200_MESSAGE = "Subscription entriy deleted"; - private static final String DELETE_EVENT_HANDLER_MGMT_HTTP_400_MESSAGE = "Could not delete Subscription entry"; - - private static final String PUT_EVENT_HANDLER_MGMT_DESCRIPTION = "Update requested Subscription entry by the given id and parameters"; - private static final String PUT_EVENT_HANDLER_MGMT_HTTP_200_MESSAGE = "Updated Subscription entry returned"; - private static final String PUT_EVENT_HANDLER_MGMT_HTTP_400_MESSAGE = "Could not update Subscription entry"; - - private static final String POST_EVENT_HANDLER_SUBSCRIPTION_DESCRIPTION = "Subscription to the events specified in requested Subscription "; - private static final String POST_EVENT_HANDLER_SUBSCRIPTION_HTTP_200_MESSAGE = "Successful subscription."; - private static final String POST_EVENT_HANDLER_SUBSCRIPTION_HTTP_400_MESSAGE = "Unsuccessful subscription."; - - private static final String DELETE_EVENT_HANDLER_SUBSCRIPTION_DESCRIPTION = "Unsubscription from the events specified in requested Subscription "; - private static final String DELETE_EVENT_HANDLER_SUBSCRIPTION_HTTP_200_MESSAGE = "Successful unsubscription."; - private static final String DELETE_EVENT_HANDLER_SUBSCRIPTION_HTTP_400_MESSAGE = "Unsuccessful unsubscription."; - - private static final String POST_EVENT_HANDLER_PUBLISH_DESCRIPTION = "Publish event"; - private static final String POST_EVENT_HANDLER_PUBLISH_HTTP_200_MESSAGE = "Publish event success"; - private static final String POST_EVENT_HANDLER_PUBLISH_HTTP_400_MESSAGE = "Publish event not success"; - - private static final String POST_EVENT_HANDLER_PUBLISH_AUTH_UPDATE_DESCRIPTION = "Publish authorization change event "; - private static final String POST_EVENT_HANDLER_PUBLISH_AUTH_UPDATE_HTTP_200_MESSAGE = "Publish authorization change event success"; - private static final String POST_EVENT_HANDLER_PUBLISH_AUTH_UPDATE_HTTP_400_MESSAGE = "Publish authorization change event not success"; - - private static final String NULL_PARAMETER_ERROR_MESSAGE = " is null."; - private static final String NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE = " is null or blank."; - private static final String ID_NOT_VALID_ERROR_MESSAGE = " Id must be greater than 0. "; - private static final String WRONG_FORMAT_ERROR_MESSAGE = " is in wrong format. "; - private static final String IS_AFTER_TOLERATED_DIFF_ERROR_MESSAGE = " is further in the future than the tolerated time difference"; - private static final String IS_BEFORE_TOLERATED_DIFF_ERROR_MESSAGE = " is further in the past than the tolerated time difference"; - - @Value(CoreCommonConstants.$TIME_STAMP_TOLERANCE_SECONDS_WD) - private long timeStampTolerance; - - private final Logger logger = LogManager.getLogger(EventHandlerController.class); - - @Autowired - EventHandlerService eventHandlerService; - - @Autowired - EventHandlerDBService eventHandlerDBService; - - //================================================================================================= - // methods - - //------------------------------------------------------------------------------------------------- - @ApiOperation(value = "Return an echo message with the purpose of testing the core service availability", response = String.class, tags = { CoreCommonConstants.SWAGGER_TAG_CLIENT }) - @ApiResponses (value = { - @ApiResponse(code = HttpStatus.SC_OK, message = CoreCommonConstants.SWAGGER_HTTP_200_MESSAGE), - @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), - @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) - }) - @GetMapping(path = CommonConstants.ECHO_URI) - public String echoService() { - return "Got it!"; - } - - //------------------------------------------------------------------------------------------------- - @ApiOperation(value = GET_EVENT_HANDLER_MGMT_DESCRIPTION, response = SubscriptionListResponseDTO.class, tags = { CoreCommonConstants.SWAGGER_TAG_MGMT }) - @ApiResponses(value = { - @ApiResponse(code = HttpStatus.SC_OK, message = GET_EVENT_HANDLER_MGMT_HTTP_200_MESSAGE), - @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_EVENT_HANDLER_MGMT_HTTP_400_MESSAGE), - @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), - @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) - }) - @GetMapping(path = EVENT_HANDLER_MGMT_URI, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody public SubscriptionListResponseDTO getSubscriptions( - @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_PAGE, required = false) final Integer page, - @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_ITEM_PER_PAGE, required = false) final Integer size, - @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_DIRECTION, defaultValue = CoreDefaults.DEFAULT_REQUEST_PARAM_DIRECTION_VALUE) final String direction, - @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_SORT_FIELD, defaultValue = CommonConstants.COMMON_FIELD_NAME_ID) final String sortField) { - logger.debug("New getSubscriptions get request recieved with page: {} and item_per page: {}", page, size); - - final ValidatedPageParams validParameters = CoreUtilities.validatePageParameters(page, size, direction, CommonConstants.EVENT_HANDLER_URI + EVENT_HANDLER_MGMT_URI); - final SubscriptionListResponseDTO subscriptionsResponse = eventHandlerDBService.getSubscriptionsResponse(validParameters.getValidatedPage(), validParameters.getValidatedSize(), - validParameters.getValidatedDirecion(), sortField); - - logger.debug("Subscriptions with page: {} and item_per page: {} retrieved successfully", page, size); - return subscriptionsResponse; - } - - //------------------------------------------------------------------------------------------------- - @ApiOperation(value = GET_EVENT_HANDLER_BY_ID_MGMT_DESCRIPTION, response = SubscriptionResponseDTO.class, tags = { CoreCommonConstants.SWAGGER_TAG_MGMT }) - @ApiResponses(value = { - @ApiResponse(code = HttpStatus.SC_OK, message = GET_EVENT_HANDLER_BY_ID_MGMT_HTTP_200_MESSAGE), - @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_EVENT_HANDLER_BY_ID_MGMT_HTTP_400_MESSAGE), - @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), - @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) - }) - @GetMapping(path = EVENTHANLER_BY_ID_MGMT_URI, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody public SubscriptionResponseDTO getSubscriptionById(@PathVariable(value = PATH_VARIABLE_ID) final long id) { - logger.debug("New getSubscriptionById get request recieved with id: {}", id); - - final String origin = CommonConstants.EVENT_HANDLER_URI + EVENTHANLER_BY_ID_MGMT_URI; - if (id < 1) { - throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - final SubscriptionResponseDTO subscriptionResponse = eventHandlerDBService.getSubscriptionByIdResponse(id); - - logger.debug("Subscription entry with id: {} successfully retrieved", id); - return subscriptionResponse; - } - - //------------------------------------------------------------------------------------------------- - @ApiOperation(value = DELETE_EVENT_HANDLER_MGMT_DESCRIPTION, tags = { CoreCommonConstants.SWAGGER_TAG_MGMT }) - @ApiResponses(value = { - @ApiResponse(code = HttpStatus.SC_OK, message = DELETE_EVENT_HANDLER_MGMT_HTTP_200_MESSAGE), - @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DELETE_EVENT_HANDLER_MGMT_HTTP_400_MESSAGE), - @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), - @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) - }) - @DeleteMapping(path = EVENTHANLER_BY_ID_MGMT_URI, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody public void deleteSubscription(@PathVariable(value = PATH_VARIABLE_ID) final long id) { - logger.debug("New deleteSubscription delete request recieved with id: {}", id); - - final String origin = CommonConstants.EVENT_HANDLER_URI + EVENTHANLER_BY_ID_MGMT_URI; - if (id < 1) { - throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - eventHandlerDBService.deleteSubscriptionResponse(id); - - logger.debug("Subscription entry with id: {} successfully deleted", id); - } - - //------------------------------------------------------------------------------------------------- - @ApiOperation(value = PUT_EVENT_HANDLER_MGMT_DESCRIPTION, response = SubscriptionResponseDTO.class, tags = { CoreCommonConstants.SWAGGER_TAG_MGMT }) - @ApiResponses(value = { - @ApiResponse(code = HttpStatus.SC_OK, message = PUT_EVENT_HANDLER_MGMT_HTTP_200_MESSAGE), - @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = PUT_EVENT_HANDLER_MGMT_HTTP_400_MESSAGE), - @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), - @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) - }) - @PutMapping(path = EVENTHANLER_BY_ID_MGMT_URI, produces = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody public SubscriptionResponseDTO updateSubscription(@PathVariable(value = PATH_VARIABLE_ID) final long id, @RequestBody final SubscriptionRequestDTO request) { - logger.debug("New updateSubscription put request recieved with id: {}", id); - - final String origin = CommonConstants.EVENT_HANDLER_URI + EVENTHANLER_BY_ID_MGMT_URI; - if (id < 1) { - throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - checkSubscriptionRequestDTO(request, origin); - final SubscriptionResponseDTO response = eventHandlerService.updateSubscriptionResponse(id, request); - - logger.debug("Subscription entry with id: {} successfully updated", id); - return response; - } - - //------------------------------------------------------------------------------------------------- - @ApiOperation(value = POST_EVENT_HANDLER_SUBSCRIPTION_DESCRIPTION, tags = { CoreCommonConstants.SWAGGER_TAG_CLIENT }) - @ApiResponses(value = { - @ApiResponse(code = HttpStatus.SC_OK, message = POST_EVENT_HANDLER_SUBSCRIPTION_HTTP_200_MESSAGE), - @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = POST_EVENT_HANDLER_SUBSCRIPTION_HTTP_400_MESSAGE), - @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), - @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) - }) - @PostMapping(path = CommonConstants.OP_EVENT_HANDLER_SUBSCRIBE, consumes = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody public void subscribe(@RequestBody final SubscriptionRequestDTO request) { - logger.debug("subscription started ..."); - - final String origin = CommonConstants.EVENT_HANDLER_URI + CommonConstants.OP_EVENT_HANDLER_SUBSCRIBE; - checkSubscriptionRequestDTO(request, origin); - - eventHandlerService.subscribe(request); - } - - //------------------------------------------------------------------------------------------------- - @ApiOperation(value = DELETE_EVENT_HANDLER_SUBSCRIPTION_DESCRIPTION, tags = { CoreCommonConstants.SWAGGER_TAG_CLIENT }) - @ApiResponses(value = { - @ApiResponse(code = HttpStatus.SC_OK, message = DELETE_EVENT_HANDLER_SUBSCRIPTION_HTTP_200_MESSAGE), - @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DELETE_EVENT_HANDLER_SUBSCRIPTION_HTTP_400_MESSAGE), - @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), - @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) - }) - @DeleteMapping(path = CommonConstants.OP_EVENT_HANDLER_UNSUBSCRIBE) - @ResponseBody public void unsubscribe( - @RequestParam(CommonConstants.OP_EVENT_HANDLER_UNSUBSCRIBE_REQUEST_PARAM_EVENT_TYPE) final String eventType, - @RequestParam(CommonConstants.OP_EVENT_HANDLER_UNSUBSCRIBE_REQUEST_PARAM_SUBSCRIBER_SYSTEM_NAME) final String subscriberName, - @RequestParam(CommonConstants.OP_EVENT_HANDLER_UNSUBSCRIBE_REQUEST_PARAM_SUBSCRIBER_ADDRESS) final String subscriberAddress, - @RequestParam(CommonConstants.OP_EVENT_HANDLER_UNSUBSCRIBE_REQUEST_PARAM_SUBSCRIBER_PORT) final int subscriberPort) { - logger.debug("unSubscription started ..."); - - final String origin = CommonConstants.EVENT_HANDLER_URI + CommonConstants.OP_EVENT_HANDLER_SUBSCRIBE; - checkUnsubscribeParameters(eventType, subscriberName, subscriberAddress, subscriberPort, origin); - - eventHandlerService.unsubscribe(eventType, subscriberName, subscriberAddress, subscriberPort); - } - - //------------------------------------------------------------------------------------------------- - @ApiOperation(value = POST_EVENT_HANDLER_PUBLISH_DESCRIPTION, tags = { CoreCommonConstants.SWAGGER_TAG_CLIENT }) - @ApiResponses(value = { - @ApiResponse(code = HttpStatus.SC_OK, message = POST_EVENT_HANDLER_PUBLISH_HTTP_200_MESSAGE), - @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = POST_EVENT_HANDLER_PUBLISH_HTTP_400_MESSAGE), - @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), - @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) - }) - @PostMapping(path = CommonConstants.OP_EVENT_HANDLER_PUBLISH, consumes = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody public void publish(@RequestBody final EventPublishRequestDTO request) { - logger.debug("publish started ..."); - - final String origin = CommonConstants.EVENT_HANDLER_URI + CommonConstants.OP_EVENT_HANDLER_PUBLISH; - checkEventPublishRequestDTO(request, origin); - validateTimeStamp(request, origin); - - eventHandlerService.publishResponse(request); - } - - //------------------------------------------------------------------------------------------------- - @ApiOperation(value = POST_EVENT_HANDLER_PUBLISH_AUTH_UPDATE_DESCRIPTION, tags = { CoreCommonConstants.SWAGGER_TAG_PRIVATE }) - @ApiResponses(value = { - @ApiResponse(code = HttpStatus.SC_OK, message = POST_EVENT_HANDLER_PUBLISH_AUTH_UPDATE_HTTP_200_MESSAGE), - @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = POST_EVENT_HANDLER_PUBLISH_AUTH_UPDATE_HTTP_400_MESSAGE), - @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), - @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) - }) - @PostMapping(path = CommonConstants.OP_EVENT_HANDLER_PUBLISH_AUTH_UPDATE, consumes = MediaType.APPLICATION_JSON_VALUE) - @ResponseBody public void publishSubscriberAuthorizationUpdate(@RequestBody final EventPublishRequestDTO request) { - logger.debug("publishSubscriberAuthorizationUpdate started ..."); - - final String origin = CommonConstants.EVENT_HANDLER_URI + CommonConstants.OP_EVENT_HANDLER_PUBLISH_AUTH_UPDATE; - checkEventPublishRequestDTO(request, origin); - validateTimeStamp(request, origin); - - eventHandlerService.publishSubscriberAuthorizationUpdateResponse(request); - } - - //================================================================================================= - // assistant methods - - //------------------------------------------------------------------------------------------------- - private void checkSubscriptionRequestDTO(final SubscriptionRequestDTO request, final String origin) { - logger.debug("checkSubscriptionRequestDTO started ..."); - - if (request == null) { - throw new BadPayloadException("Request" + NULL_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - checkSystemRequestDTO(request.getSubscriberSystem(), origin); - - if (Utilities.isEmpty(request.getEventType())) { - throw new BadPayloadException("Request.EventType" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - if (Utilities.isEmpty(request.getNotifyUri())) { - throw new BadPayloadException("Request.NotifyUri" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - if (request.getMatchMetaData() && (request.getFilterMetaData() == null || request.getFilterMetaData().isEmpty())) { - throw new BadPayloadException("Request.MatchMetaData is true but Request.FilterMetaData" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - if (request.getSources() != null && !request.getSources().isEmpty()) { - for (final SystemRequestDTO systemRequestDTO : request.getSources()) { - checkSystemRequestDTO(systemRequestDTO, origin); - } - } - } - - //------------------------------------------------------------------------------------------------- - private void checkSystemRequestDTO(final SystemRequestDTO system, final String origin) { - logger.debug("checkSystemRequestDTO started..."); - - if (system == null) { - throw new BadPayloadException("System" + NULL_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - if (Utilities.isEmpty(system.getSystemName())) { - throw new BadPayloadException("System name" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - if (Utilities.isEmpty(system.getAddress())) { - throw new BadPayloadException("System address" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - if (system.getPort() == null) { - throw new BadPayloadException("System port" + NULL_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - final int validatedPort = system.getPort().intValue(); - if (validatedPort < CommonConstants.SYSTEM_PORT_RANGE_MIN || validatedPort > CommonConstants.SYSTEM_PORT_RANGE_MAX) { - throw new BadPayloadException("System port must be between " + CommonConstants.SYSTEM_PORT_RANGE_MIN + " and " + CommonConstants.SYSTEM_PORT_RANGE_MAX + ".", - HttpStatus.SC_BAD_REQUEST, origin); - } - } - - //------------------------------------------------------------------------------------------------- - private void checkEventPublishRequestDTO(final EventPublishRequestDTO request, final String origin) { - logger.debug("checkEventPublishRequestDTO started ..."); - - if (request == null) { - throw new BadPayloadException("Request" + NULL_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - checkSystemRequestDTO(request.getSource(), origin); - - if (Utilities.isEmpty( request.getEventType())) { - throw new BadPayloadException("Request.EventType" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - if (Utilities.isEmpty( request.getPayload())) { - throw new BadPayloadException("Request.Payload" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - } - - //------------------------------------------------------------------------------------------------- - // This method may CHANGE the content of EventPublishRequestDTO - private void validateTimeStamp(final EventPublishRequestDTO request, final String origin) { - logger.debug("validateTimeStamp started ..."); - - if (Utilities.isEmpty(request.getTimeStamp())) { - request.setTimeStamp(Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now())); - } else { - final ZonedDateTime now = ZonedDateTime.now(); - final ZonedDateTime timeStamp; - - try { - timeStamp = Utilities.parseUTCStringToLocalZonedDateTime(request.getTimeStamp()); - } catch (final DateTimeParseException ex) { - throw new BadPayloadException("Request.TimeStamp" + WRONG_FORMAT_ERROR_MESSAGE + ex, HttpStatus.SC_BAD_REQUEST, origin); - } - - if (timeStamp.isAfter(now.plusSeconds(timeStampTolerance))) { - throw new BadPayloadException("Request.TimeStamp" + IS_AFTER_TOLERATED_DIFF_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - - if (timeStamp.isBefore(now.minusSeconds(timeStampTolerance))) { - throw new BadPayloadException("Request.TimeStamp" + IS_BEFORE_TOLERATED_DIFF_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); - } - } - } - - //------------------------------------------------------------------------------------------------- - private void checkUnsubscribeParameters(final String eventType, final String subscriberName, final String subscriberAddress, final int subscriberPort, final String origin) { - logger.debug("checkUnsubscribeParameters started..."); - - if (Utilities.isEmpty(eventType)) { - throw new BadPayloadException("Event Type is blank", HttpStatus.SC_BAD_REQUEST, origin); - } - - if (Utilities.isEmpty(subscriberName)) { - throw new BadPayloadException("Name of the subscriber system is blank", HttpStatus.SC_BAD_REQUEST, origin); - } - - if (Utilities.isEmpty(subscriberAddress)) { - throw new BadPayloadException("Address of the subscriber system is blank", HttpStatus.SC_BAD_REQUEST, origin); - } - } +package eu.arrowhead.core.eventhandler; + +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; + +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.CoreDefaults; +import eu.arrowhead.common.CoreUtilities; +import eu.arrowhead.common.CoreUtilities.ValidatedPageParams; +import eu.arrowhead.common.Defaults; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.dto.shared.EventPublishRequestDTO; +import eu.arrowhead.common.dto.shared.SubscriptionListResponseDTO; +import eu.arrowhead.common.dto.shared.SubscriptionRequestDTO; +import eu.arrowhead.common.dto.shared.SubscriptionResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; +import eu.arrowhead.common.exception.BadPayloadException; +import eu.arrowhead.core.eventhandler.database.service.EventHandlerDBService; +import eu.arrowhead.core.eventhandler.service.EventHandlerService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + +@Api(tags = { CoreCommonConstants.SWAGGER_TAG_ALL }) +@CrossOrigin(maxAge = Defaults.CORS_MAX_AGE, allowCredentials = Defaults.CORS_ALLOW_CREDENTIALS, + allowedHeaders = { HttpHeaders.ORIGIN, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT, HttpHeaders.AUTHORIZATION } +) +@RestController +@RequestMapping(CommonConstants.EVENT_HANDLER_URI) +public class EventHandlerController { + + //================================================================================================= + // members + + private static final String PATH_VARIABLE_ID = "id"; + + private static final String EVENT_HANDLER_MGMT_URI = CoreCommonConstants.MGMT_URI + "/subscriptions"; + private static final String EVENTHANLER_BY_ID_MGMT_URI = EVENT_HANDLER_MGMT_URI + "/{" + PATH_VARIABLE_ID + "}"; + + private static final String GET_EVENT_HANDLER_MGMT_DESCRIPTION = "Return requested Subscription entries by the given parameters"; + private static final String GET_EVENT_HANDLER_MGMT_HTTP_200_MESSAGE = "Subscription entries returned"; + private static final String GET_EVENT_HANDLER_MGMT_HTTP_400_MESSAGE = "Could not retrieve Subscription entries"; + + private static final String GET_EVENT_HANDLER_BY_ID_MGMT_DESCRIPTION = "Return requested Subscription entry by the given id"; + private static final String GET_EVENT_HANDLER_BY_ID_MGMT_HTTP_200_MESSAGE = "Subscription entriy returned"; + private static final String GET_EVENT_HANDLER_BY_ID_MGMT_HTTP_400_MESSAGE = "Could not retrieve Subscription entry"; + + private static final String DELETE_EVENT_HANDLER_MGMT_DESCRIPTION = "Delete requested Subscription entry by the given id"; + private static final String DELETE_EVENT_HANDLER_MGMT_HTTP_200_MESSAGE = "Subscription entriy deleted"; + private static final String DELETE_EVENT_HANDLER_MGMT_HTTP_400_MESSAGE = "Could not delete Subscription entry"; + + private static final String PUT_EVENT_HANDLER_MGMT_DESCRIPTION = "Update requested Subscription entry by the given id and parameters"; + private static final String PUT_EVENT_HANDLER_MGMT_HTTP_200_MESSAGE = "Updated Subscription entry returned"; + private static final String PUT_EVENT_HANDLER_MGMT_HTTP_400_MESSAGE = "Could not update Subscription entry"; + + private static final String POST_EVENT_HANDLER_SUBSCRIPTION_DESCRIPTION = "Subscription to the events specified in requested Subscription "; + private static final String POST_EVENT_HANDLER_SUBSCRIPTION_HTTP_200_MESSAGE = "Successful subscription."; + private static final String POST_EVENT_HANDLER_SUBSCRIPTION_HTTP_400_MESSAGE = "Unsuccessful subscription."; + + private static final String DELETE_EVENT_HANDLER_SUBSCRIPTION_DESCRIPTION = "Unsubscription from the events specified in requested Subscription "; + private static final String DELETE_EVENT_HANDLER_SUBSCRIPTION_HTTP_200_MESSAGE = "Successful unsubscription."; + private static final String DELETE_EVENT_HANDLER_SUBSCRIPTION_HTTP_400_MESSAGE = "Unsuccessful unsubscription."; + + private static final String POST_EVENT_HANDLER_PUBLISH_DESCRIPTION = "Publish event"; + private static final String POST_EVENT_HANDLER_PUBLISH_HTTP_200_MESSAGE = "Publish event success"; + private static final String POST_EVENT_HANDLER_PUBLISH_HTTP_400_MESSAGE = "Publish event not success"; + + private static final String POST_EVENT_HANDLER_PUBLISH_AUTH_UPDATE_DESCRIPTION = "Publish authorization change event "; + private static final String POST_EVENT_HANDLER_PUBLISH_AUTH_UPDATE_HTTP_200_MESSAGE = "Publish authorization change event success"; + private static final String POST_EVENT_HANDLER_PUBLISH_AUTH_UPDATE_HTTP_400_MESSAGE = "Publish authorization change event not success"; + + private static final String NULL_PARAMETER_ERROR_MESSAGE = " is null."; + private static final String NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE = " is null or blank."; + private static final String ID_NOT_VALID_ERROR_MESSAGE = " Id must be greater than 0. "; + private static final String WRONG_FORMAT_ERROR_MESSAGE = " is in wrong format. "; + private static final String IS_AFTER_TOLERATED_DIFF_ERROR_MESSAGE = " is further in the future than the tolerated time difference"; + private static final String IS_BEFORE_TOLERATED_DIFF_ERROR_MESSAGE = " is further in the past than the tolerated time difference"; + + @Value(CoreCommonConstants.$TIME_STAMP_TOLERANCE_SECONDS_WD) + private long timeStampTolerance; + + private final Logger logger = LogManager.getLogger(EventHandlerController.class); + + @Autowired + EventHandlerService eventHandlerService; + + @Autowired + EventHandlerDBService eventHandlerDBService; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return an echo message with the purpose of testing the core service availability", response = String.class, tags = { CoreCommonConstants.SWAGGER_TAG_CLIENT }) + @ApiResponses (value = { + @ApiResponse(code = HttpStatus.SC_OK, message = CoreCommonConstants.SWAGGER_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = CommonConstants.ECHO_URI) + public String echoService() { + return "Got it!"; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = GET_EVENT_HANDLER_MGMT_DESCRIPTION, response = SubscriptionListResponseDTO.class, tags = { CoreCommonConstants.SWAGGER_TAG_MGMT }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_EVENT_HANDLER_MGMT_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_EVENT_HANDLER_MGMT_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = EVENT_HANDLER_MGMT_URI, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody public SubscriptionListResponseDTO getSubscriptions( + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_PAGE, required = false) final Integer page, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_ITEM_PER_PAGE, required = false) final Integer size, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_DIRECTION, defaultValue = CoreDefaults.DEFAULT_REQUEST_PARAM_DIRECTION_VALUE) final String direction, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_SORT_FIELD, defaultValue = CommonConstants.COMMON_FIELD_NAME_ID) final String sortField) { + logger.debug("New getSubscriptions get request recieved with page: {} and item_per page: {}", page, size); + + final ValidatedPageParams validParameters = CoreUtilities.validatePageParameters(page, size, direction, CommonConstants.EVENT_HANDLER_URI + EVENT_HANDLER_MGMT_URI); + final SubscriptionListResponseDTO subscriptionsResponse = eventHandlerDBService.getSubscriptionsResponse(validParameters.getValidatedPage(), validParameters.getValidatedSize(), + validParameters.getValidatedDirection(), + sortField); + + logger.debug("Subscriptions with page: {} and item_per page: {} retrieved successfully", page, size); + return subscriptionsResponse; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = GET_EVENT_HANDLER_BY_ID_MGMT_DESCRIPTION, response = SubscriptionResponseDTO.class, tags = { CoreCommonConstants.SWAGGER_TAG_MGMT }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_EVENT_HANDLER_BY_ID_MGMT_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_EVENT_HANDLER_BY_ID_MGMT_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = EVENTHANLER_BY_ID_MGMT_URI, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody public SubscriptionResponseDTO getSubscriptionById(@PathVariable(value = PATH_VARIABLE_ID) final long id) { + logger.debug("New getSubscriptionById get request recieved with id: {}", id); + + final String origin = CommonConstants.EVENT_HANDLER_URI + EVENTHANLER_BY_ID_MGMT_URI; + if (id < 1) { + throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + final SubscriptionResponseDTO subscriptionResponse = eventHandlerDBService.getSubscriptionByIdResponse(id); + + logger.debug("Subscription entry with id: {} successfully retrieved", id); + return subscriptionResponse; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = DELETE_EVENT_HANDLER_MGMT_DESCRIPTION, tags = { CoreCommonConstants.SWAGGER_TAG_MGMT }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = DELETE_EVENT_HANDLER_MGMT_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DELETE_EVENT_HANDLER_MGMT_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @DeleteMapping(path = EVENTHANLER_BY_ID_MGMT_URI, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody public void deleteSubscription(@PathVariable(value = PATH_VARIABLE_ID) final long id) { + logger.debug("New deleteSubscription delete request recieved with id: {}", id); + + final String origin = CommonConstants.EVENT_HANDLER_URI + EVENTHANLER_BY_ID_MGMT_URI; + if (id < 1) { + throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + eventHandlerDBService.deleteSubscriptionResponse(id); + + logger.debug("Subscription entry with id: {} successfully deleted", id); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = PUT_EVENT_HANDLER_MGMT_DESCRIPTION, response = SubscriptionResponseDTO.class, tags = { CoreCommonConstants.SWAGGER_TAG_MGMT }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = PUT_EVENT_HANDLER_MGMT_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = PUT_EVENT_HANDLER_MGMT_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PutMapping(path = EVENTHANLER_BY_ID_MGMT_URI, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody public SubscriptionResponseDTO updateSubscription(@PathVariable(value = PATH_VARIABLE_ID) final long id, @RequestBody final SubscriptionRequestDTO request) { + logger.debug("New updateSubscription put request recieved with id: {}", id); + + final String origin = CommonConstants.EVENT_HANDLER_URI + EVENTHANLER_BY_ID_MGMT_URI; + if (id < 1) { + throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + checkSubscriptionRequestDTO(request, origin); + final SubscriptionResponseDTO response = eventHandlerService.updateSubscriptionResponse(id, request); + + logger.debug("Subscription entry with id: {} successfully updated", id); + return response; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = POST_EVENT_HANDLER_SUBSCRIPTION_DESCRIPTION, tags = { CoreCommonConstants.SWAGGER_TAG_CLIENT }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = POST_EVENT_HANDLER_SUBSCRIPTION_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = POST_EVENT_HANDLER_SUBSCRIPTION_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(path = CommonConstants.OP_EVENT_HANDLER_SUBSCRIBE, consumes = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody public void subscribe(@RequestBody final SubscriptionRequestDTO request) { + logger.debug("subscription started ..."); + + final String origin = CommonConstants.EVENT_HANDLER_URI + CommonConstants.OP_EVENT_HANDLER_SUBSCRIBE; + checkSubscriptionRequestDTO(request, origin); + + eventHandlerService.subscribe(request); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = DELETE_EVENT_HANDLER_SUBSCRIPTION_DESCRIPTION, tags = { CoreCommonConstants.SWAGGER_TAG_CLIENT }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = DELETE_EVENT_HANDLER_SUBSCRIPTION_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DELETE_EVENT_HANDLER_SUBSCRIPTION_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @DeleteMapping(path = CommonConstants.OP_EVENT_HANDLER_UNSUBSCRIBE) + @ResponseBody public void unsubscribe( + @RequestParam(CommonConstants.OP_EVENT_HANDLER_UNSUBSCRIBE_REQUEST_PARAM_EVENT_TYPE) final String eventType, + @RequestParam(CommonConstants.OP_EVENT_HANDLER_UNSUBSCRIBE_REQUEST_PARAM_SUBSCRIBER_SYSTEM_NAME) final String subscriberName, + @RequestParam(CommonConstants.OP_EVENT_HANDLER_UNSUBSCRIBE_REQUEST_PARAM_SUBSCRIBER_ADDRESS) final String subscriberAddress, + @RequestParam(CommonConstants.OP_EVENT_HANDLER_UNSUBSCRIBE_REQUEST_PARAM_SUBSCRIBER_PORT) final int subscriberPort) { + logger.debug("unSubscription started ..."); + + final String origin = CommonConstants.EVENT_HANDLER_URI + CommonConstants.OP_EVENT_HANDLER_SUBSCRIBE; + checkUnsubscribeParameters(eventType, subscriberName, subscriberAddress, subscriberPort, origin); + + eventHandlerService.unsubscribe(eventType, subscriberName, subscriberAddress, subscriberPort); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = POST_EVENT_HANDLER_PUBLISH_DESCRIPTION, tags = { CoreCommonConstants.SWAGGER_TAG_CLIENT }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = POST_EVENT_HANDLER_PUBLISH_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = POST_EVENT_HANDLER_PUBLISH_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(path = CommonConstants.OP_EVENT_HANDLER_PUBLISH, consumes = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody public void publish(@RequestBody final EventPublishRequestDTO request) { + logger.debug("publish started ..."); + + final String origin = CommonConstants.EVENT_HANDLER_URI + CommonConstants.OP_EVENT_HANDLER_PUBLISH; + checkEventPublishRequestDTO(request, origin); + validateTimeStamp(request, origin); + + eventHandlerService.publishResponse(request); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = POST_EVENT_HANDLER_PUBLISH_AUTH_UPDATE_DESCRIPTION, tags = { CoreCommonConstants.SWAGGER_TAG_PRIVATE }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = POST_EVENT_HANDLER_PUBLISH_AUTH_UPDATE_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = POST_EVENT_HANDLER_PUBLISH_AUTH_UPDATE_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(path = CommonConstants.OP_EVENT_HANDLER_PUBLISH_AUTH_UPDATE, consumes = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody public void publishSubscriberAuthorizationUpdate(@RequestBody final EventPublishRequestDTO request) { + logger.debug("publishSubscriberAuthorizationUpdate started ..."); + + final String origin = CommonConstants.EVENT_HANDLER_URI + CommonConstants.OP_EVENT_HANDLER_PUBLISH_AUTH_UPDATE; + checkEventPublishRequestDTO(request, origin); + validateTimeStamp(request, origin); + + eventHandlerService.publishSubscriberAuthorizationUpdateResponse(request); + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + private void checkSubscriptionRequestDTO(final SubscriptionRequestDTO request, final String origin) { + logger.debug("checkSubscriptionRequestDTO started ..."); + + if (request == null) { + throw new BadPayloadException("Request" + NULL_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + checkSystemRequestDTO(request.getSubscriberSystem(), origin); + + if (Utilities.isEmpty(request.getEventType())) { + throw new BadPayloadException("Request.EventType" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(request.getNotifyUri())) { + throw new BadPayloadException("Request.NotifyUri" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (request.getMatchMetaData() && (request.getFilterMetaData() == null || request.getFilterMetaData().isEmpty())) { + throw new BadPayloadException("Request.MatchMetaData is true but Request.FilterMetaData" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (request.getSources() != null && !request.getSources().isEmpty()) { + for (final SystemRequestDTO systemRequestDTO : request.getSources()) { + checkSystemRequestDTO(systemRequestDTO, origin); + } + } + } + + //------------------------------------------------------------------------------------------------- + private void checkSystemRequestDTO(final SystemRequestDTO system, final String origin) { + logger.debug("checkSystemRequestDTO started..."); + + if (system == null) { + throw new BadPayloadException("System" + NULL_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(system.getSystemName())) { + throw new BadPayloadException("System name" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(system.getAddress())) { + throw new BadPayloadException("System address" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (system.getPort() == null) { + throw new BadPayloadException("System port" + NULL_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + final int validatedPort = system.getPort().intValue(); + if (validatedPort < CommonConstants.SYSTEM_PORT_RANGE_MIN || validatedPort > CommonConstants.SYSTEM_PORT_RANGE_MAX) { + throw new BadPayloadException("System port must be between " + CommonConstants.SYSTEM_PORT_RANGE_MIN + " and " + CommonConstants.SYSTEM_PORT_RANGE_MAX + ".", + HttpStatus.SC_BAD_REQUEST, origin); + } + } + + //------------------------------------------------------------------------------------------------- + private void checkEventPublishRequestDTO(final EventPublishRequestDTO request, final String origin) { + logger.debug("checkEventPublishRequestDTO started ..."); + + if (request == null) { + throw new BadPayloadException("Request" + NULL_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + checkSystemRequestDTO(request.getSource(), origin); + + if (Utilities.isEmpty( request.getEventType())) { + throw new BadPayloadException("Request.EventType" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty( request.getPayload())) { + throw new BadPayloadException("Request.Payload" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + } + + //------------------------------------------------------------------------------------------------- + // This method may CHANGE the content of EventPublishRequestDTO + private void validateTimeStamp(final EventPublishRequestDTO request, final String origin) { + logger.debug("validateTimeStamp started ..."); + + if (Utilities.isEmpty(request.getTimeStamp())) { + request.setTimeStamp(Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now())); + } else { + final ZonedDateTime now = ZonedDateTime.now(); + final ZonedDateTime timeStamp; + + try { + timeStamp = Utilities.parseUTCStringToLocalZonedDateTime(request.getTimeStamp()); + } catch (final DateTimeParseException ex) { + throw new BadPayloadException("Request.TimeStamp" + WRONG_FORMAT_ERROR_MESSAGE + ex, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (timeStamp.isAfter(now.plusSeconds(timeStampTolerance))) { + throw new BadPayloadException("Request.TimeStamp" + IS_AFTER_TOLERATED_DIFF_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (timeStamp.isBefore(now.minusSeconds(timeStampTolerance))) { + throw new BadPayloadException("Request.TimeStamp" + IS_BEFORE_TOLERATED_DIFF_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + } + } + + //------------------------------------------------------------------------------------------------- + private void checkUnsubscribeParameters(final String eventType, final String subscriberName, final String subscriberAddress, final int subscriberPort, final String origin) { + logger.debug("checkUnsubscribeParameters started..."); + + if (Utilities.isEmpty(eventType)) { + throw new BadPayloadException("Event Type is blank", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(subscriberName)) { + throw new BadPayloadException("Name of the subscriber system is blank", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(subscriberAddress)) { + throw new BadPayloadException("Address of the subscriber system is blank", HttpStatus.SC_BAD_REQUEST, origin); + } + } } \ No newline at end of file diff --git a/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/database/service/EventHandlerDBService.java b/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/database/service/EventHandlerDBService.java index d5af25cea..ccedc3a96 100644 --- a/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/database/service/EventHandlerDBService.java +++ b/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/database/service/EventHandlerDBService.java @@ -44,11 +44,11 @@ public class EventHandlerDBService { // members private static final String LESS_THAN_ONE_ERROR_MESSAGE= " must be greater than zero."; - private static final String NOT_AVAILABLE_SORTABLE_FIELD_ERROR_MESSAGE = " sortable field is not available."; + private static final String NOT_AVAILABLE_SORTABLE_FIELD_ERROR_MESSAGE = " sortable field is not available."; private static final String NOT_IN_DB_ERROR_MESSAGE = " is not available in database"; private static final String EMPTY_OR_NULL_ERROR_MESSAGE = " is empty or null"; private static final String NULL_ERROR_MESSAGE = " is null"; - private static final String VIOLATES_UNIQUE_CONSTRAINT = " violates uniqueConstraint rules"; + private static final String VIOLATES_UNIQUE_CONSTRAINT = " violates unique constraint rules"; private static final String IS_BEFORE_TOLERATED_DIFF_ERROR_MESSAGE = " is further in the past than the tolerated time difference"; private static final String INVALID_TYPE_ERROR_MESSAGE = " is not valid."; @@ -144,7 +144,7 @@ public Subscription getSubscriptionBySubscriptionRequestDTO(final SubscriptionRe try { final Optional subcriptionOptional = subscriptionRepository.findByEventTypeAndSubscriberSystem(subscription.getEventType(), subscription.getSubscriberSystem()); if (subcriptionOptional.isPresent()) { - return subcriptionOptional.get(); + return subcriptionOptional.get(); } else { throw new InvalidParameterException("Subscription with name '" + subscription.getSubscriberSystem().getSystemName() + "' and eventType '" + subscription.getEventType().getEventTypeName() + "' not exists"); @@ -357,7 +357,7 @@ private Subscription validateSubscriptionRequestDTO(final SubscriptionRequestDTO subscription.setOnlyPredefinedPublishers(request.getSources() != null && !request.getSources().isEmpty()); subscription.setMatchMetaData(request.getMatchMetaData()); if (subscription.isMatchMetaData() && (subscription.getFilterMetaData() == null || subscription.getFilterMetaData().isEmpty())) { - throw new InvalidParameterException("If MatchMetaData is true filterMetaData sould not be null or empty"); + throw new InvalidParameterException("If MatchMetaData is true filterMetaData should not be null or empty"); } if (request.getStartDate() != null) { @@ -408,7 +408,7 @@ private void validateDateLimits(final Subscription subscription) { if (start != null && end != null) { if (end.isBefore(start) || !end.isAfter(start)) { - throw new InvalidParameterException("Start Date sould be before End Date"); + throw new InvalidParameterException("Start Date should be before End Date"); } } } diff --git a/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/service/EventHandlerDriver.java b/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/service/EventHandlerDriver.java index e6bbb38f0..b1c4a6c8e 100644 --- a/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/service/EventHandlerDriver.java +++ b/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/service/EventHandlerDriver.java @@ -128,12 +128,12 @@ private void checkPublishRequestDTO(final EventPublishRequestDTO request) { throw new InvalidParameterException("Payload" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE); } - ckeckTimeStamp(request.getTimeStamp()); + checkTimeStamp(request.getTimeStamp()); checkSystemRequestDTO(request.getSource()); } //------------------------------------------------------------------------------------------------- - private void ckeckTimeStamp(final String timeStampString) { + private void checkTimeStamp(final String timeStampString) { logger.debug("ckeckTimeStamp started..."); if (Utilities.isEmpty(timeStampString)) { diff --git a/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/service/EventHandlerService.java b/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/service/EventHandlerService.java index 1ff8ca61a..3805dc383 100644 --- a/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/service/EventHandlerService.java +++ b/eventhandler/src/main/java/eu/arrowhead/core/eventhandler/service/EventHandlerService.java @@ -161,12 +161,12 @@ private void checkPublishRequestDTO(final EventPublishRequestDTO request) { throw new InvalidParameterException("Payload" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE); } - ckeckTimeStamp(request.getTimeStamp()); + checkTimeStamp(request.getTimeStamp()); checkSystemRequestDTO(request.getSource()); } //------------------------------------------------------------------------------------------------- - private void ckeckTimeStamp(final String timeStampString) { + private void checkTimeStamp(final String timeStampString) { logger.debug("ckeckTimeStamp started..."); if (Utilities.isEmpty(timeStampString)) { diff --git a/eventhandler/src/test/java/eu/arrowhead/core/eventhandler/database/service/EventHandlerDBServiceTest.java b/eventhandler/src/test/java/eu/arrowhead/core/eventhandler/database/service/EventHandlerDBServiceTest.java index 4c5d08e30..e42526736 100644 --- a/eventhandler/src/test/java/eu/arrowhead/core/eventhandler/database/service/EventHandlerDBServiceTest.java +++ b/eventhandler/src/test/java/eu/arrowhead/core/eventhandler/database/service/EventHandlerDBServiceTest.java @@ -260,7 +260,7 @@ public void testGetSubscriptionsResponseInvalidParameterSortField() { eventHandlerDBService.getSubscriptionsResponse(page, size, direction, sortField); } catch (final Exception ex) { verify(subscriptionRepository, never()).findAll(any(PageRequest.class)); - Assert.assertTrue(ex.getMessage().contains(" sortable field is not available." )); + Assert.assertTrue(ex.getMessage().contains(" sortable field is not available." )); throw ex; } } @@ -365,7 +365,7 @@ public void testGetSubscriptionsInvalidParameterSortField() { eventHandlerDBService.getSubscriptions(page, size, direction, sortField); } catch (final Exception ex) { verify(subscriptionRepository, never()).findAll(any(PageRequest.class)); - Assert.assertTrue(ex.getMessage().contains(" sortable field is not available.")); + Assert.assertTrue(ex.getMessage().contains(" sortable field is not available.")); throw ex; } } @@ -877,7 +877,7 @@ public void testGetSubscriptionBySubscriptionRequestDTOInvalidParameterEndDateIs verify(eventTypeRepository, times(1)).findByEventTypeName(any()); verify(eventTypeRepository, times(1)).saveAndFlush(any()); verify(subscriptionRepository, never()).findByEventTypeAndSubscriberSystem(any(), any()); - Assert.assertTrue(ex.getMessage().contains("Start Date sould be before End Date")); + Assert.assertTrue(ex.getMessage().contains("Start Date should be before End Date")); throw ex; } } @@ -907,7 +907,7 @@ public void testGetSubscriptionBySubscriptionRequestDTOInvalidParameterStartDate verify(eventTypeRepository, times(1)).findByEventTypeName(any()); verify(eventTypeRepository, times(1)).saveAndFlush(any()); verify(subscriptionRepository, times(0)).findByEventTypeAndSubscriberSystem(any(), any()); - Assert.assertTrue(ex.getMessage().contains("Start Date sould be before End Date")); + Assert.assertTrue(ex.getMessage().contains("Start Date should be before End Date")); throw ex; } } @@ -935,7 +935,7 @@ public void testGetSubscriptionBySubscriptionRequestDTOInvalidParameterMatchMeta verify(eventTypeRepository, times(1)).findByEventTypeName(any()); verify(eventTypeRepository, times(1)).saveAndFlush(any()); verify(subscriptionRepository, never()).findByEventTypeAndSubscriberSystem(any(), any()); - Assert.assertTrue(ex.getMessage().contains("If MatchMetaData is true filterMetaData sould not be null or empty")); + Assert.assertTrue(ex.getMessage().contains("If MatchMetaData is true filterMetaData should not be null or empty")); throw ex; } } @@ -963,7 +963,7 @@ public void testGetSubscriptionBySubscriptionRequestDTOInvalidParameterMatchMeta verify(eventTypeRepository, times(1)).findByEventTypeName(any()); verify(eventTypeRepository, times(1)).saveAndFlush(any()); verify(subscriptionRepository, never()).findByEventTypeAndSubscriberSystem(any(), any()); - Assert.assertTrue(ex.getMessage().contains("If MatchMetaData is true filterMetaData sould not be null or empty")); + Assert.assertTrue(ex.getMessage().contains("If MatchMetaData is true filterMetaData should not be null or empty")); throw ex; } } @@ -1132,7 +1132,7 @@ public void testRegisterSubscriptionInvalidParameterSubscriptionAllreadyInDB() { verify(subscriptionPublisherConnectionRepository, never()).saveAll(any()); verify(subscriptionPublisherConnectionRepository, never()).flush(); verify(subscriptionRepository, never()).saveAndFlush(any()); - Assert.assertTrue(ex.getMessage().contains("Subscription violates uniqueConstraint rules")); + Assert.assertTrue(ex.getMessage().contains("Subscription violates unique constraint rules")); throw ex; } } diff --git a/gatekeeper/.classpath b/gatekeeper/.classpath index 01997bb0d..e210343c4 100644 --- a/gatekeeper/.classpath +++ b/gatekeeper/.classpath @@ -45,5 +45,19 @@ + + + + + + + + + + + + + + diff --git a/gatekeeper/src/main/java/eu/arrowhead/core/gatekeeper/GatekeeperController.java b/gatekeeper/src/main/java/eu/arrowhead/core/gatekeeper/GatekeeperController.java index bc809dd16..98f2c2f55 100644 --- a/gatekeeper/src/main/java/eu/arrowhead/core/gatekeeper/GatekeeperController.java +++ b/gatekeeper/src/main/java/eu/arrowhead/core/gatekeeper/GatekeeperController.java @@ -145,7 +145,7 @@ public String echoService() { final ValidatedPageParams validParameters = CoreUtilities.validatePageParameters(page, size, direction, CommonConstants.GATEKEEPER_URI + CLOUDS_MGMT_URI); final CloudWithRelaysListResponseDTO cloudsResponse = gatekeeperDBService.getCloudsResponse(validParameters.getValidatedPage(), validParameters.getValidatedSize(), - validParameters.getValidatedDirecion(), sortField); + validParameters.getValidatedDirection(), sortField); logger.debug("Clouds with page: {} and item_per page: {} retrieved successfully", page, size); return cloudsResponse; @@ -311,7 +311,7 @@ public void removeCloudById(@PathVariable(value = PATH_VARIABLE_ID) final long i final ValidatedPageParams validParameters = CoreUtilities.validatePageParameters(page, size, direction, CommonConstants.GATEKEEPER_URI + RELAYS_MGMT_URI); final RelayListResponseDTO relaysResponse = gatekeeperDBService.getRelaysResponse(validParameters.getValidatedPage(), validParameters.getValidatedSize(), - validParameters.getValidatedDirecion(), sortField); + validParameters.getValidatedDirection(), sortField); logger.debug("Relays with page: {} and item_per page: {} retrieved successfully", page, size); return relaysResponse; diff --git a/gatekeeper/src/main/java/eu/arrowhead/core/gatekeeper/database/service/GatekeeperDBService.java b/gatekeeper/src/main/java/eu/arrowhead/core/gatekeeper/database/service/GatekeeperDBService.java index 29169e7bb..1c440d009 100644 --- a/gatekeeper/src/main/java/eu/arrowhead/core/gatekeeper/database/service/GatekeeperDBService.java +++ b/gatekeeper/src/main/java/eu/arrowhead/core/gatekeeper/database/service/GatekeeperDBService.java @@ -903,12 +903,14 @@ private List deleteUnnecessaryGatewayRelayConnectionsAndGetValidatedAddit final Set relaysToAssign = new HashSet<>(); for (final CloudGatewayRelay relayConn : cloud.getGatewayRelays()) { boolean relayConnToRemove = true; - for (final Long dtoRelayId : gatewayRealyIds) { - if (relayConn.getRelay().getId() == dtoRelayId) { - relaysToKeep.add(relayConn.getRelay().getId()); - relayConnToRemove = false; - break; - } + if (gatewayRealyIds != null && !gatewayRealyIds.isEmpty()) { + for (final Long dtoRelayId : gatewayRealyIds) { + if (relayConn.getRelay().getId() == dtoRelayId) { + relaysToKeep.add(relayConn.getRelay().getId()); + relayConnToRemove = false; + break; + } + } } if (relayConnToRemove) { @@ -916,7 +918,9 @@ private List deleteUnnecessaryGatewayRelayConnectionsAndGetValidatedAddit } } - relaysToAssign.addAll(gatewayRealyIds); + if (gatewayRealyIds != null && !gatewayRealyIds.isEmpty()) { + relaysToAssign.addAll(gatewayRealyIds); + } relaysToAssign.removeAll(relaysToKeep); final List entriesToDelete = cloudGatewayRelayRepository.findAllById(relaysConnToDelete); diff --git a/gateway/.classpath b/gateway/.classpath index 01997bb0d..e210343c4 100644 --- a/gateway/.classpath +++ b/gateway/.classpath @@ -45,5 +45,19 @@ + + + + + + + + + + + + + + diff --git a/gateway/src/main/java/eu/arrowhead/core/gateway/thread/ConsumerSideServerSocketThread.java b/gateway/src/main/java/eu/arrowhead/core/gateway/thread/ConsumerSideServerSocketThread.java index 02ee5e1eb..a6dfc9d25 100644 --- a/gateway/src/main/java/eu/arrowhead/core/gateway/thread/ConsumerSideServerSocketThread.java +++ b/gateway/src/main/java/eu/arrowhead/core/gateway/thread/ConsumerSideServerSocketThread.java @@ -96,7 +96,19 @@ public void init(final MessageProducer sender) { Assert.notNull(sender, "sender is null."); this.sender = sender; - this.initialized = true; + + try { + final SSLContext sslContext = SSLContextFactory.createGatewaySSLContext(sslProperties); + final SSLServerSocketFactory serverSocketFactory = sslContext.getServerSocketFactory(); + sslServerSocket = (SSLServerSocket) serverSocketFactory.createServerSocket(port); + sslServerSocket.setNeedClientAuth(true); + sslServerSocket.setSoTimeout(timeout); + this.initialized = true; + } catch (final Throwable ex) { + logger.debug("Problem occurs in initializing gateway communication: {}", ex.getMessage()); + logger.debug("Stacktrace:", ex); + close(); + } } //------------------------------------------------------------------------------------------------- @@ -147,12 +159,6 @@ public void run() { } try { - final SSLContext sslContext = SSLContextFactory.createGatewaySSLContext(sslProperties); - final SSLServerSocketFactory serverSocketFactory = sslContext.getServerSocketFactory(); - sslServerSocket = (SSLServerSocket) serverSocketFactory.createServerSocket(port); - sslServerSocket.setNeedClientAuth(true); - sslServerSocket.setSoTimeout(timeout); - sslConsumerSocket = (SSLSocket) sslServerSocket.accept(); final InputStream inConsumer = sslConsumerSocket.getInputStream(); outConsumer = sslConsumerSocket.getOutputStream(); diff --git a/gateway/src/test/java/eu/arrowhead/core/gateway/service/GatewayServiceTest.java b/gateway/src/test/java/eu/arrowhead/core/gateway/service/GatewayServiceTest.java index 945efe856..69c7f7e2f 100644 --- a/gateway/src/test/java/eu/arrowhead/core/gateway/service/GatewayServiceTest.java +++ b/gateway/src/test/java/eu/arrowhead/core/gateway/service/GatewayServiceTest.java @@ -42,6 +42,8 @@ import org.mockito.Mock; import org.mockito.Spy; import org.springframework.context.ApplicationContext; +import org.springframework.core.io.ClassPathResource; +import org.springframework.core.io.Resource; import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.util.ReflectionTestUtils; @@ -74,7 +76,7 @@ public class GatewayServiceTest { @Mock private Map arrowheadContext; - @Spy + @Mock private ApplicationContext appContext; @Mock @@ -624,6 +626,7 @@ public void testConnectConsumerEverythingOK() throws JMSException { when(relayClient.createConnection(any(String.class), anyInt(), anyBoolean())).thenReturn(getTestSession()); when(relayClient.isConnectionClosed(any(Session.class))).thenReturn(false); when(relayClient.initializeConsumerSideRelay(any(Session.class), any(MessageListener.class), any(String.class), any(String.class))).thenReturn(new ConsumerSideRelayInfo(producer, producer)); + when(appContext.getBean(SSLProperties.class)).thenReturn(getTestSSLPropertiesForThread()); final int serverPort = testingObject.connectConsumer(request); @@ -921,4 +924,19 @@ private GatewayConsumerConnectionRequestDTO getTestGatewayConsumerConnectionRequ return new GatewayConsumerConnectionRequestDTO(relay, "queueId", "peerName", publicKey, consumer, provider, consumerCloud, providerCloud, "test-service"); } + + //------------------------------------------------------------------------------------------------- + private SSLProperties getTestSSLPropertiesForThread() { + final SSLProperties sslProps = new SSLProperties(); + ReflectionTestUtils.setField(sslProps, "sslEnabled", true); + ReflectionTestUtils.setField(sslProps, "keyStoreType", "PKCS12"); + final Resource keystore = new ClassPathResource("certificates/gateway.p12"); + ReflectionTestUtils.setField(sslProps, "keyStore", keystore); + ReflectionTestUtils.setField(sslProps, "keyStorePassword", "123456"); + final Resource truststore = new ClassPathResource("certificates/truststore.p12"); + ReflectionTestUtils.setField(sslProps, "trustStore", truststore); + ReflectionTestUtils.setField(sslProps, "trustStorePassword", "123456"); + + return sslProps; + } } \ No newline at end of file diff --git a/gateway/src/test/java/eu/arrowhead/core/gateway/thread/ConsumerSideServerSocketThreadTest.java b/gateway/src/test/java/eu/arrowhead/core/gateway/thread/ConsumerSideServerSocketThreadTest.java index 3176e9cca..f99acbcbd 100644 --- a/gateway/src/test/java/eu/arrowhead/core/gateway/thread/ConsumerSideServerSocketThreadTest.java +++ b/gateway/src/test/java/eu/arrowhead/core/gateway/thread/ConsumerSideServerSocketThreadTest.java @@ -8,6 +8,7 @@ import static org.mockito.Mockito.when; import java.io.ByteArrayOutputStream; +import java.io.IOException; import java.io.OutputStream; import java.io.Serializable; import java.security.PublicKey; @@ -34,6 +35,7 @@ import javax.jms.Topic; import javax.jms.TopicSubscriber; import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLServerSocket; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; @@ -44,6 +46,7 @@ import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import org.springframework.context.ApplicationContext; import org.springframework.core.io.ClassPathResource; import org.springframework.core.io.Resource; @@ -161,12 +164,24 @@ public void testConstructorServiceDefinitionEmpty() { public void testInitSenderNull() { testingObject.init(null); } + + //------------------------------------------------------------------------------------------------- + @Test + public void testInitSSLSocketInitializationFailed() { + Assert.assertFalse(testingObject.isInitialized()); + + ReflectionTestUtils.setField(testingObject, "sslProperties", null); + testingObject.init(getTestMessageProducer()); + + Assert.assertFalse(testingObject.isInitialized()); + } //------------------------------------------------------------------------------------------------- @Test public void testInitOk() { Assert.assertTrue(!testingObject.isInitialized()); + ReflectionTestUtils.setField(testingObject, "port", 22004); testingObject.init(getTestMessageProducer()); Assert.assertTrue(testingObject.isInitialized()); @@ -235,16 +250,18 @@ public void testRunNotInitialized() { //------------------------------------------------------------------------------------------------- @Test - public void testRunWhenInternalExceptionThrown() { - final SSLProperties sslProps = getTestSSLPropertiesForThread(); - ReflectionTestUtils.setField(sslProps, "keyStoreType", "invalid"); - - when(appContext.getBean(SSLProperties.class)).thenReturn(sslProps); - + public void testRunWhenInternalExceptionThrown() throws IOException { + when(appContext.getBean(SSLProperties.class)).thenReturn(getTestSSLPropertiesForThread()); + final String publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq5Jq4tOeFoLqxOqtYcujbCNZina3iuV9+/o8D1R9D0HvgnmlgPlqWwjDSxV7m7SGJpuc/rRXJ85OzqV3rwRHO8A8YWXiabj8EdgEIyqg4SOgTN7oZ7MQUisTpwtWn9K14se4dHt/YE9mUW4en19p/yPUDwdw3ECMJHamy/O+Mh6rbw6AFhYvz6F5rXYB8svkenOuG8TSBFlRkcjdfqQqtl4xlHgmlDNWpHsQ3eFAO72mKQjm2ZhWI1H9CLrJf1NQs2GnKXgHBOM5ET61fEHWN8axGGoSKfvTed5vhhX7l5uwxM+AKQipLNNKjEaQYnyX3TL9zL8I7y+QkhzDa7/5kQIDAQAB"; - final ConsumerSideServerSocketThread thread = new ConsumerSideServerSocketThread(appContext, 22003, relayClient, getTestSession(), publicKey, "queueId", 60000, "consumer", "test-service"); + final ConsumerSideServerSocketThread thread = new ConsumerSideServerSocketThread(appContext, 22005, relayClient, getTestSession(), publicKey, "queueId", 60000, "consumer", "test-service"); thread.init(getTestMessageProducer()); + + final SSLServerSocket sslServerSocket = Mockito.mock(SSLServerSocket.class); + when(sslServerSocket.accept()).thenThrow(IOException.class); + ReflectionTestUtils.setField(thread, "sslServerSocket", sslServerSocket); + thread.run(); final boolean interrupted = (boolean) ReflectionTestUtils.getField(thread, "interrupted"); diff --git a/onboarding/pom.xml b/onboarding/pom.xml new file mode 100644 index 000000000..d1fa22ec9 --- /dev/null +++ b/onboarding/pom.xml @@ -0,0 +1,136 @@ + + 4.0.0 + + eu.arrowhead + core + ${revision} + + + arrowhead-onboarding + jar + Arrowhead Onboarding Controller + SQL-based Onboarding Controller core service + + + + eu.arrowhead + arrowhead-core-common + ${revision} + + + + + + + maven-resources-plugin + ${mvn.resources.version} + + + copy-resources + + validate + + copy-resources + + + ${basedir}/target + + + src/main/resources + + application.properties + log4j2.xml + + + + + + + + + + jdeb + org.vafer + 1.8 + + + package + + jdeb + + + true + + [YYMMddHHmm].${git.commit.id.abbrev} + target/${project.artifactId}_${revision}.deb + true + ${basedir}/src/deb/control + + + file + ${project.build.directory}/${project.build.finalName}.jar + + perm + /usr/share/arrowhead/onboarding_controller + 755 + + + + + link + /usr/share/arrowhead/onboarding_controller/${project.artifactId}.jar + /usr/share/arrowhead/onboarding_controller/${project.build.finalName}.jar + + + + file + ${project.build.directory}/log4j2.xml + + perm + /etc/arrowhead/systems/onboarding_controller + 644 + + + + + file + ${project.build.directory}/application.properties + + perm + /etc/arrowhead/systems/onboarding_controller + 644 + + + + + link + /usr/share/arrowhead/onboarding_controller/application.properties + /etc/arrowhead/systems/onboarding_controller/application.properties + + + + file + ${project.basedir}/src/deb/arrowhead-onboarding.service + + perm + /etc/systemd/system + 644 + + + + + file + ${project.basedir}/../scripts/onboarding_controller_privileges.sql + + perm + /usr/share/arrowhead/conf + + + + + + + + + + \ No newline at end of file diff --git a/onboarding/src/deb/arrowhead-onboarding.service b/onboarding/src/deb/arrowhead-onboarding.service new file mode 100644 index 000000000..19b843e88 --- /dev/null +++ b/onboarding/src/deb/arrowhead-onboarding.service @@ -0,0 +1,15 @@ +[Unit] +Description=arrowhead-onboarding +After=network.target + +[Service] +WorkingDirectory=/etc/arrowhead/systems/onboarding_controller +ExecStart=/usr/bin/java -Dlog4j.configurationFile=file:/etc/arrowhead/systems/onboarding_controller/log4j2.xml -jar /usr/share/arrowhead/onboarding_controller/arrowhead-onboarding.jar +ExecStartPost=/bin/bash -c 'sleep 10' +TimeoutStopSec=5 +Type=simple +User=arrowhead +Group=arrowhead + +[Install] +WantedBy=default.target diff --git a/onboarding/src/deb/control/config b/onboarding/src/deb/control/config new file mode 100644 index 000000000..44fd37679 --- /dev/null +++ b/onboarding/src/deb/control/config @@ -0,0 +1,19 @@ +#!/bin/sh -e + +. /usr/share/debconf/confmodule + +if logname 2>/dev/null; then + USER=$(logname) + HOME=$(eval echo "~$USER") +else + USER="root" + HOME="/root" +fi + +# Get installation type +db_input high arrowhead-core-common/db_host || true +db_input high arrowhead-core-common/mysql_password_onboarding || true + +# Run dialogs +db_go || true + diff --git a/onboarding/src/deb/control/control b/onboarding/src/deb/control/control new file mode 100644 index 000000000..5765d3184 --- /dev/null +++ b/onboarding/src/deb/control/control @@ -0,0 +1,10 @@ +Package: arrowhead-onboarding +Version: [[version]] +Section: contrib/java +Priority: optional +Architecture: all +Maintainer: Mario Zsilak +Homepage: http://www.arrowhead.eu +Description: Arrowhead Onboarding Controller +Distribution: development +Depends: java-runtime-headless, openssl, virtual-mysql-server, arrowhead-core-common diff --git a/onboarding/src/deb/control/postinst b/onboarding/src/deb/control/postinst new file mode 100644 index 000000000..a2e66a110 --- /dev/null +++ b/onboarding/src/deb/control/postinst @@ -0,0 +1,104 @@ +#!/bin/sh +# postinst script for arrowhead-onboarding +# +# see: dh_installdeb(1) + +set -e + +. /usr/share/debconf/confmodule + +SYSTEM_NAME="onboarding_controller" +PKG_NAME="arrowhead-onboarding" + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + +case "$1" in + configure) + dos2unix -q /etc/systemd/system/${PKG_NAME}.service + + . /usr/share/arrowhead/conf/ahconf.sh + + SYSTEM_DIR="${AH_SYSTEMS_DIR}/${SYSTEM_NAME}" + + db_get arrowhead-core-common/mysql_password_onboarding; system_passwd=$RET || true + db_unregister arrowhead-core-common/mysql_password_onboarding + + # Generate password (if required) + if [ -z "${system_passwd}" ]; then + system_passwd="$(openssl rand -base64 12)" + fi + + echo "Configuring MySQL database..." >&2 + ah_db_tables_and_user ${SYSTEM_NAME} ${SYSTEM_NAME}_privileges.sql ${system_passwd} + + if [ ! -d "${SYSTEM_DIR}" ]; then + mkdir -p ${SYSTEM_DIR} + fi + + domain_name=${AH_DOMAIN_NAME} + if [ -z ${domain_name} ]; then + domain_name=${OWN_IP} + fi + + ah_cert_signed_system ${SYSTEM_NAME} + + # modify log config and application.properties + + ah_transform_log_file ${SYSTEM_DIR} + + db_get arrowhead-core-common/sr_host; sr_host=$RET || true + + if [ -z ${sr_host} ]; then + sr_host=${OWN_IP} + fi + + db_get arrowhead-core-common/db_host; db_host=$RET || true + + mv ${SYSTEM_DIR}/application.properties ${SYSTEM_DIR}/application.properties.orig + cat ${SYSTEM_DIR}/application.properties.orig | \ + sed -r -e "\#^.*spring\.datasource\.url=#s#.*\$#spring.datasource.url=jdbc:mysql://"${db_host}":3306/arrowhead?serverTimezone=Europe/Budapest#" \ + -e "\#^.*spring\.datasource\.password=#s#.*\$#spring.datasource.password=${system_passwd}#" \ + -e "\#^.*domain\.name=#s#.*\$#domain.name=${domain_name}#" \ + -e "\#^.*server\.address=#s#.*\$#server.address=${OWN_IP}#" \ + -e "\#^.*sr_address=#s#.*\$#sr_address=${sr_host}#" \ + -e "\#^.*server\.ssl\.key-store=#s#.*\$#server.ssl.key-store=file:${SYSTEM_DIR}/${SYSTEM_NAME}.p12#" \ + -e "\#^.*server\.ssl\.key-store-password=#s#.*\$#server.ssl.key-store-password=${AH_PASS_CERT}#" \ + -e "\#^.*server\.ssl\.key-password=#s#.*\$#server.ssl.key-password=${AH_PASS_CERT}#" \ + -e "\#^.*server\.ssl\.trust-store=#s#.*\$#server.ssl.trust-store=file:${AH_CONF_DIR}/truststore.p12#" \ + -e "\#^.*server\.ssl\.trust-store-password=#s#.*\$#server.ssl.trust-store-password=${AH_PASS_CERT}#" > ${SYSTEM_DIR}/application.properties + + rm ${SYSTEM_DIR}/application.properties.orig + chown arrowhead:arrowhead ${SYSTEM_DIR}/application.properties + chmod 640 ${SYSTEM_DIR}/application.properties + + echo "Starting ${PKG_NAME}..." >&2 + systemctl daemon-reload + systemctl enable ${PKG_NAME}.service + systemctl start ${PKG_NAME}.service + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/onboarding/src/deb/control/postrm b/onboarding/src/deb/control/postrm new file mode 100644 index 000000000..e692870d7 --- /dev/null +++ b/onboarding/src/deb/control/postrm @@ -0,0 +1,56 @@ +#!/bin/sh +# postrm script for arrowhead-onboarding +# +# see: dh_installdeb(1) + +set -e + +. /usr/share/debconf/confmodule + +SYSTEM_NAME="onboarding_controller" + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + purge) + AH_CONF_DIR="/etc/arrowhead" + AH_SYSTEMS_DIR="${AH_CONF_DIR}/systems" + SYSTEM_DIR="${AH_SYSTEMS_DIR}/${SYSTEM_NAME}" + + rm -f \ + /var/log/arrowhead/${SYSTEM_NAME}*.log \ + ${SYSTEM_DIR}/log4j2.xml \ + ${SYSTEM_DIR}/application.properties \ + ${SYSTEM_DIR}/${SYSTEM_NAME}.p12 + rmdir ${SYSTEM_DIR} 2>/dev/null || true + rmdir ${AH_SYSTEMS_DIR}/sysop 2>/dev/null || true + db_purge + ;; + + remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/onboarding/src/deb/control/preinst b/onboarding/src/deb/control/preinst new file mode 100644 index 000000000..6e36ca318 --- /dev/null +++ b/onboarding/src/deb/control/preinst @@ -0,0 +1,35 @@ +#!/bin/sh +# preinst script for arrowhead-onboarding +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `install' +# * `install' +# * `upgrade' +# * `abort-upgrade' +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + install|upgrade) + ;; + + abort-upgrade) + ;; + + *) + echo "preinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/onboarding/src/deb/control/prerm b/onboarding/src/deb/control/prerm new file mode 100644 index 000000000..e9a9717a6 --- /dev/null +++ b/onboarding/src/deb/control/prerm @@ -0,0 +1,45 @@ +#!/bin/sh +# prerm script for arrowhead-onboarding +# +# see: dh_installdeb(1) + +set -e + +PKG_NAME="arrowhead-onboarding" + +# summary of how this script can be called: +# * `remove' +# * `upgrade' +# * `failed-upgrade' +# * `remove' `in-favour' +# * `deconfigure' `in-favour' +# `removing' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + remove) + systemctl stop ${PKG_NAME}.service + systemctl disable ${PKG_NAME}.service + ;; + + upgrade|deconfigure) + ;; + + failed-upgrade) + ;; + + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/onboarding/src/main/java/eu/arrowhead/core/onboarding/OnboardingApplicationInitListener.java b/onboarding/src/main/java/eu/arrowhead/core/onboarding/OnboardingApplicationInitListener.java new file mode 100644 index 000000000..a20d44447 --- /dev/null +++ b/onboarding/src/main/java/eu/arrowhead/core/onboarding/OnboardingApplicationInitListener.java @@ -0,0 +1,112 @@ +package eu.arrowhead.core.onboarding; + +import eu.arrowhead.common.ApplicationInitListener; +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.core.CoreSystemService; +import eu.arrowhead.common.drivers.DriverUtilities; +import eu.arrowhead.common.dto.internal.AuthorizationIntraCloudListResponseDTO; +import eu.arrowhead.common.dto.internal.AuthorizationIntraCloudRequestDTO; +import eu.arrowhead.common.dto.shared.ServiceInterfaceResponseDTO; +import eu.arrowhead.common.dto.shared.ServiceRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponents; + +import java.util.Base64; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +@Component +public class OnboardingApplicationInitListener extends ApplicationInitListener { + + private static final long SLEEP_PERIOD = TimeUnit.SECONDS.toMillis(15); + private static final int MAX_RETRIES = 10; + + private final Logger logger = LogManager.getLogger(OnboardingApplicationInitListener.class); + private final DriverUtilities driver; + + @Autowired + public OnboardingApplicationInitListener(final DriverUtilities driver) {this.driver = driver;} + + //================================================================================================= + // members + + //------------------------------------------------------------------------------------------------- + @Override + protected void customInit(final ContextRefreshedEvent event) { + + if (sslProperties.isSslEnabled()) { + logger.debug("AuthInfo: {}", Base64.getEncoder().encodeToString(publicKey.getEncoded())); + } + + logger.info("Searching for authorization system"); + final UriComponents authIntraService = driver.findUriByServiceRegistry(CoreSystemService.AUTH_CONTROL_INTRA_SERVICE); + final UriComponents authMgmtUri = driver.createCustomUri(authIntraService, CommonConstants.AUTHORIZATION_URI, + OnboardingConstants.AUTHORIZATION_INTRA_CLOUD_MGMT_URI); + logger.debug("Authorization system intracloud management uri created: {}", authMgmtUri.toUriString()); + + + logger.info("Searching for own system entry"); + final ServiceRegistryResponseDTO onboardingEntry = + driver.findByServiceRegistry(CoreSystemService.ONBOARDING_WITH_CERTIFICATE_AND_CSR_SERVICE, false); + final SystemResponseDTO onboardingSystem = onboardingEntry.getProvider(); + + for (CoreSystemService coreSystemService : getRequiredCoreSystemServiceUris()) { + lookupAndAuthorize(authMgmtUri, onboardingSystem, coreSystemService); + } + } + + @Override + protected List getRequiredCoreSystemServiceUris() { + return List.of(CoreSystemService.CERTIFICATE_AUTHORITY_SIGN_SERVICE, + CoreSystemService.ORCHESTRATION_SERVICE, + CoreSystemService.DEVICE_REGISTRY_ONBOARDING_WITH_NAME_SERVICE, + CoreSystemService.DEVICE_REGISTRY_ONBOARDING_WITH_CSR_SERVICE, + CoreSystemService.SYSTEM_REGISTRY_ONBOARDING_WITH_NAME_SERVICE, + CoreSystemService.SYSTEM_REGISTRY_ONBOARDING_WITH_CSR_SERVICE, + CoreSystemService.SERVICE_REGISTRY_REGISTER_SERVICE); + } + + private void lookupAndAuthorize(final UriComponents authMgmtUri, + final SystemResponseDTO consumer, + final CoreSystemService service) { + final ServiceRegistryResponseDTO serviceEntry = driver.findByServiceRegistry(service, false); + final SystemResponseDTO systemEntry = serviceEntry.getProvider(); + + int retryCount = 0; + + logger.info("Creating authorization rule for {}", service); + + final var authRequest = new AuthorizationIntraCloudRequestDTO(); + authRequest.setConsumerId(consumer.getId()); + authRequest.setProviderIds(Collections.singletonList(systemEntry.getId())); + authRequest.setInterfaceIds(serviceEntry.getInterfaces().stream().map(ServiceInterfaceResponseDTO::getId).collect(Collectors.toList())); + authRequest.setServiceDefinitionIds(Collections.singletonList(serviceEntry.getServiceDefinition().getId())); + try { + httpService.sendRequest(authMgmtUri, HttpMethod.POST, AuthorizationIntraCloudListResponseDTO.class, authRequest); + } catch (final ArrowheadException e) { + if (retryCount++ > MAX_RETRIES) { + throw e; + } else { + logger.info("Unable to retrieve service {}: {}. Retrying in {}ms", service.getServiceDefinition(), e.getMessage(), SLEEP_PERIOD); + sleep(); + } + } + } + + private void sleep() { + try { + Thread.sleep(SLEEP_PERIOD); + } catch (InterruptedException e) { + logger.warn(e.getMessage()); + } + } +} \ No newline at end of file diff --git a/onboarding/src/main/java/eu/arrowhead/core/onboarding/OnboardingConstants.java b/onboarding/src/main/java/eu/arrowhead/core/onboarding/OnboardingConstants.java new file mode 100644 index 000000000..ed97ec7e2 --- /dev/null +++ b/onboarding/src/main/java/eu/arrowhead/core/onboarding/OnboardingConstants.java @@ -0,0 +1,15 @@ +package eu.arrowhead.core.onboarding; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; + +public class OnboardingConstants { + + public static final String AUTHORIZATION_INTRA_CLOUD_MGMT_URI = CoreCommonConstants.MGMT_URI + "/intracloud"; + public static final String SERVICE_REGISTRY_QUERY_BY_DTO_PATH = + CommonConstants.SERVICE_REGISTRY_URI + CoreCommonConstants.OP_SERVICE_REGISTRY_QUERY_BY_SYSTEM_DTO_URI; + public static final String SERVICE_REGISTRY_QUERY_BY_DTO_KEY = SERVICE_REGISTRY_QUERY_BY_DTO_PATH + CoreCommonConstants.URI_SUFFIX; + + //------------------------------------------------------------------------------------------------- + private OnboardingConstants() { super(); } +} diff --git a/onboarding/src/main/java/eu/arrowhead/core/onboarding/OnboardingController.java b/onboarding/src/main/java/eu/arrowhead/core/onboarding/OnboardingController.java new file mode 100644 index 000000000..4f43b8d5d --- /dev/null +++ b/onboarding/src/main/java/eu/arrowhead/core/onboarding/OnboardingController.java @@ -0,0 +1,285 @@ +package eu.arrowhead.core.onboarding; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.Defaults; +import eu.arrowhead.common.SSLProperties; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.dto.shared.OnboardingWithCsrRequestDTO; +import eu.arrowhead.common.dto.shared.OnboardingWithCsrResponseDTO; +import eu.arrowhead.common.dto.shared.OnboardingWithNameRequestDTO; +import eu.arrowhead.common.dto.shared.OnboardingWithNameResponseDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.common.exception.AuthException; +import eu.arrowhead.common.exception.BadPayloadException; +import eu.arrowhead.common.exception.InvalidParameterException; +import eu.arrowhead.core.onboarding.service.OnboardingService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +import javax.annotation.Resource; +import javax.servlet.http.HttpServletRequest; +import java.security.cert.X509Certificate; +import java.util.Base64; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import static eu.arrowhead.common.CommonConstants.OP_ONBOARDING_WITH_CERTIFICATE_AND_CSR; +import static eu.arrowhead.common.CommonConstants.OP_ONBOARDING_WITH_CERTIFICATE_AND_NAME; +import static eu.arrowhead.common.CommonConstants.OP_ONBOARDING_WITH_SHARED_SECRET_AND_CSR; +import static eu.arrowhead.common.CommonConstants.OP_ONBOARDING_WITH_SHARED_SECRET_AND_NAME; + +@Api(tags = {CoreCommonConstants.SWAGGER_TAG_CLIENT, CoreCommonConstants.SWAGGER_TAG_ONBOARDING}) +@CrossOrigin(maxAge = Defaults.CORS_MAX_AGE, allowCredentials = Defaults.CORS_ALLOW_CREDENTIALS, + allowedHeaders = {HttpHeaders.ORIGIN, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT, HttpHeaders.AUTHORIZATION} +) +@RestController +@RequestMapping(CommonConstants.ONBOARDING_URI) +public class OnboardingController { + + //================================================================================================= + // members + + private static final String ONBOARDING_HTTP_200_MESSAGE = "Initial Onboarding successful"; + private static final String ONBOARDING_HTTP_400_MESSAGE = "Request parameter missing"; + private static final String COMMON_NAME_NULL_ERROR_MESSAGE = " Common name must have value "; + private static final String CSR_NULL_ERROR_MESSAGE = " CertificateSigningRequest must have value "; + + private final Logger logger = LogManager.getLogger(OnboardingController.class); + private final OnboardingService onboardingDBService; + private final SSLProperties sslProperties; + + + @Resource(name = CommonConstants.ARROWHEAD_CONTEXT) + private Map arrowheadContext; + + @Value(value = "${sharedSecret:#{null}}") + private Optional sharedSecret; + + @Autowired + public OnboardingController(final OnboardingService onboardingDBService, final SSLProperties sslProperties) { + this.onboardingDBService = onboardingDBService; + this.sslProperties = sslProperties; + } + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return an echo message with the purpose of testing the core device availability", response = String.class, tags = {CoreCommonConstants.SWAGGER_TAG_CLIENT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = CoreCommonConstants.SWAGGER_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = CommonConstants.ECHO_URI) + public String echoOnboarding() { + return "Got it!"; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Onboarding with certificate and device name", response = OnboardingWithNameResponseDTO.class, + tags = {CoreCommonConstants.SWAGGER_TAG_CLIENT, CoreCommonConstants.SWAGGER_TAG_ONBOARDING}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = ONBOARDING_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = ONBOARDING_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(OP_ONBOARDING_WITH_CERTIFICATE_AND_NAME) + @ResponseBody + public OnboardingWithNameResponseDTO onboardWithCertificateAndName(final HttpServletRequest httpServletRequest, + @RequestBody final OnboardingWithNameRequestDTO onboardingRequest) { + logger.debug("onboardWithCertificateAndName started ..."); + + authenticateCertificate(httpServletRequest); + verifyRequest(onboardingRequest, CommonConstants.ONBOARDING_URI + OP_ONBOARDING_WITH_CERTIFICATE_AND_NAME); + + final String host = httpServletRequest.getRemoteHost(); + final String address = httpServletRequest.getRemoteAddr(); + return onboardingDBService.onboarding(onboardingRequest, host, address); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Onboarding with shared secret and device name", response = OnboardingWithNameResponseDTO.class, + tags = {CoreCommonConstants.SWAGGER_TAG_CLIENT, CoreCommonConstants.SWAGGER_TAG_ONBOARDING}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = ONBOARDING_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = ONBOARDING_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(OP_ONBOARDING_WITH_SHARED_SECRET_AND_NAME) + @ResponseBody + public OnboardingWithNameResponseDTO onboardWithSharedSecretAndName(final HttpServletRequest httpServletRequest, + @RequestBody final OnboardingWithNameRequestDTO onboardingRequest, + @RequestHeader final HttpHeaders headers) { + logger.debug("onboardWithSharedSecretAndName started ..."); + + authenticateSharedSecret(headers.getFirst(HttpHeaders.AUTHORIZATION)); + verifyRequest(onboardingRequest, CommonConstants.ONBOARDING_URI + OP_ONBOARDING_WITH_SHARED_SECRET_AND_NAME); + + final String host = httpServletRequest.getRemoteHost(); + final String address = httpServletRequest.getRemoteAddr(); + return onboardingDBService.onboarding(onboardingRequest, host, address); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Onboarding with certificate and certificate signing request", response = OnboardingWithCsrResponseDTO.class, + tags = {CoreCommonConstants.SWAGGER_TAG_CLIENT, CoreCommonConstants.SWAGGER_TAG_ONBOARDING}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = ONBOARDING_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = ONBOARDING_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(OP_ONBOARDING_WITH_CERTIFICATE_AND_CSR) + @ResponseBody + public OnboardingWithCsrResponseDTO onboardWithCertificateAndSigningRequest(final HttpServletRequest httpServletRequest, + @RequestBody final OnboardingWithCsrRequestDTO onboardingRequest) { + logger.debug("onboardWithCertificateAndSigningRequest started ..."); + + authenticateCertificate(httpServletRequest); + verifyRequest(onboardingRequest, CommonConstants.ONBOARDING_URI + OP_ONBOARDING_WITH_CERTIFICATE_AND_CSR); + + return onboardingDBService.onboarding(onboardingRequest); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Onboarding with certificate and certificate signing request", response = OnboardingWithCsrResponseDTO.class, + tags = {CoreCommonConstants.SWAGGER_TAG_CLIENT, CoreCommonConstants.SWAGGER_TAG_ONBOARDING}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = ONBOARDING_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = ONBOARDING_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(OP_ONBOARDING_WITH_SHARED_SECRET_AND_CSR) + @ResponseBody + public OnboardingWithCsrResponseDTO onboardWithSharedSecretAndSigningRequest(@RequestBody final OnboardingWithCsrRequestDTO onboardingRequest, + @RequestHeader(HttpHeaders.AUTHORIZATION) final String authorization) { + logger.debug("onboardWithSharedSecretAndSigningRequest started ..."); + + authenticateSharedSecret(authorization); + verifyRequest(onboardingRequest, CommonConstants.ONBOARDING_URI + OP_ONBOARDING_WITH_SHARED_SECRET_AND_CSR); + + return onboardingDBService.onboarding(onboardingRequest); + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + private void authenticateCertificate(final HttpServletRequest httpServletRequest) { + final X509Certificate[] certificates = (X509Certificate[]) httpServletRequest.getAttribute(CommonConstants.ATTR_JAVAX_SERVLET_REQUEST_X509_CERTIFICATE); + + if (sslProperties.isSslEnabled()) { + if (Objects.nonNull(certificates) && certificates.length > 0) { + + // TODO verification should be done by CA + final X509Certificate cert = certificates[0]; + final String clientCN = Utilities.getCertCNFromSubject(cert.getSubjectDN().getName()); + final String requestTarget = Utilities.stripEndSlash(httpServletRequest.getRequestURL().toString()); + + if (!Utilities.isKeyStoreCNArrowheadValid(clientCN)) { + logger.debug("{} is not a valid common name, access denied!", clientCN); + throw new AuthException(clientCN + " is unauthorized to access " + requestTarget); + } + + // All requests from the local cloud are allowed + if (!Utilities.isKeyStoreCNArrowheadValid(clientCN, getServerCloudCN())) { + logger.debug("{} is unauthorized to access {}", clientCN, requestTarget); + throw new AuthException(clientCN + " is unauthorized to access " + requestTarget); + } + } else { + logger.debug("No client certificate given!"); + throw new AuthException("Client certificate in needed!"); + } + } + } + + //------------------------------------------------------------------------------------------------- + private void authenticateSharedSecret(final String authorization) { + if (sharedSecret.isEmpty()) { + throw new InvalidParameterException("Shared Secret is disabled by this service"); + } + + if (Utilities.isEmpty(authorization)) { + throw new AuthException("Basic Authentication is needed for this method", HttpStatus.SC_UNAUTHORIZED); + } + + // Header is in the format "Basic 5tyc0uiDat4" + // We need to extract data before decoding it back to original string + final String[] authParts = authorization.split("\\s+"); + final String authInfo = authParts[1]; + + // Decode the data back to original string + byte[] bytes; + try { + bytes = Base64.getDecoder().decode(authInfo); + } catch (IllegalArgumentException e) { + logger.error(e.getMessage()); + throw new ArrowheadException("Unable to decode authorization header"); + } + + final String expectedSecret = sharedSecret.get(); + final String[] basicAuth = new String(bytes).split(":"); + + if (!(basicAuth.length == 2 && expectedSecret.equals(basicAuth[1]))) { + throw new AuthException("Basic Authentication failed with the given secret", HttpStatus.SC_UNAUTHORIZED); + } + } + + //------------------------------------------------------------------------------------------------- + private void verifyRequest(final OnboardingWithNameRequestDTO onboardingRequest, final String origin) { + logger.debug("verifyRequest started..."); + + if (Objects.isNull(onboardingRequest) || Objects.isNull(onboardingRequest.getCreationRequestDTO())) { + throw new BadPayloadException("Request is null.", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(onboardingRequest.getCreationRequestDTO().getCommonName())) { + throw new BadPayloadException(COMMON_NAME_NULL_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + } + + //------------------------------------------------------------------------------------------------- + private void verifyRequest(final OnboardingWithCsrRequestDTO onboardingRequest, final String origin) { + logger.debug("verifyRequest started..."); + + if (Objects.isNull(onboardingRequest)) { + throw new BadPayloadException("Request is null.", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(onboardingRequest.getCertificateSigningRequest())) { + throw new BadPayloadException(CSR_NULL_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + } + + //------------------------------------------------------------------------------------------------- + private String getServerCloudCN() { + final String serverCN = (String) arrowheadContext.get(CommonConstants.SERVER_COMMON_NAME); + final String[] serverFields = serverCN.split("\\.", 2); // serverFields contains: coreSystemName, cloudName.operator.arrowhead.eu + Assert.isTrue(serverFields.length >= 2, "Server common name is invalid: " + serverCN); + + return serverFields[1]; + } +} \ No newline at end of file diff --git a/onboarding/src/main/java/eu/arrowhead/core/onboarding/OnboardingMain.java b/onboarding/src/main/java/eu/arrowhead/core/onboarding/OnboardingMain.java new file mode 100644 index 000000000..a043735eb --- /dev/null +++ b/onboarding/src/main/java/eu/arrowhead/core/onboarding/OnboardingMain.java @@ -0,0 +1,26 @@ +package eu.arrowhead.core.onboarding; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.database.repository.RefreshableRepositoryImpl; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@SpringBootApplication(scanBasePackages = CommonConstants.BASE_PACKAGE) +@EntityScan(CoreCommonConstants.DATABASE_ENTITY_PACKAGE) +@EnableJpaRepositories(basePackages = CoreCommonConstants.DATABASE_REPOSITORY_PACKAGE, repositoryBaseClass = RefreshableRepositoryImpl.class) +@EnableSwagger2 +public class OnboardingMain +{ + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public static void main(final String[] args) { + SpringApplication.run(OnboardingMain.class, args); + } +} diff --git a/onboarding/src/main/java/eu/arrowhead/core/onboarding/security/OnboardingAccessControlFilter.java b/onboarding/src/main/java/eu/arrowhead/core/onboarding/security/OnboardingAccessControlFilter.java new file mode 100644 index 000000000..154c9e515 --- /dev/null +++ b/onboarding/src/main/java/eu/arrowhead/core/onboarding/security/OnboardingAccessControlFilter.java @@ -0,0 +1,71 @@ +package eu.arrowhead.core.onboarding.security; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.SecurityUtilities; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.common.exception.AuthException; +import eu.arrowhead.common.filter.thirdparty.MultiReadRequestWrapper; +import eu.arrowhead.common.security.CoreSystemAccessControlFilter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; + +import javax.servlet.FilterChain; +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.Map; + +import static eu.arrowhead.common.CommonConstants.ONBOARDING_AUTH_WITH_SHARED_SECRET_URI; + +@Component +@ConditionalOnProperty(name = CommonConstants.SERVER_SSL_ENABLED, matchIfMissing = true) +public class OnboardingAccessControlFilter extends CoreSystemAccessControlFilter { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Override + public void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws IOException, ServletException { + if (request instanceof HttpServletRequest) { + log.debug("Checking access in OnboardingAccessControlFilter..."); + try { + final MultiReadRequestWrapper requestWrapper = new MultiReadRequestWrapper((HttpServletRequest) request); + final String requestTarget = Utilities.stripEndSlash(requestWrapper.getRequestURL().toString()); + + if (requestTarget.contains(CoreCommonConstants.MGMT_URI)) { + // Only the local System Operator can use these methods + final String cloudCN = getServerCloudCN(); + final String clientCN = SecurityUtilities.getCertificateCNFromRequest(requestWrapper); + + checkIfLocalSystemOperator(clientCN, cloudCN, requestTarget); + } + + log.debug("Using MultiReadRequestWrapper in the filter chain from now..."); + chain.doFilter(requestWrapper, response); + } catch (final ArrowheadException ex) { + handleException(ex, response); + } + } else { + chain.doFilter(request, response); + } + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + @Override + protected void checkClientAuthorized(final String clientCN, final String method, final String requestTarget, final String requestJSON, final Map queryParams) { + final String cloudCN = getServerCloudCN(); + if (requestTarget.contains(CoreCommonConstants.MGMT_URI)) { + // Only the local System Operator can use these methods + checkIfLocalSystemOperator(clientCN, cloudCN, requestTarget); + } + } +} \ No newline at end of file diff --git a/onboarding/src/main/java/eu/arrowhead/core/onboarding/security/OnboardingSecurityConfig.java b/onboarding/src/main/java/eu/arrowhead/core/onboarding/security/OnboardingSecurityConfig.java new file mode 100644 index 000000000..21eb5d4d1 --- /dev/null +++ b/onboarding/src/main/java/eu/arrowhead/core/onboarding/security/OnboardingSecurityConfig.java @@ -0,0 +1,11 @@ +package eu.arrowhead.core.onboarding.security; + +import eu.arrowhead.common.security.DefaultSecurityConfig; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + +@Configuration +@EnableWebSecurity +public class OnboardingSecurityConfig extends DefaultSecurityConfig { + +} \ No newline at end of file diff --git a/onboarding/src/main/java/eu/arrowhead/core/onboarding/service/OnboardingService.java b/onboarding/src/main/java/eu/arrowhead/core/onboarding/service/OnboardingService.java new file mode 100644 index 000000000..f0b7f7360 --- /dev/null +++ b/onboarding/src/main/java/eu/arrowhead/core/onboarding/service/OnboardingService.java @@ -0,0 +1,143 @@ +package eu.arrowhead.core.onboarding.service; + +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.SecurityUtilities; +import eu.arrowhead.common.core.CoreSystemService; +import eu.arrowhead.common.drivers.CertificateAuthorityDriver; +import eu.arrowhead.common.drivers.DriverUtilities; +import eu.arrowhead.common.drivers.OrchestrationDriver; +import eu.arrowhead.common.dto.internal.CertificateSigningRequestDTO; +import eu.arrowhead.common.dto.internal.CertificateSigningResponseDTO; +import eu.arrowhead.common.dto.shared.CertificateCreationRequestDTO; +import eu.arrowhead.common.dto.shared.CertificateCreationResponseDTO; +import eu.arrowhead.common.dto.shared.CertificateType; +import eu.arrowhead.common.dto.shared.OnboardingResponseDTO; +import eu.arrowhead.common.dto.shared.OnboardingWithCsrRequestDTO; +import eu.arrowhead.common.dto.shared.OnboardingWithCsrResponseDTO; +import eu.arrowhead.common.dto.shared.OnboardingWithNameRequestDTO; +import eu.arrowhead.common.dto.shared.OnboardingWithNameResponseDTO; +import eu.arrowhead.common.dto.shared.ServiceEndpoint; +import eu.arrowhead.common.exception.ArrowheadException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.Assert; +import org.springframework.web.util.UriComponents; + +import java.security.KeyPair; +import java.util.function.Consumer; + +@Service +public class OnboardingService { + + //================================================================================================= + // members + private final Logger logger = LogManager.getLogger(OnboardingService.class); + private final OrchestrationDriver orchestrationDriver; + private final CertificateAuthorityDriver caDriver; + private final SecurityUtilities securityUtilities; + + @Autowired + public OnboardingService(final OrchestrationDriver orchestrationDriver, + final CertificateAuthorityDriver caDriver, + final SecurityUtilities securityUtilities) { + this.orchestrationDriver = orchestrationDriver; + this.caDriver = caDriver; + this.securityUtilities = securityUtilities; + } + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public OnboardingWithNameResponseDTO onboarding(final OnboardingWithNameRequestDTO onboardingRequest, final String host, final String address) + throws DriverUtilities.DriverException { + logger.debug("onboarding started..."); + Assert.notNull(onboardingRequest, "OnboardingWithNameRequestDTO must not be null"); + Assert.notNull(onboardingRequest.getCreationRequestDTO(), "CreationRequestDTO must not be null"); + + final CertificateCreationRequestDTO creationRequestDTO = onboardingRequest.getCreationRequestDTO(); + final KeyPair keyPair = securityUtilities.extractOrGenerateKeyPair(creationRequestDTO); + final String certificateSigningRequest; + + try { + certificateSigningRequest = securityUtilities.createCertificateSigningRequest(creationRequestDTO.getCommonName(), keyPair, + CertificateType.AH_ONBOARDING, host, address); + } catch (Exception e) { + logger.error(e.getMessage(), e); + throw new ArrowheadException("Unable to create certificate signing request: " + e.getMessage()); + } + + final var signingResponseDTO = executeCertificateSigningRequest(certificateSigningRequest); + final var responseDto = new OnboardingWithNameResponseDTO(); + enrichCaResult(responseDto, signingResponseDTO); + enrichEndpoints(responseDto); + + final CertificateCreationResponseDTO onboardingCertificate = responseDto.getOnboardingCertificate(); + onboardingCertificate.setKeyPairDTO(securityUtilities.encodeKeyPair(keyPair)); + + return responseDto; + } + + //------------------------------------------------------------------------------------------------- + public OnboardingWithCsrResponseDTO onboarding(final OnboardingWithCsrRequestDTO onboardingRequest) + throws DriverUtilities.DriverException { + logger.debug("onboarding started..."); + Assert.notNull(onboardingRequest, "OnboardingWithCsrRequestDTO must not be null"); + Assert.notNull(onboardingRequest.getCertificateSigningRequest(), "CertificateSigningRequest must not be null"); + + final var signingResponseDTO = executeCertificateSigningRequest(onboardingRequest.getCertificateSigningRequest()); + final var responseDto = new OnboardingWithCsrResponseDTO(); + enrichCaResult(responseDto, signingResponseDTO); + enrichEndpoints(responseDto); + + final var onboardingCertificate = responseDto.getOnboardingCertificate(); + securityUtilities.extractAndSetPublicKey(onboardingCertificate); + + return responseDto; + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + private CertificateSigningResponseDTO executeCertificateSigningRequest(final String certificateSigningRequest) throws DriverUtilities.DriverException { + logger.debug("Contact CertificateAuthority ..."); + final var csrDTO = new CertificateSigningRequestDTO(certificateSigningRequest); + return caDriver.signCertificate(csrDTO); + } + + private void enrichCaResult(final T responseDTO, final CertificateSigningResponseDTO csrResult) { + logger.debug("Processing response from Certificate Authority ..."); + final CertificateCreationResponseDTO certificateResponseDTO = new CertificateCreationResponseDTO(); + certificateResponseDTO.setCertificate(csrResult.getCertificateChain().get(0)); + certificateResponseDTO.setCertificateFormat(CoreCommonConstants.CERTIFICATE_FORMAT); + certificateResponseDTO.setCertificateType(CertificateType.AH_ONBOARDING); + + responseDTO.setOnboardingCertificate(certificateResponseDTO); + responseDTO.setIntermediateCertificate(csrResult.getCertificateChain().get(1)); + responseDTO.setRootCertificate(csrResult.getCertificateChain().get(2)); + } + + private void enrichEndpoints(final OnboardingWithNameResponseDTO responseDTO) throws DriverUtilities.DriverException { + orchestrateAndSet(responseDTO::setDeviceRegistry, CoreSystemService.DEVICE_REGISTRY_ONBOARDING_WITH_NAME_SERVICE); + orchestrateAndSet(responseDTO::setSystemRegistry, CoreSystemService.SYSTEM_REGISTRY_ONBOARDING_WITH_NAME_SERVICE); + orchestrateAndSet(responseDTO::setServiceRegistry, CoreSystemService.SERVICE_REGISTRY_REGISTER_SERVICE); + orchestrateAndSet(responseDTO::setOrchestrationService, CoreSystemService.ORCHESTRATION_SERVICE); + } + + private void enrichEndpoints(final OnboardingWithCsrResponseDTO responseDTO) throws DriverUtilities.DriverException { + orchestrateAndSet(responseDTO::setDeviceRegistry, CoreSystemService.DEVICE_REGISTRY_ONBOARDING_WITH_CSR_SERVICE); + orchestrateAndSet(responseDTO::setSystemRegistry, CoreSystemService.SYSTEM_REGISTRY_ONBOARDING_WITH_CSR_SERVICE); + orchestrateAndSet(responseDTO::setServiceRegistry, CoreSystemService.SERVICE_REGISTRY_REGISTER_SERVICE); + orchestrateAndSet(responseDTO::setOrchestrationService, CoreSystemService.ORCHESTRATION_SERVICE); + } + + private void orchestrateAndSet(final Consumer consumer, + final CoreSystemService coreSystemService) throws DriverUtilities.DriverException { + logger.debug("Orchestrating '{}' ...", coreSystemService.getServiceDefinition()); + final UriComponents service = orchestrationDriver.findCoreSystemService(coreSystemService); + consumer.accept(new ServiceEndpoint(coreSystemService, service.toUri())); + } +} diff --git a/onboarding/src/main/java/eu/arrowhead/core/onboarding/swagger/OnboardingSwaggerConfig.java b/onboarding/src/main/java/eu/arrowhead/core/onboarding/swagger/OnboardingSwaggerConfig.java new file mode 100644 index 000000000..b642cb974 --- /dev/null +++ b/onboarding/src/main/java/eu/arrowhead/core/onboarding/swagger/OnboardingSwaggerConfig.java @@ -0,0 +1,27 @@ +package eu.arrowhead.core.onboarding.swagger; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.swagger.DefaultSwaggerConfig; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@EnableSwagger2 +@Configuration +public class OnboardingSwaggerConfig extends DefaultSwaggerConfig { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public OnboardingSwaggerConfig() { + super(CommonConstants.CORE_SYSTEM_ONBOARDING); + } + + //------------------------------------------------------------------------------------------------- + @Bean + public Docket customizeSwagger() { + return configureSwaggerForCoreSystem(this.getClass().getPackageName()); + } +} \ No newline at end of file diff --git a/onboarding/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/onboarding/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..16e979ed4 --- /dev/null +++ b/onboarding/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,27 @@ +{"properties": [ + { + "name": "disable.hostname.verifier", + "type": "java.lang.Boolean", + "description": "A description for 'disable.hostname.verifier'" + }, + { + "name": "log_all_request_and_response", + "type": "java.lang.Boolean", + "description": "A description for 'log_all_request_and_response'" + }, + { + "name": "core_system_name", + "type": "java.lang.String", + "description": "A description for 'core_system_name'" + }, + { + "name": "domain.name", + "type": "java.lang.String", + "description": "A description for 'domain.name'" + }, + { + "name": "domain.port", + "type": "java.lang.Integer", + "description": "A description for 'domain.port'" + } +]} \ No newline at end of file diff --git a/onboarding/src/main/resources/application.properties b/onboarding/src/main/resources/application.properties new file mode 100644 index 000000000..d7f253a24 --- /dev/null +++ b/onboarding/src/main/resources/application.properties @@ -0,0 +1,60 @@ +############################################ +### APPLICATION PARAMETERS ### +############################################ + +# Database connection (mandatory) +# Change the server timezone if necessary +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/arrowhead?serverTimezone=Europe/Budapest +spring.datasource.username=onboarding_controller +spring.datasource.password=JKgh1as5f6oi7aV +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +# use true only for debugging +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.hibernate.ddl-auto=none + +# Onboarding Controller web-server parameters +server.address=127.0.0.1 +server.port=8435 +domain.name=127.0.0.1 +domain.port=8435 + +############################################ +### CUSTOM PARAMETERS ### +############################################ + +# Name of the core system +core_system_name=ONBOARDING_CONTROLLER + +# Show all request/response in debug log +log_all_request_and_response=false + +# Service Registry web-server parameters (to register the Authorization services) +sr_address=127.0.0.1 +sr_port=8443 + +############################################ +### SECURE MODE ### +############################################ + +# configure shared secret. comment to disable +sharedSecret=hidden_secret + +# Set this to false to disable https mode +server.ssl.enabled=true + +server.ssl.key-store-type=PKCS12 +server.ssl.key-store=classpath:certificates/onboarding_controller.p12 +server.ssl.key-store-password=123456 +server.ssl.key-alias=onboarding_controller +server.ssl.key-password=123456 +server.ssl.client-auth=want +server.ssl.trust-store-type=PKCS12 +server.ssl.trust-store=classpath:certificates/truststore.p12 +server.ssl.trust-store-password=123456 + +#If true, http client does not check whether the hostname is match one of the server's SAN in its certificate +#Just for testing, DO NOT USE this feature in production environment +disable.hostname.verifier=false diff --git a/onboarding/src/main/resources/banner.txt b/onboarding/src/main/resources/banner.txt new file mode 100644 index 000000000..82fe4e6b5 --- /dev/null +++ b/onboarding/src/main/resources/banner.txt @@ -0,0 +1,8 @@ +=========================================================================== + _____ _____ ______ ___ _ ______ _____ + /\ | __ \| __ \ / __ \ \ / / | | | ____| /\ | __ \ + / \ | |__) | |__) | | | \ \ /\ / /| |__| | |__ / \ | | | | + / /\ \ | _ /| _ /| | | |\ \/ \/ / | __ | __| / /\ \ | | | | + / ____ \| | \ \| | \ \| |__| | \ /\ / | | | | |____ / ____ \| |__| | + /_/ \_\_| \_\_| \_\\____/ \/ \/ |_| |_|______/_/ \_\_____/ +=========================================================================== \ No newline at end of file diff --git a/onboarding/src/main/resources/certificates/onboarding_controller.p12 b/onboarding/src/main/resources/certificates/onboarding_controller.p12 new file mode 100644 index 000000000..cbfcb32b1 Binary files /dev/null and b/onboarding/src/main/resources/certificates/onboarding_controller.p12 differ diff --git a/onboarding/src/main/resources/certificates/truststore.p12 b/onboarding/src/main/resources/certificates/truststore.p12 new file mode 100644 index 000000000..57c1c5f43 Binary files /dev/null and b/onboarding/src/main/resources/certificates/truststore.p12 differ diff --git a/onboarding/src/main/resources/log4j2.xml b/onboarding/src/main/resources/log4j2.xml new file mode 100644 index 000000000..ee4008a2c --- /dev/null +++ b/onboarding/src/main/resources/log4j2.xml @@ -0,0 +1,49 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex + + INFO + DEBUG + INFO + . + + + + + + + + ${LOG_PATTERN} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/onboarding/src/main/resources/swagger/swagger-ui.html b/onboarding/src/main/resources/swagger/swagger-ui.html new file mode 100644 index 000000000..7c468dfce --- /dev/null +++ b/onboarding/src/main/resources/swagger/swagger-ui.html @@ -0,0 +1,75 @@ + + + + + + Onboarding Controller + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/onboarding/src/test/java/eu/arrowhead/core/onboarding/OnboardingControllerTest.java b/onboarding/src/test/java/eu/arrowhead/core/onboarding/OnboardingControllerTest.java new file mode 100644 index 000000000..f2aaa7e0b --- /dev/null +++ b/onboarding/src/test/java/eu/arrowhead/core/onboarding/OnboardingControllerTest.java @@ -0,0 +1,81 @@ +package eu.arrowhead.core.onboarding; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import com.fasterxml.jackson.databind.ObjectMapper; +import eu.arrowhead.common.database.service.CommonDBService; +import eu.arrowhead.core.onboarding.service.OnboardingService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +@RunWith(SpringRunner.class) +@SpringBootTest//(classes = OnboardingMain.class) +@ContextConfiguration(classes = {OnboardingTestContext.class}) +public class OnboardingControllerTest { + + + //================================================================================================= + // members + + @Autowired + private WebApplicationContext wac; + + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean(name = "mockOnboardingDBService") + private OnboardingService onboardingDBService; + + @MockBean(name = "mockCommonDBService") + private CommonDBService commonDBService; + + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Before + public void setup() { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } + + //================================================================================================= + // Tests of onboarding controller + + @Test + public void echoOnboarding() throws Exception { + final MvcResult response = this.mockMvc.perform(get("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/onboarding/echo") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + assertEquals("Got it!", response.getResponse().getContentAsString()); + } + + @Test + public void onboardWithName() { + } + + @Test + public void onboardWithCsr() { + } +} \ No newline at end of file diff --git a/onboarding/src/test/java/eu/arrowhead/core/onboarding/OnboardingTestContext.java b/onboarding/src/test/java/eu/arrowhead/core/onboarding/OnboardingTestContext.java new file mode 100644 index 000000000..7940d5c71 --- /dev/null +++ b/onboarding/src/test/java/eu/arrowhead/core/onboarding/OnboardingTestContext.java @@ -0,0 +1,42 @@ +package eu.arrowhead.core.onboarding; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.database.service.CommonDBService; +import eu.arrowhead.core.onboarding.service.OnboardingService; +import org.mockito.Mockito; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.Primary; + +@Configuration +@ComponentScan(basePackages = CommonConstants.BASE_PACKAGE, + excludeFilters = { + @ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*database.*"), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = OnboardingMain.class), + }) +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) +public class OnboardingTestContext { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Bean + @Primary // This bean is primary only in test context + public OnboardingService mockOnboardingDBService() { + return Mockito.mock(OnboardingService.class); + } + + //------------------------------------------------------------------------------------------------- + @Bean + @Primary // This bean is primary only in test context + public CommonDBService mockCommonDBService() { + return Mockito.mock(CommonDBService.class); + } +} \ No newline at end of file diff --git a/onboarding/src/test/java/eu/arrowhead/core/onboarding/StandaloneModeInOnboardingTests.java b/onboarding/src/test/java/eu/arrowhead/core/onboarding/StandaloneModeInOnboardingTests.java new file mode 100644 index 000000000..1924b893e --- /dev/null +++ b/onboarding/src/test/java/eu/arrowhead/core/onboarding/StandaloneModeInOnboardingTests.java @@ -0,0 +1,9 @@ +package eu.arrowhead.core.onboarding; + +import eu.arrowhead.common.testhelper.StandaloneModeInTests; +import org.springframework.stereotype.Component; + +@Component +public class StandaloneModeInOnboardingTests extends StandaloneModeInTests { + +} \ No newline at end of file diff --git a/onboarding/src/test/resources/log4j2.xml b/onboarding/src/test/resources/log4j2.xml new file mode 100644 index 000000000..4271b64a2 --- /dev/null +++ b/onboarding/src/test/resources/log4j2.xml @@ -0,0 +1,31 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex + + OFF + + + + + + + + ${LOG_PATTERN} + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/orchestrator/.classpath b/orchestrator/.classpath index 01997bb0d..e210343c4 100644 --- a/orchestrator/.classpath +++ b/orchestrator/.classpath @@ -45,5 +45,19 @@
+ + + + + + + + + + + + + + diff --git a/orchestrator/pom.xml b/orchestrator/pom.xml index 051dfe016..a2ef22e72 100644 --- a/orchestrator/pom.xml +++ b/orchestrator/pom.xml @@ -10,7 +10,7 @@ jar Arrowhead Orchestrator Arrowhead Orchestrator core service - + eu.arrowhead @@ -18,7 +18,7 @@ ${revision} - + diff --git a/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/OrchestratorApplicationInitListener.java b/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/OrchestratorApplicationInitListener.java index ef13b43b3..5e137cd62 100644 --- a/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/OrchestratorApplicationInitListener.java +++ b/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/OrchestratorApplicationInitListener.java @@ -1,5 +1,6 @@ package eu.arrowhead.core.orchestrator; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -21,6 +22,9 @@ import eu.arrowhead.core.orchestrator.matchmaking.InterCloudProviderMatchmakingAlgorithm; import eu.arrowhead.core.orchestrator.matchmaking.IntraCloudProviderMatchmakingAlgorithm; import eu.arrowhead.core.orchestrator.matchmaking.RandomIntraCloudProviderMatchmaker; +import eu.arrowhead.core.qos.manager.QoSManager; +import eu.arrowhead.core.qos.manager.impl.DummyQoSManager; +import eu.arrowhead.core.qos.manager.impl.QoSManagerImpl; @Component public class OrchestratorApplicationInitListener extends ApplicationInitListener { @@ -31,6 +35,9 @@ public class OrchestratorApplicationInitListener extends ApplicationInitListener @Value(CoreCommonConstants.$ORCHESTRATOR_IS_GATEKEEPER_PRESENT_WD) private boolean gatekeeperIsPresent; + @Value(CoreCommonConstants.$QOS_ENABLED_WD) + private boolean qosEnabled; + //================================================================================================= // methods @@ -51,6 +58,12 @@ public InterCloudProviderMatchmakingAlgorithm getInterCloudProviderMatchmaker() public CloudMatchmakingAlgorithm getCloudMatchmaker() { return new DefaultCloudMatchmaker(); } + + //------------------------------------------------------------------------------------------------- + @Bean(CoreCommonConstants.QOS_MANAGER) + public QoSManager getQoSManager() { + return qosEnabled ? new QoSManagerImpl() : new DummyQoSManager(); + } //================================================================================================= // assistant methods @@ -58,12 +71,20 @@ public CloudMatchmakingAlgorithm getCloudMatchmaker() { //------------------------------------------------------------------------------------------------- @Override protected List getRequiredCoreSystemServiceUris() { + final List result = new ArrayList<>(5); + result.add(CoreSystemService.AUTH_TOKEN_GENERATION_SERVICE); + result.add(CoreSystemService.AUTH_CONTROL_INTRA_SERVICE); + if (gatekeeperIsPresent) { - return List.of(CoreSystemService.AUTH_TOKEN_GENERATION_SERVICE, CoreSystemService.AUTH_CONTROL_INTRA_SERVICE, CoreSystemService.GATEKEEPER_GLOBAL_SERVICE_DISCOVERY, - CoreSystemService.GATEKEEPER_INTER_CLOUD_NEGOTIATION); + result.add(CoreSystemService.GATEKEEPER_GLOBAL_SERVICE_DISCOVERY); + result.add(CoreSystemService.GATEKEEPER_INTER_CLOUD_NEGOTIATION); + } + + if (qosEnabled) { + result.add(CoreSystemService.QOS_MONITOR_PING_MEASUREMENT_SERVICE); } - return List.of(CoreSystemService.AUTH_TOKEN_GENERATION_SERVICE, CoreSystemService.AUTH_CONTROL_INTRA_SERVICE); + return result; } //------------------------------------------------------------------------------------------------- diff --git a/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/OrchestratorStoreController.java b/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/OrchestratorStoreController.java index 39e27b985..2f5f64356 100644 --- a/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/OrchestratorStoreController.java +++ b/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/OrchestratorStoreController.java @@ -122,7 +122,7 @@ public class OrchestratorStoreController { final ValidatedPageParams vpp = CoreUtilities.validatePageParameters(page, size, direction, CommonConstants.ORCHESTRATOR_URI + CoreCommonConstants.ORCHESTRATOR_STORE_MGMT_URI); final OrchestratorStoreListResponseDTO orchestratorStoreListResponse = orchestratorStoreDBService.getOrchestratorStoreEntriesResponse(vpp.getValidatedPage(), vpp.getValidatedSize(), - vpp.getValidatedDirecion(), sortField); + vpp.getValidatedDirection(), sortField); logger.debug("OrchestratorStores with page: {} and item_per page: {} retrieved successfully", page, size); return orchestratorStoreListResponse; @@ -147,7 +147,7 @@ public class OrchestratorStoreController { final ValidatedPageParams vpp = CoreUtilities.validatePageParameters(page, size, direction, CommonConstants.ORCHESTRATOR_URI + ORCHESTRATOR_STORE_MGMT_ALL_TOP_PRIORITY); final OrchestratorStoreListResponseDTO orchestratorStoreResponse = orchestratorStoreDBService.getAllTopPriorityOrchestratorStoreEntriesResponse(vpp.getValidatedPage(), vpp.getValidatedSize(), - vpp.getValidatedDirecion(), sortField); + vpp.getValidatedDirection(), sortField); logger.debug("OrchestratorStores with page: {} and item_per page: {} retrieved successfully", page, size); return orchestratorStoreResponse; @@ -174,7 +174,7 @@ public class OrchestratorStoreController { final ValidatedPageParams vpp = CoreUtilities.validatePageParameters(page, size, direction, CommonConstants.ORCHESTRATOR_URI + ORCHESTRATOR_STORE_MGMT_ALL_BY_CONSUMER); checkOrchestratorStoreRequestDTOForConsumerIdAndServiceDefinitionName(request, CommonConstants.ORCHESTRATOR_URI + ORCHESTRATOR_STORE_MGMT_ALL_BY_CONSUMER); final OrchestratorStoreListResponseDTO orchestratorStoreResponse = orchestratorStoreDBService.getOrchestratorStoresByConsumerResponse(vpp.getValidatedPage(), vpp.getValidatedSize(), - vpp.getValidatedDirecion(), sortField, + vpp.getValidatedDirection(), sortField, request.getConsumerSystemId(), request.getServiceDefinitionName(), request.getServiceInterfaceName()); diff --git a/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/matchmaking/DefaultIntraCloudProviderMatchmaker.java b/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/matchmaking/DefaultIntraCloudProviderMatchmaker.java index e29a27ec1..8dd338485 100644 --- a/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/matchmaking/DefaultIntraCloudProviderMatchmaker.java +++ b/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/matchmaking/DefaultIntraCloudProviderMatchmaker.java @@ -7,8 +7,8 @@ import org.springframework.util.Assert; import eu.arrowhead.common.dto.internal.DTOUtilities; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; import eu.arrowhead.common.dto.shared.PreferredProviderDataDTO; -import eu.arrowhead.common.dto.shared.ServiceRegistryResponseDTO; public class DefaultIntraCloudProviderMatchmaker implements IntraCloudProviderMatchmakingAlgorithm { @@ -25,28 +25,28 @@ public class DefaultIntraCloudProviderMatchmaker implements IntraCloudProviderMa * This algorithm returns the first (preferred) provider. */ @Override - public ServiceRegistryResponseDTO doMatchmaking(final List srList, final IntraCloudProviderMatchmakingParameters params) { + public OrchestrationResultDTO doMatchmaking(final List orList, final IntraCloudProviderMatchmakingParameters params) { logger.debug("DefaultIntraCloudProviderMatchmaker.doMatchmaking started..."); - Assert.isTrue(srList != null && !srList.isEmpty(), "srList is null or empty."); + Assert.isTrue(orList != null && !orList.isEmpty(), "orList is null or empty."); Assert.notNull(params, "params is null"); if (params.getPreferredLocalProviders().isEmpty()) { - logger.debug("No preferred provider is specified, the first one in the SR list is selected."); - return srList.get(0); + logger.debug("No preferred provider is specified, the first one in the list is selected."); + return orList.get(0); } - for (final ServiceRegistryResponseDTO srResult : srList) { + for (final OrchestrationResultDTO orResult : orList) { for (final PreferredProviderDataDTO provider : params.getPreferredLocalProviders()) { - if (DTOUtilities.equalsSystemInResponseAndRequest(srResult.getProvider(), provider.getProviderSystem())) { - logger.debug("The first preferred provider found in SR is selected."); - return srResult; + if (DTOUtilities.equalsSystemInResponseAndRequest(orResult.getProvider(), provider.getProviderSystem())) { + logger.debug("The first preferred provider found in the list is selected."); + return orResult; } } } logger.debug("no match was found between preferred providers, the first one is selected."); - return srList.get(0); + return orList.get(0); } } \ No newline at end of file diff --git a/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/matchmaking/IntraCloudProviderMatchmakingAlgorithm.java b/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/matchmaking/IntraCloudProviderMatchmakingAlgorithm.java index 01117dfda..ac5d27f7b 100644 --- a/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/matchmaking/IntraCloudProviderMatchmakingAlgorithm.java +++ b/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/matchmaking/IntraCloudProviderMatchmakingAlgorithm.java @@ -2,7 +2,7 @@ import java.util.List; -import eu.arrowhead.common.dto.shared.ServiceRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; public interface IntraCloudProviderMatchmakingAlgorithm { @@ -10,5 +10,5 @@ public interface IntraCloudProviderMatchmakingAlgorithm { // methods //------------------------------------------------------------------------------------------------- - public ServiceRegistryResponseDTO doMatchmaking(final List srList, final IntraCloudProviderMatchmakingParameters params); + public OrchestrationResultDTO doMatchmaking(final List orList, final IntraCloudProviderMatchmakingParameters params); } \ No newline at end of file diff --git a/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/matchmaking/RandomIntraCloudProviderMatchmaker.java b/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/matchmaking/RandomIntraCloudProviderMatchmaker.java index 6eeb6fc20..f885976da 100644 --- a/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/matchmaking/RandomIntraCloudProviderMatchmaker.java +++ b/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/matchmaking/RandomIntraCloudProviderMatchmaker.java @@ -8,8 +8,8 @@ import org.springframework.util.Assert; import eu.arrowhead.common.dto.internal.DTOUtilities; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; import eu.arrowhead.common.dto.shared.PreferredProviderDataDTO; -import eu.arrowhead.common.dto.shared.ServiceRegistryResponseDTO; public class RandomIntraCloudProviderMatchmaker implements IntraCloudProviderMatchmakingAlgorithm { @@ -28,10 +28,10 @@ public class RandomIntraCloudProviderMatchmaker implements IntraCloudProviderMat * This algorithm returns the first (preferred) provider. */ @Override - public ServiceRegistryResponseDTO doMatchmaking(final List srList, final IntraCloudProviderMatchmakingParameters params) { + public OrchestrationResultDTO doMatchmaking(final List orList, final IntraCloudProviderMatchmakingParameters params) { logger.debug("RandomIntraCloudProviderMatchmaker.doMatchmaking started..."); - Assert.isTrue(srList != null && !srList.isEmpty(), "srList is null or empty."); + Assert.isTrue(orList != null && !orList.isEmpty(), "orList is null or empty."); Assert.notNull(params, "params is null"); if (rng == null) { @@ -39,21 +39,21 @@ public ServiceRegistryResponseDTO doMatchmaking(final List generateAuthTokens(final OrchestrationFormRe final UriComponents tokenGenerationUri = getAuthTokenGenerationUri(); for (final TokenGenHelper helper : tokenGenHelperList) { - final TokenGenerationRequestDTO payload = new TokenGenerationRequestDTO(request.getRequesterSystem(), request.getRequesterCloud(), helper.getProviders(), helper.getService(), - tokenDuration > 0 ? tokenDuration : null); + final TokenGenerationRequestDTO payload = new TokenGenerationRequestDTO(request.getRequesterSystem(), request.getRequesterCloud(), helper.getProviders(), helper.getService()); final ResponseEntity response = httpService.sendRequest(tokenGenerationUri, HttpMethod.POST, TokenGenerationResponseDTO.class, payload); final TokenGenerationResponseDTO tokenGenerationResult = response.getBody(); @@ -166,9 +182,8 @@ public ICNResultDTO doInterCloudNegotiation(final ICNRequestFormDTO icnForm) { return response.getBody(); } - //------------------------------------------------------------------------------------------------- - public GSDQueryResultDTO doGlobalServiceDiscovery(final GSDQueryFormDTO gsdForm ) { + public GSDQueryResultDTO doGlobalServiceDiscovery(final GSDQueryFormDTO gsdForm) { logger.debug("doGlobalServiceDiscovery started..."); Assert.notNull(gsdForm, "GSDPollRequestDTO is null."); @@ -178,6 +193,16 @@ public GSDQueryResultDTO doGlobalServiceDiscovery(final GSDQueryFormDTO gsdForm return response.getBody(); } + //------------------------------------------------------------------------------------------------- + public PingMeasurementResponseDTO getPingMeasurement(final long systemId) { + logger.debug("getPingMeasurement started..."); + + final UriComponents pingUri = getQosMonitorPingMeasurementUri(systemId); + final ResponseEntity response = httpService.sendRequest(pingUri, HttpMethod.GET, PingMeasurementResponseDTO.class); + + return response.getBody(); + } + //================================================================================================= // assistant methods @@ -286,6 +311,22 @@ private UriComponents getGatekeeperICNUri() { throw new ArrowheadException("Orchestrator can't find gatekeeper init_icn URI."); } + //------------------------------------------------------------------------------------------------- + private UriComponents getQosMonitorPingMeasurementUri(final long id) { + logger.debug("getQosMonitorPingMeasurementUri started..."); + + if (arrowheadContext.containsKey(QOS_MONITOR_PING_MEASUREMENT_URI_KEY)) { + try { + final UriComponents uri = (UriComponents) arrowheadContext.get(QOS_MONITOR_PING_MEASUREMENT_URI_KEY); + return uri.expand(id); + } catch (final ClassCastException ex) { + throw new ArrowheadException("Orchestrator can't find QoS Monitor ping/measurement URI."); + } + } + + throw new ArrowheadException("Orchestrator can't find gatekeeper init_icn URI."); + } + //------------------------------------------------------------------------------------------------- private List convertOrchestrationResultListToTokenGenHelperList(final List orList) { logger.debug("convertOrchestrationResultListToTokenGenHelperList started..."); @@ -315,7 +356,17 @@ private List convertOrchestrationResultListToTokenGenHelperList( private TokenGenerationProviderDTO createTokenGenerationProvider(final OrchestrationResultDTO result) { logger.debug("createTokenGenerationProvider started..."); - return new TokenGenerationProviderDTO(DTOConverter.convertSystemResponseDTOToSystemRequestDTO(result.getProvider()), + int tokenDuration = this.tokenDuration; + if (result.getMetadata() != null && result.getMetadata().containsKey(KEY_CALCULATED_SERVICE_TIME_FRAME)) { + try { + tokenDuration = Integer.parseInt(result.getMetadata().get(KEY_CALCULATED_SERVICE_TIME_FRAME)); + } catch (final NumberFormatException ex) { + logger.debug(ex.getMessage()); + logger.trace("Stacktrace:", ex); + } + } + + return new TokenGenerationProviderDTO(DTOConverter.convertSystemResponseDTOToSystemRequestDTO(result.getProvider()), tokenDuration, convertServiceInterfaceListToServiceInterfaceNameList(result.getInterfaces())); } @@ -380,7 +431,7 @@ private List convertServiceInterfaceListToServiceInterfaceIdList(final Lis // method may change providers list private void filterProviderListUsingAuthorizationResult(final List providers, final AuthorizationIntraCloudCheckResponseDTO authResult) { logger.debug("filterProviderListUsingAuthorizationResult started..."); - + if (authResult.getAuthorizedProviderIdsWithInterfaceIds().isEmpty()) { // consumer has no access to any of the specified providers providers.clear(); diff --git a/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/service/OrchestratorService.java b/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/service/OrchestratorService.java index 86002c40b..6ebda6249 100644 --- a/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/service/OrchestratorService.java +++ b/orchestrator/src/main/java/eu/arrowhead/core/orchestrator/service/OrchestratorService.java @@ -54,6 +54,7 @@ import eu.arrowhead.core.orchestrator.matchmaking.InterCloudProviderMatchmakingParameters; import eu.arrowhead.core.orchestrator.matchmaking.IntraCloudProviderMatchmakingAlgorithm; import eu.arrowhead.core.orchestrator.matchmaking.IntraCloudProviderMatchmakingParameters; +import eu.arrowhead.core.qos.manager.QoSManager; @Service public class OrchestratorService { @@ -66,7 +67,7 @@ public class OrchestratorService { private static final String LESS_THAN_ONE_ERROR_MESSAGE= " must be greater than zero."; private static final String MORE_THAN_ONE_ERROR_MESSAGE= " must not have more than one element."; - private static final int EXPIRING_TIME_IN_MINUTES = 2; + public static final int EXPIRING_TIME_IN_MINUTES = 2; private static final Logger logger = LogManager.getLogger(OrchestratorService.class); @@ -85,9 +86,18 @@ public class OrchestratorService { @Resource(name = CoreCommonConstants.CLOUD_MATCHMAKER) private CloudMatchmakingAlgorithm cloudMatchmaker; + @Resource(name = CoreCommonConstants.QOS_MANAGER) + private QoSManager qosManager; + @Value(CoreCommonConstants.$ORCHESTRATOR_IS_GATEKEEPER_PRESENT_WD) private boolean gateKeeperIsPresent; + @Value(CoreCommonConstants.$QOS_ENABLED_WD) + private boolean qosEnabled; + + @Value(CoreCommonConstants.$QOS_MAX_RESERVATION_DURATION_WD) + private int maxReservationDuration; // in seconds + //================================================================================================= // methods @@ -114,12 +124,22 @@ public OrchestrationResponseDTO externalServiceRequest(final OrchestrationFormRe queryData = removeNonPreferred(queryData, localProviders); } - logger.debug("externalServiceRequest finished with {} service providers.", queryData.size()); - return compileOrchestrationResponse(queryData, request); + List orList = compileOrchestrationResponse(queryData, request); + orList = qosManager.filterReservedProviders(orList, request.getRequesterSystem()); // to reduce the number of results before token generation + + // Generate the authorization tokens if it is requested based on the service security (modifies the orList) + orList = orchestratorDriver.generateAuthTokens(request, orList); + + orList = qosManager.filterReservedProviders(orList, request.getRequesterSystem()); // token generation can be slow, so we have to check for new reservations + + logger.debug("externalServiceRequest finished with {} service providers.", orList.size()); + + return new OrchestrationResponseDTO(orList); } //------------------------------------------------------------------------------------------------- + //TODO: handle qos (inter) public OrchestrationResponseDTO triggerInterCloud(final OrchestrationFormRequestDTO request) { logger.debug("triggerInterCloud started ..."); @@ -167,7 +187,15 @@ public OrchestrationResponseDTO topPriorityEntriesOrchestrationProcess(final Orc return new OrchestrationResponseDTO(); // empty response } - return compileOrchestrationResponse(crossCheckedEntryList, orchestrationFormRequestDTO); + List orList = compileOrchestrationResponse(crossCheckedEntryList, orchestrationFormRequestDTO); + orList = qosManager.filterReservedProviders(orList, orchestrationFormRequestDTO.getRequesterSystem()); // to reduce the number of results before token generation + + // Generate the authorization tokens if it is requested based on the service security (modifies the orList) + orList = orchestratorDriver.generateAuthTokens(orchestrationFormRequestDTO, orList); + + orList = qosManager.filterReservedProviders(orList, orchestrationFormRequestDTO.getRequesterSystem()); // token generation can be slow, so we have to check for new reservations + + return new OrchestrationResponseDTO(orList); } //------------------------------------------------------------------------------------------------- @@ -191,7 +219,11 @@ public OrchestrationResponseDTO orchestrationFromStore(final OrchestrationFormRe final List authorizedLocalServiceRegistryEntries = getAuthorizedServiceRegistryEntries(entryList, orchestrationFormRequestDTO); - return getHighestPriorityCurrentlyWorkingStoreEntryFromEntryList(orchestrationFormRequestDTO, entryList, authorizedLocalServiceRegistryEntries); + final OrchestrationResponseDTO result = getHighestPriorityCurrentlyWorkingStoreEntryFromEntryList(orchestrationFormRequestDTO, entryList, authorizedLocalServiceRegistryEntries); + + final List orList = qosManager.filterReservedProviders(result.getResponse(), orchestrationFormRequestDTO.getRequesterSystem()); + + return new OrchestrationResponseDTO(orList); } //------------------------------------------------------------------------------------------------- @@ -258,19 +290,64 @@ public OrchestrationResponseDTO dynamicOrchestration(final OrchestrationFormRequ } } + List orList = compileOrchestrationResponse(queryData, request); + orList = qosManager.filterReservedProviders(orList, request.getRequesterSystem()); + if (orList.isEmpty()) { + return new OrchestrationResponseDTO(); + } + + final boolean needReservation = qosEnabled && flags.get(Flag.ENABLE_QOS) && request.getCommands().containsKey(OrchestrationFormRequestDTO.QOS_COMMAND_EXCLUSIVITY); + + if (needReservation) { + orList = qosManager.reserveProvidersTemporarily(orList, request.getRequesterSystem()); + } + + if (flags.get(Flag.ENABLE_QOS)) { + orList = qosManager.verifyServices(orList, request); + if (orList.isEmpty()) { + return new OrchestrationResponseDTO(); + } + } + + if (!needReservation) { + orList = qosManager.filterReservedProviders(orList, request.getRequesterSystem()); + if (orList.isEmpty()) { + return new OrchestrationResponseDTO(); + } + } + + if (qosEnabled) { + // Generate the authorization tokens if it is requested based on the service security (modifies the orList) + orList = orchestratorDriver.generateAuthTokens(request, orList); + if (!needReservation) { + orList = qosManager.filterReservedProviders(orList, request.getRequesterSystem()); + if (orList.isEmpty()) { + return new OrchestrationResponseDTO(); + } + } + } + // If matchmaking is requested, we pick out 1 ServiceRegistryEntry entity from the list. if (flags.get(Flag.MATCHMAKING)) { final IntraCloudProviderMatchmakingParameters params = new IntraCloudProviderMatchmakingParameters(localProviders); // set additional parameters here if you use a different matchmaking algorithm - final ServiceRegistryResponseDTO selected = intraCloudProviderMatchmaker.doMatchmaking(queryData, params); - queryData.clear(); - queryData.add(selected); + final OrchestrationResultDTO selected = intraCloudProviderMatchmaker.doMatchmaking(orList, params); + if (needReservation) { + qosManager.confirmReservation(selected, orList, request.getRequesterSystem()); + } + orList.clear(); + orList.add(selected); } // all the filtering is done logger.debug("dynamicOrchestration finished with {} service providers.", queryData.size()); - return compileOrchestrationResponse(queryData, request); + if (!qosEnabled) { + // Generate the authorization tokens if it is requested based on the service security (modifies the orList) + orList = orchestratorDriver.generateAuthTokens(request, orList); + } + + return new OrchestrationResponseDTO(orList); } //------------------------------------------------------------------------------------------------- @@ -302,6 +379,17 @@ private void checkServiceRequestForm(final OrchestrationFormRequestDTO request, request.validateCrossParameterConstraints(); + if (qosEnabled && request.getOrchestrationFlags().get(Flag.ENABLE_QOS) && request.getCommands().containsKey(OrchestrationFormRequestDTO.QOS_COMMAND_EXCLUSIVITY)) { + try { + final int exclusivityTime = Integer.parseInt(request.getCommands().get(OrchestrationFormRequestDTO.QOS_COMMAND_EXCLUSIVITY)); + if (exclusivityTime <= 0 || exclusivityTime > maxReservationDuration) { + throw new InvalidParameterException("Exclusivity time must be specified in seconds. Valid interval: [1, " + maxReservationDuration + "]."); + } + } catch (final NumberFormatException ex) { + throw new InvalidParameterException("Exclusivity time is in the wrong format."); + } + } + // Requested service checkRequestedServiceForm(request.getRequestedService()); @@ -397,14 +485,17 @@ private List removeNonPreferred(final List srList, final OrchestrationFormRequestDTO request) { + private List compileOrchestrationResponse(final List srList, final OrchestrationFormRequestDTO request) { logger.debug("compileOrchestrationResponse started..."); List orList = new ArrayList<>(srList.size()); for (final ServiceRegistryResponseDTO entry : srList) { final OrchestrationResultDTO result = new OrchestrationResultDTO(entry.getProvider(), entry.getServiceDefinition(), entry.getServiceUri(), entry.getSecure(), entry.getMetadata(), entry.getInterfaces(), entry.getVersion()); - + + if(result.getMetadata() == null ) { + result.setMetadata( new HashMap<>()); + } if (request.getOrchestrationFlags().get(Flag.OVERRIDE_STORE)) { final List warnings = calculateOrchestratorWarnings(entry); result.setWarnings(warnings); @@ -412,12 +503,9 @@ private OrchestrationResponseDTO compileOrchestrationResponse(final List orList = compileOrchestrationResponse(List.of(serviceRegistryResponseDTO), request); + // Generate the authorization tokens if it is requested based on the service security (modifies the orList) + orList = orchestratorDriver.generateAuthTokens(request, orList); + + return new OrchestrationResponseDTO(orList); } } diff --git a/orchestrator/src/main/java/eu/arrowhead/core/qos/database/service/QoSReservationDBService.java b/orchestrator/src/main/java/eu/arrowhead/core/qos/database/service/QoSReservationDBService.java new file mode 100644 index 000000000..381135145 --- /dev/null +++ b/orchestrator/src/main/java/eu/arrowhead/core/qos/database/service/QoSReservationDBService.java @@ -0,0 +1,178 @@ +package eu.arrowhead.core.qos.database.service; + +import java.time.ZonedDateTime; +import java.util.List; +import java.util.Optional; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; + +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.database.entity.QoSReservation; +import eu.arrowhead.common.database.repository.QoSReservationRepository; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.core.orchestrator.service.OrchestratorDriver; + +@Service +public class QoSReservationDBService { + + //================================================================================================= + // members + + @Value(CoreCommonConstants.$QOS_RESERVATION_TEMP_LOCK_DURATION_WD) + private int lockDuration; // in seconds + + @Value(CoreCommonConstants.$QOS_MAX_RESERVATION_DURATION_WD) + private int maxReservationDuration; // in seconds + + private final Logger logger = LogManager.getLogger(QoSReservationDBService.class); + + @Autowired + private QoSReservationRepository qosReservationRepository; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public int releaseObsoleteReservations() { + logger.debug("releaseObsoleteReservations started ..."); + + try { + final ZonedDateTime now = ZonedDateTime.now(); + final List obsoletes = qosReservationRepository.findAllByReservedToLessThanEqual(now); + qosReservationRepository.deleteAll(obsoletes); + qosReservationRepository.flush(); + + return obsoletes.size(); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + public List getAllReservationsExceptMine(final String systemName, final String address, final int port) { + logger.debug("getAllReservationsExceptMine started ..."); + + Assert.isTrue(!Utilities.isEmpty(systemName), "'systemName' is null or empty."); + Assert.isTrue(!Utilities.isEmpty(address), "'address' is null or empty."); + + final String validatedSystemName = systemName.trim().toLowerCase(); + final String validatedAddress = address.trim().toLowerCase(); + + return qosReservationRepository.findAllByConsumerSystemNameNotOrConsumerAddressNotOrConsumerPortNot(validatedSystemName, validatedAddress, port); + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public void applyTemporaryLock(final String systemName, final String address, final int port, final OrchestrationResultDTO dto) { + logger.debug("applyTemporaryLock started ..."); + + Assert.isTrue(!Utilities.isEmpty(systemName), "'systemName' is null or empty."); + Assert.isTrue(!Utilities.isEmpty(address), "'address' is null or empty."); + Assert.notNull(dto, "'dto' is null."); + Assert.notNull(dto.getProvider(), "Provider is null."); + Assert.notNull(dto.getService(), "Service is null."); + + final ZonedDateTime reservedTo = ZonedDateTime.now().plusSeconds(lockDuration); + final QoSReservation reservation = new QoSReservation(dto.getProvider().getId(), dto.getService().getId(), systemName.trim().toLowerCase(), address.trim().toLowerCase(), port, + reservedTo, true); + try { + qosReservationRepository.saveAndFlush(reservation); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public void removeTemporaryLock(final OrchestrationResultDTO dto) { + logger.debug("removeTemporaryLock started ..."); + + Assert.notNull(dto, "'dto' is null."); + Assert.notNull(dto.getProvider(), "Provider is null."); + Assert.notNull(dto.getService(), "Service is null."); + + final Optional optReservation = qosReservationRepository.findByReservedProviderIdAndReservedServiceIdAndTemporaryLockTrue(dto.getProvider().getId(), + dto.getService().getId()); + if (optReservation.isEmpty()) { // maybe temporary lock is expired and removed + // do nothing + } else { + final QoSReservation reservation = optReservation.get(); + try { + qosReservationRepository.delete(reservation); + qosReservationRepository.flush(); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public void extendReservation(final OrchestrationResultDTO reserved, final SystemRequestDTO requester) { + logger.debug("extendReservation started ..."); + + Assert.notNull(reserved, "'reserved' is null."); + Assert.notNull(reserved.getProvider(), "Provider is null."); + Assert.notNull(reserved.getService(), "Service is null."); + Assert.notNull(requester, "'requester' is null."); + Assert.isTrue(!Utilities.isEmpty(requester.getSystemName()), "Requester system's name is null or empty."); + Assert.isTrue(!Utilities.isEmpty(requester.getAddress()), "Requester system's address is null or empty."); + Assert.notNull(requester.getPort(), "Requester system's port is null."); + + final Optional optReservation = qosReservationRepository.findByReservedProviderIdAndReservedServiceId(reserved.getProvider().getId(), reserved.getService().getId()); + QoSReservation reservation; + if (optReservation.isEmpty()) { // maybe temporary lock is expired and removed + reservation = new QoSReservation(reserved.getProvider().getId(), reserved.getService().getId(), requester.getSystemName().trim().toLowerCase(), + requester.getAddress().trim().toLowerCase(), requester.getPort(), + null, false); + } else { + reservation = optReservation.get(); + } + + reservation.setTemporaryLock(false); + reservation.setReservedTo(getReservationTime(reserved)); + try { + qosReservationRepository.saveAndFlush(reservation); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + private ZonedDateTime getReservationTime(final OrchestrationResultDTO dto) { + logger.debug("getReservationTime started ..."); + + final ZonedDateTime time = ZonedDateTime.now(); + + int seconds = maxReservationDuration; + if (dto.getMetadata() != null && dto.getMetadata().containsKey(OrchestratorDriver.KEY_CALCULATED_SERVICE_TIME_FRAME)) { + try { + final String calculatedTimeFrameStr = dto.getMetadata().remove(OrchestratorDriver.KEY_CALCULATED_SERVICE_TIME_FRAME); + final int calculatedTimeFrame = Integer.parseInt(calculatedTimeFrameStr); + seconds = Math.min(maxReservationDuration, calculatedTimeFrame); + } catch (final NumberFormatException ex) { + logger.debug(ex.getMessage()); + logger.trace("Stacktracke:", ex); + } + } + + return time.plusSeconds(seconds); + } +} \ No newline at end of file diff --git a/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/QoSManager.java b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/QoSManager.java new file mode 100644 index 000000000..051cf8b67 --- /dev/null +++ b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/QoSManager.java @@ -0,0 +1,24 @@ +package eu.arrowhead.core.qos.manager; + +import java.util.List; + +import eu.arrowhead.common.dto.shared.OrchestrationFormRequestDTO; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; + +public interface QoSManager { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + // verification-related + public List verifyServices(final List orList, final OrchestrationFormRequestDTO request); + + //------------------------------------------------------------------------------------------------- + // reservation-related + public List filterReservedProviders(final List orList, final SystemRequestDTO requester); + public List reserveProvidersTemporarily(final List orList, final SystemRequestDTO requester); // returns with the temp locked results + public void confirmReservation(final OrchestrationResultDTO selected, final List orList, final SystemRequestDTO requester); + +} \ No newline at end of file diff --git a/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/QoSVerifier.java b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/QoSVerifier.java new file mode 100644 index 000000000..a5dedabc5 --- /dev/null +++ b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/QoSVerifier.java @@ -0,0 +1,14 @@ +package eu.arrowhead.core.qos.manager; + +import java.util.Map; + +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; + +public interface QoSVerifier { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public boolean verify(final OrchestrationResultDTO result, final Map qosRequirements, final Map commands); +} \ No newline at end of file diff --git a/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/QoSVerifiers.java b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/QoSVerifiers.java new file mode 100644 index 000000000..662d0da27 --- /dev/null +++ b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/QoSVerifiers.java @@ -0,0 +1,32 @@ +package eu.arrowhead.core.qos.manager; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import eu.arrowhead.core.qos.manager.impl.PingRequirementsVerifier; +import eu.arrowhead.core.qos.manager.impl.ServiceTimeVerifier; + +@Configuration +public class QoSVerifiers { + + //================================================================================================= + // members + + public static final String SERVICE_TIME_VERIFIER = "serviceTimeVerifier"; + public static final String PING_REQUIREMENTS_VERIFIER = "pingRequirementsVerifier"; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Bean(SERVICE_TIME_VERIFIER) + public QoSVerifier getServiceTimeVerifier() { + return new ServiceTimeVerifier(); + } + + //------------------------------------------------------------------------------------------------- + @Bean(PING_REQUIREMENTS_VERIFIER) + public QoSVerifier getPingRequirementsVerifier() { + return new PingRequirementsVerifier(); + } +} \ No newline at end of file diff --git a/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/impl/DummyQoSManager.java b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/impl/DummyQoSManager.java new file mode 100644 index 000000000..c326e734d --- /dev/null +++ b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/impl/DummyQoSManager.java @@ -0,0 +1,38 @@ +package eu.arrowhead.core.qos.manager.impl; + +import java.util.List; + +import eu.arrowhead.common.dto.shared.OrchestrationFormRequestDTO; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; +import eu.arrowhead.core.qos.manager.QoSManager; + +public class DummyQoSManager implements QoSManager { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Override + public List filterReservedProviders(final List orList, final SystemRequestDTO requester) { + return orList; + } + + //------------------------------------------------------------------------------------------------- + @Override + public List reserveProvidersTemporarily(final List orList, final SystemRequestDTO requester) { + return orList; + } + + //------------------------------------------------------------------------------------------------- + @Override + public void confirmReservation(final OrchestrationResultDTO selected, final List orList, final SystemRequestDTO requester) { + // intentionally do nothing + } + + //------------------------------------------------------------------------------------------------- + @Override + public List verifyServices(final List orList, final OrchestrationFormRequestDTO request) { + return orList; + } +} \ No newline at end of file diff --git a/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/impl/PingRequirementsVerifier.java b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/impl/PingRequirementsVerifier.java new file mode 100644 index 000000000..71c7d2b56 --- /dev/null +++ b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/impl/PingRequirementsVerifier.java @@ -0,0 +1,258 @@ +package eu.arrowhead.core.qos.manager.impl; + +import java.time.ZonedDateTime; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.util.Assert; + +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.dto.internal.PingMeasurementResponseDTO; +import eu.arrowhead.common.dto.shared.OrchestrationFormRequestDTO; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; +import eu.arrowhead.common.exception.InvalidParameterException; +import eu.arrowhead.core.orchestrator.service.OrchestratorDriver; +import eu.arrowhead.core.qos.manager.QoSVerifier; + +public class PingRequirementsVerifier implements QoSVerifier { + + //================================================================================================= + // members + + @Value(CoreCommonConstants.$QOS_NOT_MEASURED_SYSTEM_VERIFY_RESULT) + private boolean verifyNotMeasuredSystem; // result of verify if a system has no ping records + + @Value(CoreCommonConstants.$QOS_PING_MEASUREMENT_CACHE_THRESHOLD_WD) + private int pingMeasurementCacheThreshold; + + @Autowired + private OrchestratorDriver orchestrationDriver; + + private static final Logger logger = LogManager.getLogger(PingRequirementsVerifier.class); + + private Map pingMeasurementCache = new ConcurrentHashMap<>(); + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Override + public boolean verify(final OrchestrationResultDTO result, final Map qosRequirements, final Map commands) { + logger.debug("verify started..."); + validateInput(result); + + if (qosRequirements == null || qosRequirements.isEmpty()) { // no need to verify anything + return true; + } + + final PingMeasurementResponseDTO measurement = getPingMeasurement(result.getProvider().getId()); + + if (!measurement.hasRecord()) { // no record => use related constant to determine output + return verifyNotMeasuredSystem; + } + + if (!measurement.isAvailable()) { + return false; + } + + if (hasMaximumResponseTimeThreshold(qosRequirements)) { + final int threshold = getMaximumResponseTimeThreshold(qosRequirements); + if (measurement.getMaxResponseTime().intValue() > threshold) { + logger.debug("Provider '{}' (id: {}) removed because of maximum response time threshold", result.getProvider().getSystemName(), result.getProvider().getId()); + return false; + } + } + + if (hasAverageResponseTimeThreshold(qosRequirements)) { + final int threshold = getAverageResponseTimeThreshold(qosRequirements); + if (measurement.getMeanResponseTimeWithoutTimeout().intValue() > threshold) { + logger.debug("Provider '{}' (id: {}) removed because of average response time threshold", result.getProvider().getSystemName(), result.getProvider().getId()); + return false; + } + } + + if (hasJitterThreshold(qosRequirements)) { + final int threshold = getJitterThreshold(qosRequirements); + if (measurement.getJitterWithoutTimeout().intValue() > threshold) { + logger.debug("Provider '{}' (id: {}) removed because of jitter threshold", result.getProvider().getSystemName(), result.getProvider().getId()); + return false; + } + } + + if (hasRecentPacketLossThreshold(qosRequirements)) { + final double threshold = getRecentPacketLossThreshold(qosRequirements); + final double recentPacketLoss = 1 - measurement.getReceived() / (double) measurement.getSent(); + if (recentPacketLoss > threshold) { + logger.debug("Provider '{}' (id: {}) removed because of recent packet loss threshold", result.getProvider().getSystemName(), result.getProvider().getId()); + return false; + } + } + + if (hasPacketLossThreshold(qosRequirements)) { + final double threshold = getPacketLossThreshold(qosRequirements); + final double packetLoss = 1 - measurement.getReceivedAll() / (double) measurement.getSentAll(); + if (packetLoss > threshold) { + logger.debug("Provider '{}' (id: {}) removed because of packet loss threshold", result.getProvider().getSystemName(), result.getProvider().getId()); + return false; + } + } + + return true; + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + private void validateInput(final OrchestrationResultDTO result) { + logger.debug("validateInput started..."); + + Assert.notNull(result, "'result' is null"); + Assert.notNull(result.getProvider(), "Provider is null"); + } + + //------------------------------------------------------------------------------------------------- + private boolean hasMaximumResponseTimeThreshold(final Map qosRequirements) { + return qosRequirements.containsKey(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD); + } + + //------------------------------------------------------------------------------------------------- + private boolean hasAverageResponseTimeThreshold(final Map qosRequirements) { + return qosRequirements.containsKey(OrchestrationFormRequestDTO.QOS_REQUIREMENT_AVERAGE_RESPONSE_TIME_THRESHOLD); + } + + //------------------------------------------------------------------------------------------------- + private boolean hasJitterThreshold(final Map qosRequirements) { + return qosRequirements.containsKey(OrchestrationFormRequestDTO.QOS_REQUIREMENT_JITTER_THRESHOLD); + } + + //------------------------------------------------------------------------------------------------- + private boolean hasRecentPacketLossThreshold(final Map qosRequirements) { + return qosRequirements.containsKey(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RECENT_PACKET_LOSS); + } + + //------------------------------------------------------------------------------------------------- + private boolean hasPacketLossThreshold(final Map qosRequirements) { + return qosRequirements.containsKey(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_PACKET_LOSS); + } + + //------------------------------------------------------------------------------------------------- + private int getMaximumResponseTimeThreshold(final Map qosRequirements) { + logger.debug("getMaximumResponseTimeThreshold started..."); + + final String valueStr = qosRequirements.get(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD); + try { + final int value = Integer.parseInt(valueStr); + if (value <= 0) { + throw new InvalidParameterException(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD + " has invalid value: " + valueStr); + } + + return value; + } catch (final NumberFormatException ex) { + throw new InvalidParameterException(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD + " has invalid value: " + valueStr); + } + } + + //------------------------------------------------------------------------------------------------- + private int getAverageResponseTimeThreshold(final Map qosRequirements) { + logger.debug("getAverageResponseTimeThreshold started..."); + + final String valueStr = qosRequirements.get(OrchestrationFormRequestDTO.QOS_REQUIREMENT_AVERAGE_RESPONSE_TIME_THRESHOLD); + try { + final int value = Integer.parseInt(valueStr); + if (value <= 0) { + throw new InvalidParameterException(OrchestrationFormRequestDTO.QOS_REQUIREMENT_AVERAGE_RESPONSE_TIME_THRESHOLD + " has invalid value: " + valueStr); + } + + return value; + } catch (final NumberFormatException ex) { + throw new InvalidParameterException(OrchestrationFormRequestDTO.QOS_REQUIREMENT_AVERAGE_RESPONSE_TIME_THRESHOLD + " has invalid value: " + valueStr); + } + } + + //------------------------------------------------------------------------------------------------- + private int getJitterThreshold(final Map qosRequirements) { + logger.debug("getJitterThreshold started..."); + + final String valueStr = qosRequirements.get(OrchestrationFormRequestDTO.QOS_REQUIREMENT_JITTER_THRESHOLD); + try { + final int value = Integer.parseInt(valueStr); + if (value < 0) { + throw new InvalidParameterException(OrchestrationFormRequestDTO.QOS_REQUIREMENT_JITTER_THRESHOLD + " has invalid value: " + valueStr); + } + + return value; + } catch (final NumberFormatException ex) { + throw new InvalidParameterException(OrchestrationFormRequestDTO.QOS_REQUIREMENT_JITTER_THRESHOLD + " has invalid value: " + valueStr); + } + } + + //------------------------------------------------------------------------------------------------- + private double getRecentPacketLossThreshold(final Map qosRequirements) { + logger.debug("getRecentPacketLossThreshold started..."); + + final String valueStr = qosRequirements.get(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RECENT_PACKET_LOSS); + try { + final int value = Integer.parseInt(valueStr); + if (value < 0) { + throw new InvalidParameterException(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RECENT_PACKET_LOSS + " has invalid value: " + valueStr); + } + + return value / 100.; + } catch (final NumberFormatException ex) { + throw new InvalidParameterException(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RECENT_PACKET_LOSS + " has invalid value: " + valueStr); + } + } + + //------------------------------------------------------------------------------------------------- + private double getPacketLossThreshold(final Map qosRequirements) { + logger.debug("getPacketLossThreshold started..."); + + final String valueStr = qosRequirements.get(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_PACKET_LOSS); + try { + final int value = Integer.parseInt(valueStr); + if (value < 0) { + throw new InvalidParameterException(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_PACKET_LOSS + " has invalid value: " + valueStr); + } + + return value / 100.; + } catch (final NumberFormatException ex) { + throw new InvalidParameterException(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_PACKET_LOSS + " has invalid value: " + valueStr); + } + } + + //------------------------------------------------------------------------------------------------- + private PingMeasurementResponseDTO getPingMeasurement(final long systemId) { + logger.debug("getPingMeasurement started..."); + + final PingMeasurementResponseDTO measurement = pingMeasurementCache.get(systemId); + + if (measurement == null) { + return getPingMeasurementFromQoSMonitor(systemId); + } + + if (measurement.getMeasurement().getLastMeasurementAt().plusSeconds(pingMeasurementCacheThreshold).isBefore(ZonedDateTime.now())) { // obsolete record + pingMeasurementCache.remove(systemId); + return getPingMeasurementFromQoSMonitor(systemId); + } + + return measurement; + } + + //------------------------------------------------------------------------------------------------- + private PingMeasurementResponseDTO getPingMeasurementFromQoSMonitor(final long systemId) { + logger.debug("getPingMeasurementFromQoSMonitor started..."); + + final PingMeasurementResponseDTO measurement = orchestrationDriver.getPingMeasurement(systemId); + + if (measurement.hasRecord() && measurement.isAvailable()) { // only caching when there are some data + pingMeasurementCache.put(systemId, measurement); + } + + return measurement; + } +} \ No newline at end of file diff --git a/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/impl/QoSManagerImpl.java b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/impl/QoSManagerImpl.java new file mode 100644 index 000000000..82a461738 --- /dev/null +++ b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/impl/QoSManagerImpl.java @@ -0,0 +1,176 @@ +package eu.arrowhead.core.qos.manager.impl; + +import java.util.ArrayList; +import java.util.List; + +import javax.annotation.PostConstruct; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.util.Assert; + +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.database.entity.QoSReservation; +import eu.arrowhead.common.dto.shared.OrchestrationFormRequestDTO; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.core.qos.database.service.QoSReservationDBService; +import eu.arrowhead.core.qos.manager.QoSManager; +import eu.arrowhead.core.qos.manager.QoSVerifier; +import eu.arrowhead.core.qos.manager.QoSVerifiers; + +public class QoSManagerImpl implements QoSManager { + + //================================================================================================= + // members + + private static final Logger logger = LogManager.getLogger(QoSManagerImpl.class); + + @Autowired + private QoSReservationDBService qosReservationDBService; + + @Autowired + private ApplicationContext appContext; + + private List verifiers = new ArrayList<>(2); + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @PostConstruct + public void init() { + verifiers.add(appContext.getBean(QoSVerifiers.SERVICE_TIME_VERIFIER, QoSVerifier.class)); + verifiers.add(appContext.getBean(QoSVerifiers.PING_REQUIREMENTS_VERIFIER, QoSVerifier.class)); + //TODO: add further verifiers here + } + + //------------------------------------------------------------------------------------------------- + @Override + public List filterReservedProviders(final List orList, final SystemRequestDTO requester) { + logger.debug("filterReservedProviders started ..."); + + Assert.notNull(orList, "'orList' is null."); + Assert.notNull(requester, "Requester system is null."); + Assert.isTrue(!Utilities.isEmpty(requester.getSystemName()), "Requester system's name is null or empty."); + Assert.isTrue(!Utilities.isEmpty(requester.getAddress()), "Requester system's address is null or empty."); + Assert.notNull(requester.getPort(), "Requester system's port is null."); + + if (orList.isEmpty()) { + return orList; + } + + final List reservations = qosReservationDBService.getAllReservationsExceptMine(requester.getSystemName(), requester.getAddress(), requester.getPort()); + final List result = new ArrayList<>(); + for (final OrchestrationResultDTO dto : orList) { + if (!isReserved(dto, reservations)) { + result.add(dto); + } + } + + return result; + } + + //------------------------------------------------------------------------------------------------- + @Override + public List reserveProvidersTemporarily(final List orList, final SystemRequestDTO requester) { + logger.debug("reserveProvidersTemporarily started ..."); + + Assert.notNull(orList, "'orList' is null."); + Assert.notNull(requester, "'requester' is null."); + Assert.isTrue(!Utilities.isEmpty(requester.getSystemName()), "Requester system's name is null or empty."); + Assert.isTrue(!Utilities.isEmpty(requester.getAddress()), "Requester system's address is null or empty."); + Assert.notNull(requester.getPort(), "Requester system's port is null."); + + if (orList.isEmpty()) { + return orList; + } + + final List result = new ArrayList(orList.size()); + for (final OrchestrationResultDTO dto : orList) { + try { + // try to lock + qosReservationDBService.applyTemporaryLock(requester.getSystemName(), requester.getAddress(), requester.getPort(), dto); + result.add(dto); + } catch (final ArrowheadException ex) { + // should means locking is failed because somebody already reserved that service => logging and removing + logger.debug("{}/{} may be already locked by someone else", dto.getProvider().getSystemName(), dto.getService().getServiceDefinition()); + } + } + + return result; + } + + //------------------------------------------------------------------------------------------------- + @Override + public void confirmReservation(final OrchestrationResultDTO selected, final List orList, final SystemRequestDTO requester) { + logger.debug("confirmReservation started ..."); + + Assert.notNull(selected, "'selected' is null."); + Assert.notEmpty(orList, "'orList' is null or empty."); + Assert.notNull(requester, "'requester' is null."); + Assert.isTrue(!Utilities.isEmpty(requester.getSystemName()), "Requester system's name is null or empty."); + Assert.isTrue(!Utilities.isEmpty(requester.getAddress()), "Requester system's address is null or empty."); + Assert.notNull(requester.getPort(), "Requester system's port is null."); + + for (final OrchestrationResultDTO dto : orList) { + + if (dto.getProvider().getId() == selected.getProvider().getId() && dto.getService().getId() == selected.getService().getId()) { + qosReservationDBService.extendReservation(selected, requester); + } else { + qosReservationDBService.removeTemporaryLock(dto); + } + } + } + + //------------------------------------------------------------------------------------------------- + @Override + public List verifyServices(final List orList, final OrchestrationFormRequestDTO request) { + logger.debug("verifyServices started ..."); + + Assert.notNull(orList, "'orList' is null."); + Assert.notNull(request, "'request' is null."); + + final boolean needLockRelease = request.getCommands().containsKey(OrchestrationFormRequestDTO.QOS_COMMAND_EXCLUSIVITY); + + final List result = new ArrayList<>(); + for (final OrchestrationResultDTO dto : orList) { + boolean verified = true; + for (final QoSVerifier verifier : verifiers) { + verified = verifier.verify(dto, request.getQosRequirements(), request.getCommands()); + if (!verified) { + if (needLockRelease) { + qosReservationDBService.removeTemporaryLock(dto); + } + logger.debug("{} exclude result: {}/{}", verifier.getClass().getName(), dto.getProvider().getId(), dto.getService().getId()); + break; + } + } + + if (verified) { + result.add(dto); + } + } + + return result; + } + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + private boolean isReserved(final OrchestrationResultDTO dto, final List reservations) { + logger.debug("isReserved started ..."); + + for (final QoSReservation reservation : reservations) { + if (reservation.getReservedProviderId() == dto.getProvider().getId() && reservation.getReservedServiceId() == dto.getService().getId()) { + return true; + } + } + + return false; + } +} \ No newline at end of file diff --git a/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/impl/ServiceTimeVerifier.java b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/impl/ServiceTimeVerifier.java new file mode 100644 index 000000000..ef78739ee --- /dev/null +++ b/orchestrator/src/main/java/eu/arrowhead/core/qos/manager/impl/ServiceTimeVerifier.java @@ -0,0 +1,76 @@ +package eu.arrowhead.core.qos.manager.impl; + +import java.util.Map; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.util.Assert; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.dto.shared.OrchestrationFormRequestDTO; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; +import eu.arrowhead.common.dto.shared.OrchestratorWarnings; +import eu.arrowhead.common.dto.shared.ServiceRegistryRequestDTO; +import eu.arrowhead.core.orchestrator.service.OrchestratorDriver; +import eu.arrowhead.core.orchestrator.service.OrchestratorService; +import eu.arrowhead.core.qos.manager.QoSVerifier; + +public class ServiceTimeVerifier implements QoSVerifier { + + //================================================================================================= + // members + + private static final double recommendedTimeFactor = 1.1; + private static final int extraSeconds = 5; + + private static final Logger logger = LogManager.getLogger(ServiceTimeVerifier.class); + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Override + public boolean verify(final OrchestrationResultDTO result, final Map qosRequirements, final Map commands) { + logger.debug("verify started..."); + Assert.notNull(result, "'result' is null."); + Assert.notNull(result.getMetadata(), "'result.getMetadata()' is null."); + Assert.notNull(result.getWarnings(), "'result.getWarnings()' is null."); + Assert.notNull(commands, "'commands' is null."); + + + int recommendedTime = -1; // no restrictions + if (result.getMetadata().containsKey(ServiceRegistryRequestDTO.KEY_RECOMMENDED_ORCHESTRATION_TIME)) { + try { + recommendedTime = Integer.parseInt(result.getMetadata().get(ServiceRegistryRequestDTO.KEY_RECOMMENDED_ORCHESTRATION_TIME)); + } catch (final NumberFormatException ex) { + logger.debug("Invalid recommended orchestration time: {}, ignored.", result.getMetadata().get(ServiceRegistryRequestDTO.KEY_RECOMMENDED_ORCHESTRATION_TIME)); + } + } + + int calculatedTime = recommendedTime; + if (commands.containsKey(OrchestrationFormRequestDTO.QOS_COMMAND_EXCLUSIVITY)) { + final int exclusivityTime = Integer.parseInt(commands.get(OrchestrationFormRequestDTO.QOS_COMMAND_EXCLUSIVITY)); + + if (recommendedTime > 0 && exclusivityTime > Math.round(recommendedTime * recommendedTimeFactor)) { // means this provider's time frame is not long enough + return false; + } + + calculatedTime = exclusivityTime; + } + + if (calculatedTime > 0) { + calculatedTime += extraSeconds; // give some extra seconds because of orchestration overhead + result.getMetadata().put(OrchestratorDriver.KEY_CALCULATED_SERVICE_TIME_FRAME, String.valueOf(calculatedTime)); + + // adjust TTL warnings + result.getWarnings().remove(OrchestratorWarnings.TTL_UNKNOWN); + if (!result.getWarnings().contains(OrchestratorWarnings.TTL_EXPIRED) && + !result.getWarnings().contains(OrchestratorWarnings.TTL_EXPIRING) && + calculatedTime <= OrchestratorService.EXPIRING_TIME_IN_MINUTES * CommonConstants.CONVERSION_SECOND_TO_MINUTE) { + result.getWarnings().add(OrchestratorWarnings.TTL_EXPIRING); + } + } + + return true; + } +} \ No newline at end of file diff --git a/orchestrator/src/main/java/eu/arrowhead/core/qos/quartz/task/ReservationCheckTask.java b/orchestrator/src/main/java/eu/arrowhead/core/qos/quartz/task/ReservationCheckTask.java new file mode 100644 index 000000000..51c6e2c87 --- /dev/null +++ b/orchestrator/src/main/java/eu/arrowhead/core/qos/quartz/task/ReservationCheckTask.java @@ -0,0 +1,38 @@ +package eu.arrowhead.core.qos.quartz.task; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import eu.arrowhead.core.qos.database.service.QoSReservationDBService; + +@Component +@DisallowConcurrentExecution +public class ReservationCheckTask implements Job { + + //================================================================================================= + // members + + protected final Logger logger = LogManager.getLogger(ReservationCheckTask.class); + + @Autowired + private QoSReservationDBService qosReservationDBService; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Override + public void execute(final JobExecutionContext context) throws JobExecutionException { + logger.debug("STARTED: Services reservation check task"); + + final int removeCount = qosReservationDBService.releaseObsoleteReservations(); + + logger.debug("FINISHED: Services reservation check task. Number of removed reservation entry: {}", removeCount); + } +} \ No newline at end of file diff --git a/orchestrator/src/main/java/eu/arrowhead/core/qos/quartz/task/ReservationCheckTaskConfig.java b/orchestrator/src/main/java/eu/arrowhead/core/qos/quartz/task/ReservationCheckTaskConfig.java new file mode 100644 index 000000000..799abfdfe --- /dev/null +++ b/orchestrator/src/main/java/eu/arrowhead/core/qos/quartz/task/ReservationCheckTaskConfig.java @@ -0,0 +1,77 @@ +package eu.arrowhead.core.qos.quartz.task; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.quartz.SimpleTrigger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.quartz.JobDetailFactoryBean; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; +import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean; + +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.quartz.AutoWiringSpringBeanQuartzTaskFactory; + +@Configuration +public class ReservationCheckTaskConfig { + + //================================================================================================= + // members + + protected final Logger logger = LogManager.getLogger(ReservationCheckTaskConfig.class); + + @Autowired + private ApplicationContext applicationContext; //NOSONAR + + @Value(CoreCommonConstants.$QOS_RESERVATION_CHECK_INTERVAL_WD) + private int interval; + + private static final int SCHEDULER_DELAY = 19; + + private static final String NAME_OF_TRIGGER = "Services_Reservation_Check_Task_Trigger"; + private static final String NAME_OF_TASK = "Services_Reservation_Check_Task_Detail"; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Bean + public SchedulerFactoryBean servicesReservationCheckScheduler() { + final AutoWiringSpringBeanQuartzTaskFactory jobFactory = new AutoWiringSpringBeanQuartzTaskFactory(); + jobFactory.setApplicationContext(applicationContext); + final SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean(); + schedulerFactory.setJobFactory(jobFactory); + schedulerFactory.setJobDetails(servicesReservationCheckTaskDetail().getObject()); + schedulerFactory.setTriggers(servicesReservationCheckTaskTrigger().getObject()); + schedulerFactory.setStartupDelay(SCHEDULER_DELAY); + logger.info("Services reservation task adjusted with interval: {} seconds", interval); + + return schedulerFactory; + } + + //------------------------------------------------------------------------------------------------- + @Bean + public SimpleTriggerFactoryBean servicesReservationCheckTaskTrigger() { + final SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean(); + trigger.setJobDetail(servicesReservationCheckTaskDetail().getObject()); + trigger.setRepeatInterval(interval * CoreCommonConstants.CONVERSION_MILLISECOND_TO_SECOND); + trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY); + trigger.setName(NAME_OF_TRIGGER); + + return trigger; + } + + //------------------------------------------------------------------------------------------------- + @Bean + public JobDetailFactoryBean servicesReservationCheckTaskDetail() { + final JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean(); + jobDetailFactory.setJobClass(ReservationCheckTask.class); + jobDetailFactory.setName(NAME_OF_TASK); + jobDetailFactory.setDurability(true); + + return jobDetailFactory; + } +} \ No newline at end of file diff --git a/orchestrator/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/orchestrator/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 302f0c115..c6a4240dd 100644 --- a/orchestrator/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/orchestrator/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -43,5 +43,20 @@ "name": "domain.port", "type": "java.lang.String", "description": "A description for 'domain.port'" + }, + { + "name": "enable_qos", + "type": "java.lang.Boolean", + "description": "A description for 'enable_qos'" + }, + { + "name": "qos_reservation_check_interval", + "type": "java.lang.Integer", + "description": "A description for 'qos_reservation_check_interval'" + }, + { + "name": "qos_ping_measurement_cache_threshold", + "type": "java.lang.Integer", + "description": "A description for 'qos_ping_measurement_cache_threshold'" } ]} \ No newline at end of file diff --git a/orchestrator/src/main/resources/application.properties b/orchestrator/src/main/resources/application.properties index 939923fd8..da28b1c45 100644 --- a/orchestrator/src/main/resources/application.properties +++ b/orchestrator/src/main/resources/application.properties @@ -38,6 +38,15 @@ sr_port=8443 #If true, operational gatekeeper must be present gatekeeper_is_present=true +#If true, orchestrator will use QoS verification and reservation (if clients using this feature) +enable_qos=true + +#How frequently the database should be checked for expired reservations, in seconds +qos_reservation_check_interval=120 + +#How long a cached ping measurement can use without refreshing using the Qos Monitor's webservice, in seconds +qos_ping_measurement_cache_threshold=600 + # Interface names has to follow this format --, where security can be SECURE or INSECURE and protocol and format must be a sequence of letters, numbers and underscore. # A regexp checker will verify that. If this setting is set to true then the PROTOCOL and FORMAT must come from a predefined set. use_strict_service_intf_name_verifier=false diff --git a/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/matchmaking/DefaultIntraCloudProviderMatchmakerTest.java b/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/matchmaking/DefaultIntraCloudProviderMatchmakerTest.java index 55e9f145a..7b867430f 100644 --- a/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/matchmaking/DefaultIntraCloudProviderMatchmakerTest.java +++ b/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/matchmaking/DefaultIntraCloudProviderMatchmakerTest.java @@ -7,8 +7,8 @@ import org.junit.runner.RunWith; import org.springframework.test.context.junit4.SpringRunner; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; import eu.arrowhead.common.dto.shared.PreferredProviderDataDTO; -import eu.arrowhead.common.dto.shared.ServiceRegistryResponseDTO; import eu.arrowhead.common.dto.shared.SystemRequestDTO; import eu.arrowhead.common.dto.shared.SystemResponseDTO; @@ -38,20 +38,20 @@ public void doMatchmakingSRListEmpty() { //------------------------------------------------------------------------------------------------- @Test(expected = IllegalArgumentException.class) public void doMatchmakingParamsNull() { - algorithm.doMatchmaking(List.of(new ServiceRegistryResponseDTO()), null); + algorithm.doMatchmaking(List.of(new OrchestrationResultDTO()), null); } //------------------------------------------------------------------------------------------------- @Test public void doMatchmakingNoPreferred() { - final ServiceRegistryResponseDTO dto1 = new ServiceRegistryResponseDTO(); - dto1.setId(1); - final ServiceRegistryResponseDTO dto2 = new ServiceRegistryResponseDTO(); - dto2.setId(2); + final OrchestrationResultDTO dto1 = new OrchestrationResultDTO(); + dto1.setVersion(1); + final OrchestrationResultDTO dto2 = new OrchestrationResultDTO(); + dto2.setVersion(2); - final ServiceRegistryResponseDTO selected = algorithm.doMatchmaking(List.of(dto1, dto2), new IntraCloudProviderMatchmakingParameters(List.of())); + final OrchestrationResultDTO selected = algorithm.doMatchmaking(List.of(dto1, dto2), new IntraCloudProviderMatchmakingParameters(List.of())); - Assert.assertEquals(1, selected.getId()); + Assert.assertEquals(1, selected.getVersion().intValue()); } //------------------------------------------------------------------------------------------------- @@ -59,11 +59,11 @@ public void doMatchmakingNoPreferred() { public void doMatchmakingNoPreferredMatch() { final SystemResponseDTO system1 = new SystemResponseDTO(1, "system1", "localhost", 1234, null, null, null); final SystemResponseDTO system2 = new SystemResponseDTO(1, "system2", "localhost", 4567, null, null, null); - final ServiceRegistryResponseDTO dto1 = new ServiceRegistryResponseDTO(); - dto1.setId(1); + final OrchestrationResultDTO dto1 = new OrchestrationResultDTO(); + dto1.setVersion(1); dto1.setProvider(system1); - final ServiceRegistryResponseDTO dto2 = new ServiceRegistryResponseDTO(); - dto2.setId(2); + final OrchestrationResultDTO dto2 = new OrchestrationResultDTO(); + dto2.setVersion(2); dto2.setProvider(system2); final SystemRequestDTO reqSystem = new SystemRequestDTO(); @@ -73,9 +73,9 @@ public void doMatchmakingNoPreferredMatch() { final PreferredProviderDataDTO ppDTO = new PreferredProviderDataDTO(); ppDTO.setProviderSystem(reqSystem); - final ServiceRegistryResponseDTO selected = algorithm.doMatchmaking(List.of(dto1, dto2), new IntraCloudProviderMatchmakingParameters(List.of(ppDTO))); + final OrchestrationResultDTO selected = algorithm.doMatchmaking(List.of(dto1, dto2), new IntraCloudProviderMatchmakingParameters(List.of(ppDTO))); - Assert.assertEquals(1, selected.getId()); + Assert.assertEquals(1, selected.getVersion().intValue()); } //------------------------------------------------------------------------------------------------- @@ -83,11 +83,11 @@ public void doMatchmakingNoPreferredMatch() { public void doMatchmakingPreferredMatch() { final SystemResponseDTO system1 = new SystemResponseDTO(1, "system1", "localhost", 1234, null, null, null); final SystemResponseDTO system2 = new SystemResponseDTO(1, "system2", "localhost", 4567, null, null, null); - final ServiceRegistryResponseDTO dto1 = new ServiceRegistryResponseDTO(); - dto1.setId(1); + final OrchestrationResultDTO dto1 = new OrchestrationResultDTO(); + dto1.setVersion(1); dto1.setProvider(system1); - final ServiceRegistryResponseDTO dto2 = new ServiceRegistryResponseDTO(); - dto2.setId(2); + final OrchestrationResultDTO dto2 = new OrchestrationResultDTO(); + dto2.setVersion(2); dto2.setProvider(system2); final SystemRequestDTO reqSystem = new SystemRequestDTO(); @@ -97,8 +97,8 @@ public void doMatchmakingPreferredMatch() { final PreferredProviderDataDTO ppDTO = new PreferredProviderDataDTO(); ppDTO.setProviderSystem(reqSystem); - final ServiceRegistryResponseDTO selected = algorithm.doMatchmaking(List.of(dto1, dto2), new IntraCloudProviderMatchmakingParameters(List.of(ppDTO))); + final OrchestrationResultDTO selected = algorithm.doMatchmaking(List.of(dto1, dto2), new IntraCloudProviderMatchmakingParameters(List.of(ppDTO))); - Assert.assertEquals(2, selected.getId()); + Assert.assertEquals(2, selected.getVersion().intValue()); } } \ No newline at end of file diff --git a/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/matchmaking/RandomIntraCloudProviderMatchmakerTest.java b/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/matchmaking/RandomIntraCloudProviderMatchmakerTest.java index aab9378bd..a22de1c5a 100644 --- a/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/matchmaking/RandomIntraCloudProviderMatchmakerTest.java +++ b/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/matchmaking/RandomIntraCloudProviderMatchmakerTest.java @@ -8,8 +8,8 @@ import org.junit.runner.RunWith; import org.springframework.test.context.junit4.SpringRunner; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; import eu.arrowhead.common.dto.shared.PreferredProviderDataDTO; -import eu.arrowhead.common.dto.shared.ServiceRegistryResponseDTO; import eu.arrowhead.common.dto.shared.SystemRequestDTO; import eu.arrowhead.common.dto.shared.SystemResponseDTO; @@ -40,16 +40,16 @@ public void doMatchmakingSRListEmpty() { //------------------------------------------------------------------------------------------------- @Test(expected = IllegalArgumentException.class) public void doMatchmakingParamsNull() { - algorithm.doMatchmaking(List.of(new ServiceRegistryResponseDTO()), null); + algorithm.doMatchmaking(List.of(new OrchestrationResultDTO()), null); } //------------------------------------------------------------------------------------------------- @Test public void doMatchmakingNoPreferred() { - final ServiceRegistryResponseDTO dto1 = new ServiceRegistryResponseDTO(); - dto1.setId(1); - final ServiceRegistryResponseDTO dto2 = new ServiceRegistryResponseDTO(); - dto2.setId(2); + final OrchestrationResultDTO dto1 = new OrchestrationResultDTO(); + dto1.setVersion(1); + final OrchestrationResultDTO dto2 = new OrchestrationResultDTO(); + dto2.setVersion(2); final long seed = System.currentTimeMillis(); IntraCloudProviderMatchmakingParameters params = new IntraCloudProviderMatchmakingParameters(List.of()); @@ -57,10 +57,10 @@ public void doMatchmakingNoPreferred() { rng.setSeed(seed); algorithm = new RandomIntraCloudProviderMatchmaker(); // to make sure the same seed is set - final List srList = List.of(dto1, dto2); - final ServiceRegistryResponseDTO selected = algorithm.doMatchmaking(srList, params); + final List orList = List.of(dto1, dto2); + final OrchestrationResultDTO selected = algorithm.doMatchmaking(orList, params); - Assert.assertEquals(srList.get(rng.nextInt(2)).getId(), selected.getId()); + Assert.assertEquals(orList.get(rng.nextInt(2)).getVersion().intValue(), selected.getVersion().intValue()); } //------------------------------------------------------------------------------------------------- @@ -68,11 +68,11 @@ public void doMatchmakingNoPreferred() { public void doMatchmakingNoPreferredMatch() { final SystemResponseDTO system1 = new SystemResponseDTO(1, "system1", "localhost", 1234, null, null, null); final SystemResponseDTO system2 = new SystemResponseDTO(1, "system2", "localhost", 4567, null, null, null); - final ServiceRegistryResponseDTO dto1 = new ServiceRegistryResponseDTO(); - dto1.setId(1); + final OrchestrationResultDTO dto1 = new OrchestrationResultDTO(); + dto1.setVersion(1); dto1.setProvider(system1); - final ServiceRegistryResponseDTO dto2 = new ServiceRegistryResponseDTO(); - dto2.setId(2); + final OrchestrationResultDTO dto2 = new OrchestrationResultDTO(); + dto2.setVersion(2); dto2.setProvider(system2); final SystemRequestDTO reqSystem = new SystemRequestDTO(); @@ -88,10 +88,10 @@ public void doMatchmakingNoPreferredMatch() { rng.setSeed(seed); algorithm = new RandomIntraCloudProviderMatchmaker(); // to make sure the same seed is set - final List srList = List.of(dto1, dto2); - final ServiceRegistryResponseDTO selected = algorithm.doMatchmaking(srList, params); + final List orList = List.of(dto1, dto2); + final OrchestrationResultDTO selected = algorithm.doMatchmaking(orList, params); - Assert.assertEquals(srList.get(rng.nextInt(2)).getId(), selected.getId()); + Assert.assertEquals(orList.get(rng.nextInt(2)).getVersion().intValue(), selected.getVersion().intValue()); } //------------------------------------------------------------------------------------------------- @@ -99,11 +99,11 @@ public void doMatchmakingNoPreferredMatch() { public void doMatchmakingPreferredMatch() { final SystemResponseDTO system1 = new SystemResponseDTO(1, "system1", "localhost", 1234, null, null, null); final SystemResponseDTO system2 = new SystemResponseDTO(1, "system2", "localhost", 4567, null, null, null); - final ServiceRegistryResponseDTO dto1 = new ServiceRegistryResponseDTO(); - dto1.setId(1); + final OrchestrationResultDTO dto1 = new OrchestrationResultDTO(); + dto1.setVersion(1); dto1.setProvider(system1); - final ServiceRegistryResponseDTO dto2 = new ServiceRegistryResponseDTO(); - dto2.setId(2); + final OrchestrationResultDTO dto2 = new OrchestrationResultDTO(); + dto2.setVersion(2); dto2.setProvider(system2); final SystemRequestDTO reqSystem = new SystemRequestDTO(); @@ -113,8 +113,8 @@ public void doMatchmakingPreferredMatch() { final PreferredProviderDataDTO ppDTO = new PreferredProviderDataDTO(); ppDTO.setProviderSystem(reqSystem); - final ServiceRegistryResponseDTO selected = algorithm.doMatchmaking(List.of(dto1, dto2), new IntraCloudProviderMatchmakingParameters(List.of(ppDTO))); + final OrchestrationResultDTO selected = algorithm.doMatchmaking(List.of(dto1, dto2), new IntraCloudProviderMatchmakingParameters(List.of(ppDTO))); - Assert.assertEquals(2, selected.getId()); + Assert.assertEquals(2, selected.getVersion().intValue()); } } \ No newline at end of file diff --git a/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/security/OrchestratorAccessControlFilterTest.java b/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/security/OrchestratorAccessControlFilterTest.java index c47b17bb0..69b032ffc 100644 --- a/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/security/OrchestratorAccessControlFilterTest.java +++ b/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/security/OrchestratorAccessControlFilterTest.java @@ -101,7 +101,7 @@ public void testEchoCertificateOtherCloud() throws Exception { @Test public void testExternalOrchestrationWithGatekeeper() throws Exception { final Map flags = new HashMap<>(); - flags.put(CommonConstants.ORCHESTRATON_FLAG_EXTERNAL_SERVICE_REQUEST, true); + flags.put(CommonConstants.ORCHESTRATION_FLAG_EXTERNAL_SERVICE_REQUEST, true); final OrchestrationFormRequestDTO requestDTO = createOrchestrationFromRequestDTO("", flags); this.mockMvc.perform(post(ORCH_ORCHESTRATION) @@ -117,7 +117,7 @@ public void testExternalOrchestrationWithGatekeeper() throws Exception { @Test public void testExternalOrchestrationWithoutGatekeeper() throws Exception { final Map flags = new HashMap<>(); - flags.put(CommonConstants.ORCHESTRATON_FLAG_EXTERNAL_SERVICE_REQUEST, true); + flags.put(CommonConstants.ORCHESTRATION_FLAG_EXTERNAL_SERVICE_REQUEST, true); final OrchestrationFormRequestDTO requestDTO = createOrchestrationFromRequestDTO("", flags); this.mockMvc.perform(post(ORCH_ORCHESTRATION) diff --git a/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/service/OrchestratorDriverTest.java b/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/service/OrchestratorDriverTest.java index 5384af3da..1e8c90103 100644 --- a/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/service/OrchestratorDriverTest.java +++ b/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/service/OrchestratorDriverTest.java @@ -5,18 +5,21 @@ import static org.mockito.Mockito.when; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.InjectMocks; import org.mockito.Mock; import org.springframework.http.HttpMethod; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.util.ReflectionTestUtils; import org.springframework.web.util.UriComponents; import eu.arrowhead.common.CommonConstants; @@ -31,6 +34,7 @@ import eu.arrowhead.common.dto.internal.ICNRequestFormDTO; import eu.arrowhead.common.dto.internal.ICNResultDTO; import eu.arrowhead.common.dto.internal.IdIdListDTO; +import eu.arrowhead.common.dto.internal.PingMeasurementResponseDTO; import eu.arrowhead.common.dto.internal.TokenDataDTO; import eu.arrowhead.common.dto.internal.TokenGenerationRequestDTO; import eu.arrowhead.common.dto.internal.TokenGenerationResponseDTO; @@ -167,6 +171,89 @@ public void testGenerateAuthTokensTokenIsFilled() { Assert.assertEquals("ABCDE", dto.getAuthorizationTokens().get(dto.getInterfaces().get(0).getInterfaceName())); } + //------------------------------------------------------------------------------------------------- + @Test + public void testGenerateAuthTokensTokenNoCalculatedServiceTimeFrame() { + ReflectionTestUtils.setField(orchestratorDriver, "tokenDuration", 1001); + + final OrchestrationResultDTO dto = getOrchestrationResultDTO(1); + final UriComponents tokenUri = Utilities.createURI(CommonConstants.HTTPS, "localhost", 8445, "/token"); + final Map tokenMap = Map.of(dto.getInterfaces().get(0).getInterfaceName(), "ABCDE"); + final TokenDataDTO tokenDataDTO = new TokenDataDTO(DTOConverter.convertSystemResponseDTOToSystemRequestDTO(dto.getProvider()), tokenMap); + final TokenGenerationResponseDTO responseDTO = new TokenGenerationResponseDTO(); + responseDTO.setTokenData(List.of(tokenDataDTO)); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(TokenGenerationRequestDTO.class); + when(arrowheadContext.containsKey(any(String.class))).thenReturn(true); + when(arrowheadContext.get(any(String.class))).thenReturn(tokenUri); + when(httpService.sendRequest(eq(tokenUri), eq(HttpMethod.POST), eq(TokenGenerationResponseDTO.class), captor.capture())). + thenReturn(new ResponseEntity(responseDTO, HttpStatus.OK)); + + final OrchestrationFormRequestDTO request = new OrchestrationFormRequestDTO(); + request.setRequesterSystem(new SystemRequestDTO()); + + orchestratorDriver.generateAuthTokens(request, List.of(dto)); + + final TokenGenerationRequestDTO requestDTO = captor.getValue(); + Assert.assertEquals(1001, requestDTO.getProviders().get(0).getTokenDuration()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testGenerateAuthTokensTokenInvalidCalculatedServiceTimeFrame() { + ReflectionTestUtils.setField(orchestratorDriver, "tokenDuration", 1000); + + final OrchestrationResultDTO dto = getOrchestrationResultDTO(1); + dto.getMetadata().put(OrchestratorDriver.KEY_CALCULATED_SERVICE_TIME_FRAME, "300invalid"); + final UriComponents tokenUri = Utilities.createURI(CommonConstants.HTTPS, "localhost", 8445, "/token"); + final Map tokenMap = Map.of(dto.getInterfaces().get(0).getInterfaceName(), "ABCDE"); + final TokenDataDTO tokenDataDTO = new TokenDataDTO(DTOConverter.convertSystemResponseDTOToSystemRequestDTO(dto.getProvider()), tokenMap); + final TokenGenerationResponseDTO responseDTO = new TokenGenerationResponseDTO(); + responseDTO.setTokenData(List.of(tokenDataDTO)); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(TokenGenerationRequestDTO.class); + when(arrowheadContext.containsKey(any(String.class))).thenReturn(true); + when(arrowheadContext.get(any(String.class))).thenReturn(tokenUri); + when(httpService.sendRequest(eq(tokenUri), eq(HttpMethod.POST), eq(TokenGenerationResponseDTO.class), captor.capture())). + thenReturn(new ResponseEntity(responseDTO, HttpStatus.OK)); + + final OrchestrationFormRequestDTO request = new OrchestrationFormRequestDTO(); + request.setRequesterSystem(new SystemRequestDTO()); + + orchestratorDriver.generateAuthTokens(request, List.of(dto)); + + final TokenGenerationRequestDTO requestDTO = captor.getValue(); + Assert.assertEquals(1000, requestDTO.getProviders().get(0).getTokenDuration()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testGenerateAuthTokensTokenValidCalculatedServiceTimeFrame() { + ReflectionTestUtils.setField(orchestratorDriver, "tokenDuration", 1000); + + final OrchestrationResultDTO dto = getOrchestrationResultDTO(1); + dto.getMetadata().put(OrchestratorDriver.KEY_CALCULATED_SERVICE_TIME_FRAME, "300"); + final UriComponents tokenUri = Utilities.createURI(CommonConstants.HTTPS, "localhost", 8445, "/token"); + final Map tokenMap = Map.of(dto.getInterfaces().get(0).getInterfaceName(), "ABCDE"); + final TokenDataDTO tokenDataDTO = new TokenDataDTO(DTOConverter.convertSystemResponseDTOToSystemRequestDTO(dto.getProvider()), tokenMap); + final TokenGenerationResponseDTO responseDTO = new TokenGenerationResponseDTO(); + responseDTO.setTokenData(List.of(tokenDataDTO)); + + final ArgumentCaptor captor = ArgumentCaptor.forClass(TokenGenerationRequestDTO.class); + when(arrowheadContext.containsKey(any(String.class))).thenReturn(true); + when(arrowheadContext.get(any(String.class))).thenReturn(tokenUri); + when(httpService.sendRequest(eq(tokenUri), eq(HttpMethod.POST), eq(TokenGenerationResponseDTO.class), captor.capture())). + thenReturn(new ResponseEntity(responseDTO, HttpStatus.OK)); + + final OrchestrationFormRequestDTO request = new OrchestrationFormRequestDTO(); + request.setRequesterSystem(new SystemRequestDTO()); + + orchestratorDriver.generateAuthTokens(request, List.of(dto)); + + final TokenGenerationRequestDTO requestDTO = captor.getValue(); + Assert.assertEquals(300, requestDTO.getProviders().get(0).getTokenDuration()); + } + //------------------------------------------------------------------------------------------------- @Test(expected = IllegalArgumentException.class) public void testQueryAuthorizationConsumerNull() { @@ -395,6 +482,42 @@ public void testDoInterCloudNegotiationsNullRequest() { orchestratorDriver.doInterCloudNegotiation(null); } + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testGetPingMeasurementUriNotFound() { + when(arrowheadContext.containsKey(any(String.class))).thenReturn(false); + + orchestratorDriver.getPingMeasurement(1); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testGetPingMeasurementUriWrongType() { + when(arrowheadContext.containsKey(any(String.class))).thenReturn(true); + when(arrowheadContext.get(any(String.class))).thenReturn("invalid"); + + orchestratorDriver.getPingMeasurement(1); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testGetPingMeasurementOk() { + final int systemId = 23; + final UriComponents uri = Utilities.createURI(CommonConstants.HTTPS, "localhost", 8451, CommonConstants.QOS_MONITOR_URI + CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT + + CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT_SUFFIX).expand(systemId); + Assert.assertTrue(uri.toString().contains("/ping/measurement/23")); + + final PingMeasurementResponseDTO responseDTO = new PingMeasurementResponseDTO(); + when(arrowheadContext.containsKey(any(String.class))).thenReturn(true); + when(arrowheadContext.get(any(String.class))).thenReturn(uri); + when(httpService.sendRequest(eq(uri), eq(HttpMethod.GET), eq(PingMeasurementResponseDTO.class))).thenReturn(new ResponseEntity(responseDTO, HttpStatus.OK)); + + final PingMeasurementResponseDTO result = orchestratorDriver.getPingMeasurement(systemId); + + Assert.assertNotNull(result); + Assert.assertFalse(result.hasRecord()); + } + //================================================================================================= // assistant methods @@ -405,7 +528,7 @@ private OrchestrationResultDTO getOrchestrationResultDTO(final int index) { final List intfs = new ArrayList<>(1); intfs.add(new ServiceInterfaceResponseDTO(1, "HTTP-SECURE-JSON", null, null)); - return new OrchestrationResultDTO(provider, service, "/uri" + index, ServiceSecurityType.TOKEN, null, intfs, null); + return new OrchestrationResultDTO(provider, service, "/uri" + index, ServiceSecurityType.TOKEN, new HashMap<>(), intfs, null); } //------------------------------------------------------------------------------------------------- diff --git a/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/service/OrchestratorServiceTest.java b/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/service/OrchestratorServiceTest.java index d4b4a56c2..30d7a5d46 100644 --- a/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/service/OrchestratorServiceTest.java +++ b/orchestrator/src/test/java/eu/arrowhead/core/orchestrator/service/OrchestratorServiceTest.java @@ -10,6 +10,7 @@ import java.util.Map; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; @@ -17,6 +18,7 @@ import org.springframework.test.context.junit4.SpringRunner; import org.springframework.test.util.ReflectionTestUtils; +import eu.arrowhead.common.CoreCommonConstants; import eu.arrowhead.common.database.entity.OrchestratorStore; import eu.arrowhead.common.database.entity.ServiceDefinition; import eu.arrowhead.common.database.entity.ServiceInterface; @@ -54,6 +56,7 @@ import eu.arrowhead.core.orchestrator.matchmaking.InterCloudProviderMatchmakingParameters; import eu.arrowhead.core.orchestrator.matchmaking.IntraCloudProviderMatchmakingAlgorithm; import eu.arrowhead.core.orchestrator.matchmaking.IntraCloudProviderMatchmakingParameters; +import eu.arrowhead.core.qos.manager.impl.DummyQoSManager; @RunWith(SpringRunner.class) public class OrchestratorServiceTest { @@ -82,6 +85,12 @@ public class OrchestratorServiceTest { //================================================================================================= // methods + //------------------------------------------------------------------------------------------------- + @Before + public void setUp() { + ReflectionTestUtils.setField(testingObject, CoreCommonConstants.QOS_MANAGER, new DummyQoSManager()); + } + //------------------------------------------------------------------------------------------------- @Test(expected = InvalidParameterException.class) public void testExternalServiceRequestRequestNull() { @@ -637,19 +646,26 @@ public void testDynamicOrchestrationOneResultWithMatchmaking() { requestedService(serviceForm). flag(Flag.MATCHMAKING, true). build(); + final ServiceDefinitionResponseDTO serviceDefinitionResponseDTO = new ServiceDefinitionResponseDTO(3, "service", null, null); + final ServiceInterfaceResponseDTO serviceInterfaceResponseDTO = new ServiceInterfaceResponseDTO(4, "HTTP-SECURE-JSON", null, null); final ServiceRegistryResponseDTO srEntry = new ServiceRegistryResponseDTO(); srEntry.setProvider(new SystemResponseDTO(1, "a", "b", 3, null, null, null)); + srEntry.setServiceDefinition(serviceDefinitionResponseDTO); + srEntry.setInterfaces(List.of(serviceInterfaceResponseDTO)); final ServiceRegistryResponseDTO srEntry2 = new ServiceRegistryResponseDTO(); srEntry2.setProvider(new SystemResponseDTO(2, "d", "e", 6, null, null, null)); - srEntry2.setServiceDefinition(new ServiceDefinitionResponseDTO(3, "service", null, null)); - srEntry2.setInterfaces(List.of(new ServiceInterfaceResponseDTO(4, "HTTP-SECURE-JSON", null, null))); + srEntry2.setServiceDefinition(serviceDefinitionResponseDTO); + srEntry2.setInterfaces(List.of(serviceInterfaceResponseDTO)); final ServiceQueryResultDTO srResult = new ServiceQueryResultDTO(); srResult.getServiceQueryData().add(srEntry); srResult.getServiceQueryData().add(srEntry2); + final OrchestrationResultDTO convertedSrEntry2 = new OrchestrationResultDTO(srEntry2.getProvider(), srEntry2.getServiceDefinition(), srEntry2.getServiceUri(), + srEntry2.getSecure(), srEntry2.getMetadata(), srEntry2.getInterfaces(), srEntry2.getVersion()); + when(orchestratorDriver.queryServiceRegistry(any(ServiceQueryFormDTO.class), anyBoolean(), anyBoolean())).thenReturn(srResult); when(orchestratorDriver.queryAuthorization(any(SystemRequestDTO.class), any())).thenReturn(srResult.getServiceQueryData()); - when(intraCloudProviderMatchmaker.doMatchmaking(any(), any(IntraCloudProviderMatchmakingParameters.class))).thenReturn(srEntry2); + when(intraCloudProviderMatchmaker.doMatchmaking(any(), any(IntraCloudProviderMatchmakingParameters.class))).thenReturn(convertedSrEntry2); when(orchestratorDriver.generateAuthTokens(any(OrchestrationFormRequestDTO.class), any())).thenCallRealMethod(); final OrchestrationResponseDTO result = testingObject.dynamicOrchestration(request); diff --git a/orchestrator/src/test/java/eu/arrowhead/core/qos/database/service/QoSReservationDBServiceTest.java b/orchestrator/src/test/java/eu/arrowhead/core/qos/database/service/QoSReservationDBServiceTest.java new file mode 100644 index 000000000..b5b263bae --- /dev/null +++ b/orchestrator/src/test/java/eu/arrowhead/core/qos/database/service/QoSReservationDBServiceTest.java @@ -0,0 +1,290 @@ +package eu.arrowhead.core.qos.database.service; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.Optional; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.util.ReflectionTestUtils; + +import eu.arrowhead.common.database.entity.QoSReservation; +import eu.arrowhead.common.database.repository.QoSReservationRepository; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; +import eu.arrowhead.common.dto.shared.ServiceDefinitionResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; + +@RunWith(SpringRunner.class) +public class QoSReservationDBServiceTest { + + //================================================================================================= + // members + + @InjectMocks + private QoSReservationDBService testingObject; + + @Mock + private QoSReservationRepository qosReservationRepository; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testGetAllReservationsExceptMineSystemNameNull() { + testingObject.getAllReservationsExceptMine(null, null, 0); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testGetAllReservationsExceptMineSystemNameEmpty() { + testingObject.getAllReservationsExceptMine(" ", null, 0); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testGetAllReservationsExceptMineAddressNull() { + testingObject.getAllReservationsExceptMine("system", null, 0); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testGetAllReservationsExceptMineAddressEmpty() { + testingObject.getAllReservationsExceptMine("system", " ", 0); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testGetAllReservationsExceptMineOk() { + when(qosReservationRepository.findAllByConsumerSystemNameNotOrConsumerAddressNotOrConsumerPortNot(anyString(), anyString(), anyInt())).thenReturn(List.of()); + testingObject.getAllReservationsExceptMine("System", "Address", 1234); + verify(qosReservationRepository, times(1)).findAllByConsumerSystemNameNotOrConsumerAddressNotOrConsumerPortNot("system", "address", 1234); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testApplyTemporaryLockSystemNameNull() { + testingObject.applyTemporaryLock(null, null, 0, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testApplyTemporaryLockSystemNameEmpty() { + testingObject.applyTemporaryLock("\t", null, 0, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testApplyTemporaryLockAddressNull() { + testingObject.applyTemporaryLock("system", null, 0, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testApplyTemporaryLockAddressEmpty() { + testingObject.applyTemporaryLock("system", "", 0, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testApplyTemporaryLockDTONull() { + testingObject.applyTemporaryLock("system", "address", 0, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testApplyTemporaryLockProviderNull() { + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + testingObject.applyTemporaryLock("system", "address", 0, dto); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testApplyTemporaryLockServiceNull() { + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + dto.setProvider(new SystemResponseDTO()); + testingObject.applyTemporaryLock("system", "address", 0, dto); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testApplyTemporaryLockOk() { + when(qosReservationRepository.saveAndFlush(any(QoSReservation.class))).thenReturn(new QoSReservation()); + + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + dto.setProvider(new SystemResponseDTO()); + dto.setService(new ServiceDefinitionResponseDTO()); + testingObject.applyTemporaryLock("system", "address", 1234, dto); + + verify(qosReservationRepository, times(1)).saveAndFlush(any(QoSReservation.class)); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testRemoveTemporaryLockDTONull() { + testingObject.removeTemporaryLock(null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testRemoveTemporaryLockProviderNull() { + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + testingObject.removeTemporaryLock(dto); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testRemoveTemporaryLockServiceNull() { + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + dto.setProvider(new SystemResponseDTO()); + testingObject.removeTemporaryLock(dto); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testRemoveTemporaryLockOkNotFound() { + when(qosReservationRepository.findByReservedProviderIdAndReservedServiceIdAndTemporaryLockTrue(anyLong(), anyLong())).thenReturn(Optional.empty()); + + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + dto.setProvider(new SystemResponseDTO()); + dto.setService(new ServiceDefinitionResponseDTO()); + testingObject.removeTemporaryLock(dto); + + verify(qosReservationRepository, never()).delete(any(QoSReservation.class)); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testRemoveTemporaryLockOkFound() { + final QoSReservation reservation = new QoSReservation(); + when(qosReservationRepository.findByReservedProviderIdAndReservedServiceIdAndTemporaryLockTrue(anyLong(), anyLong())).thenReturn(Optional.of(reservation)); + doNothing().when(qosReservationRepository).delete(reservation); + doNothing().when(qosReservationRepository).flush(); + + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + dto.setProvider(new SystemResponseDTO()); + dto.setService(new ServiceDefinitionResponseDTO()); + testingObject.removeTemporaryLock(dto); + + verify(qosReservationRepository, times(1)).delete(reservation); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testExtendReservationReservedNull() { + testingObject.extendReservation(null, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testExtendReservationProviderNull() { + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + testingObject.extendReservation(dto, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testExtendReservationServiceNull() { + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + dto.setProvider(new SystemResponseDTO()); + testingObject.extendReservation(dto, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testExtendReservationRequesterNull() { + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + dto.setProvider(new SystemResponseDTO()); + dto.setService(new ServiceDefinitionResponseDTO()); + testingObject.extendReservation(dto, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testExtendReservationRequesterSystemNameNull() { + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + dto.setProvider(new SystemResponseDTO()); + dto.setService(new ServiceDefinitionResponseDTO()); + final SystemRequestDTO requester = new SystemRequestDTO(); + testingObject.extendReservation(dto, requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testExtendReservationRequesterSystemNameEmpty() { + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + dto.setProvider(new SystemResponseDTO()); + dto.setService(new ServiceDefinitionResponseDTO()); + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName(" "); + testingObject.extendReservation(dto, requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testExtendReservationRequesterAddressNull() { + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + dto.setProvider(new SystemResponseDTO()); + dto.setService(new ServiceDefinitionResponseDTO()); + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + testingObject.extendReservation(dto, requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testExtendReservationRequesterAddressEmpty() { + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + dto.setProvider(new SystemResponseDTO()); + dto.setService(new ServiceDefinitionResponseDTO()); + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress(" "); + testingObject.extendReservation(dto, requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testExtendReservationRequesterPortNull() { + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + dto.setProvider(new SystemResponseDTO()); + dto.setService(new ServiceDefinitionResponseDTO()); + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress("address"); + testingObject.extendReservation(dto, requester); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExtendReservationOk() { + ReflectionTestUtils.setField(testingObject, "maxReservationDuration", 1000); + final QoSReservation reservation = new QoSReservation(); + when(qosReservationRepository.findByReservedProviderIdAndReservedServiceId(anyLong(), anyLong())).thenReturn(Optional.of(reservation)); + when(qosReservationRepository.saveAndFlush(reservation)).thenReturn(reservation); + + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + dto.setProvider(new SystemResponseDTO()); + dto.setService(new ServiceDefinitionResponseDTO()); + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress("address"); + requester.setPort(1234); + testingObject.extendReservation(dto, requester); + + verify(qosReservationRepository, times(1)).saveAndFlush(reservation); + } +} \ No newline at end of file diff --git a/orchestrator/src/test/java/eu/arrowhead/core/qos/manager/impl/DummyQoSManagerTest.java b/orchestrator/src/test/java/eu/arrowhead/core/qos/manager/impl/DummyQoSManagerTest.java new file mode 100644 index 000000000..08f5b9373 --- /dev/null +++ b/orchestrator/src/test/java/eu/arrowhead/core/qos/manager/impl/DummyQoSManagerTest.java @@ -0,0 +1,71 @@ +package eu.arrowhead.core.qos.manager.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.junit4.SpringRunner; + +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; + +@RunWith(SpringRunner.class) +public class DummyQoSManagerTest { + + //================================================================================================= + // members + + private final DummyQoSManager qosManager = new DummyQoSManager(); + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Test + public void testFilterReservedProvidersDoNothing() { + final List filtered = qosManager.filterReservedProviders(getTestOrchestrationResults(), null); + Assert.assertEquals(3, filtered.size()); + for (int i = 0; i < 3; ++i) { + Assert.assertEquals(i, filtered.get(i).getProvider().getId()); + } + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testReserveProvidersTemporarilyDoNothing() { + final List reserved = qosManager.reserveProvidersTemporarily(getTestOrchestrationResults(), null); + Assert.assertEquals(3, reserved.size()); + for (int i = 0; i < 3; ++i) { + Assert.assertEquals(i, reserved.get(i).getProvider().getId()); + } + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyServicesDoNothing() { + final List verified = qosManager.verifyServices(getTestOrchestrationResults(), null); + Assert.assertEquals(3, verified.size()); + for (int i = 0; i < 3; ++i) { + Assert.assertEquals(i, verified.get(i).getProvider().getId()); + } + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + private List getTestOrchestrationResults() { + final List result = new ArrayList<>(); + for (int i = 0; i < 3; ++i) { + final OrchestrationResultDTO dto = new OrchestrationResultDTO(); + final SystemResponseDTO system = new SystemResponseDTO(i, "System" + i, "localhost", 3000 + i, null, null, null); + dto.setProvider(system); + result.add(dto); + } + + return result; + } + +} \ No newline at end of file diff --git a/orchestrator/src/test/java/eu/arrowhead/core/qos/manager/impl/PingRequirementsVerifierTest.java b/orchestrator/src/test/java/eu/arrowhead/core/qos/manager/impl/PingRequirementsVerifierTest.java new file mode 100644 index 000000000..1103cd3b5 --- /dev/null +++ b/orchestrator/src/test/java/eu/arrowhead/core/qos/manager/impl/PingRequirementsVerifierTest.java @@ -0,0 +1,669 @@ +package eu.arrowhead.core.qos.manager.impl; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.time.ZonedDateTime; +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.util.ReflectionTestUtils; + +import eu.arrowhead.common.dto.internal.PingMeasurementResponseDTO; +import eu.arrowhead.common.dto.internal.QoSIntraMeasurementResponseDTO; +import eu.arrowhead.common.dto.shared.OrchestrationFormRequestDTO; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.common.exception.BadPayloadException; +import eu.arrowhead.common.exception.InvalidParameterException; +import eu.arrowhead.core.orchestrator.service.OrchestratorDriver; + +@RunWith(SpringRunner.class) +public class PingRequirementsVerifierTest { + + //================================================================================================= + // members + + @InjectMocks + private PingRequirementsVerifier verifier; + + @Mock + private OrchestratorDriver orchestratorDriver; + + @Mock + private Map pingMeasurementCache; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Before + public void setUp() { + ReflectionTestUtils.setField(verifier, "pingMeasurementCacheThreshold", 120); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testVerifyResultNull() { + verifier.verify(null, null, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testVerifyResultProviderNull() { + verifier.verify(new OrchestrationResultDTO(), null, null); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyQosRequirementsNull() { // answer true + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + result.setProvider(new SystemResponseDTO()); + + final boolean verified = verifier.verify(result, null, null); + Assert.assertTrue(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyQosRequirementsEmpty() { // answer true + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + result.setProvider(new SystemResponseDTO()); + + final boolean verified = verifier.verify(result, Map.of(), null); + Assert.assertTrue(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = BadPayloadException.class) + public void testVerifyInvalidSystemId() { + when(pingMeasurementCache.get(anyLong())).thenReturn(null); + when(orchestratorDriver.getPingMeasurement(anyLong())).thenThrow(new BadPayloadException("test")); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(-1); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD, "500"); + + verifier.verify(result, qosRequirements, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testVerifyObsoleteCache() { + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now().minusHours(2)); + response.setMeasurement(measurement); + when(pingMeasurementCache.get(anyLong())).thenReturn(response); + when(orchestratorDriver.getPingMeasurement(anyLong())).thenThrow(new ArrowheadException("just for finish the method execution")); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD, "500"); + + verifier.verify(result, qosRequirements, null); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyNoMeasurementRecordUsingDefaultTrue() { + ReflectionTestUtils.setField(verifier, "verifyNotMeasuredSystem", true); + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + Assert.assertFalse(response.hasRecord()); + when(pingMeasurementCache.get(anyLong())).thenReturn(null); + when(orchestratorDriver.getPingMeasurement(anyLong())).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD, "500"); + + final boolean verified = verifier.verify(result, qosRequirements, null); + Assert.assertTrue(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyNoMeasurementRecordUsingDefaultFalse() { + ReflectionTestUtils.setField(verifier, "verifyNotMeasuredSystem", false); + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + Assert.assertFalse(response.hasRecord()); + when(pingMeasurementCache.get(anyLong())).thenReturn(null); + when(orchestratorDriver.getPingMeasurement(anyLong())).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD, "500"); + + final boolean verified = verifier.verify(result, qosRequirements, null); + Assert.assertFalse(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifySystemNotAvailable() { + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + response.setId(12L); + response.setAvailable(false); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(anyLong())).thenReturn(null); + when(orchestratorDriver.getPingMeasurement(anyLong())).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD, "500"); + + final boolean verified = verifier.verify(result, qosRequirements, null); + Assert.assertFalse(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testVerifyMaximumThresholdResponseRequirementInvalid() { // also tests that cache is stored the measurement + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setMaxResponseTime(32); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(anyLong())).thenReturn(null); + when(pingMeasurementCache.put(anyLong(), any())).thenReturn(response); + when(orchestratorDriver.getPingMeasurement(anyLong())).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD, "invalid"); + + try { + verifier.verify(result, qosRequirements, null); + } catch (final InvalidParameterException ex) { // catch exception to test the caching + verify(pingMeasurementCache, times(1)).put(anyLong(), any()); + throw ex; + } + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testVerifyMaximumThresholdResponseRequirementNotPositive() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setMaxResponseTime(32); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD, "0"); + + verifier.verify(result, qosRequirements, null); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyMaximumThresholdResponseRequirementNotVerified() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setMaxResponseTime(32); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD, "30"); + + final boolean verified = verifier.verify(result, qosRequirements, null); + Assert.assertFalse(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyMaximumThresholdResponseRequirementVerified() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setMaxResponseTime(32); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RESPONSE_TIME_THRESHOLD, "300"); + + final boolean verified = verifier.verify(result, qosRequirements, null); + Assert.assertTrue(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testVerifyAverageThresholdResponseRequirementInvalid() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setMeanResponseTimeWithTimeout(32); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_AVERAGE_RESPONSE_TIME_THRESHOLD, "invalid"); + + verifier.verify(result, qosRequirements, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testVerifyAverageThresholdResponseRequirementNotPositive() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setMeanResponseTimeWithTimeout(32); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_AVERAGE_RESPONSE_TIME_THRESHOLD, "0"); + + verifier.verify(result, qosRequirements, null); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyAverageThresholdResponseRequirementNotVerified() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setMeanResponseTimeWithoutTimeout(32); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_AVERAGE_RESPONSE_TIME_THRESHOLD, "30"); + + final boolean verified = verifier.verify(result, qosRequirements, null); + Assert.assertFalse(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyAverageThresholdResponseRequirementVerified() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setMeanResponseTimeWithoutTimeout(32); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_AVERAGE_RESPONSE_TIME_THRESHOLD, "300"); + + final boolean verified = verifier.verify(result, qosRequirements, null); + Assert.assertTrue(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testVerifyJitterThresholdResponseRequirementInvalid() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setJitterWithoutTimeout(32); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_JITTER_THRESHOLD, "invalid"); + + verifier.verify(result, qosRequirements, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testVerifyJitterThresholdResponseRequirementNegative() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setJitterWithoutTimeout(32); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_JITTER_THRESHOLD, "-2"); + + verifier.verify(result, qosRequirements, null); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyJitterThresholdResponseRequirementNotVerified() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setJitterWithoutTimeout(32); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_JITTER_THRESHOLD, "30"); + + final boolean verified = verifier.verify(result, qosRequirements, null); + Assert.assertFalse(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyJitterThresholdResponseRequirementVerified() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setJitterWithoutTimeout(32); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_JITTER_THRESHOLD, "300"); + + final boolean verified = verifier.verify(result, qosRequirements, null); + Assert.assertTrue(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testVerifyRecentPacketLossRequirementInvalid() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setReceived(20); + response.setSent(100); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RECENT_PACKET_LOSS, "invalid"); + + verifier.verify(result, qosRequirements, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testVerifyRecentPacketLossRequirementNegative() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setReceived(20); + response.setSent(100); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RECENT_PACKET_LOSS, "-2"); + + verifier.verify(result, qosRequirements, null); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyRecentPacketLossRequirementNotVerified() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setReceived(20); + response.setSent(100); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RECENT_PACKET_LOSS, "10"); + + final boolean verified = verifier.verify(result, qosRequirements, null); + Assert.assertFalse(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyRecentPacketLossRequirementVerified() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setReceived(20); + response.setSent(100); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_RECENT_PACKET_LOSS, "85"); + + final boolean verified = verifier.verify(result, qosRequirements, null); + Assert.assertTrue(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testVerifyPacketLossRequirementInvalid() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setReceivedAll(20); + response.setSentAll(100); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_PACKET_LOSS, "invalid"); + + verifier.verify(result, qosRequirements, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testVerifyPacketLossRequirementNegative() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setReceivedAll(20); + response.setSentAll(100); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_PACKET_LOSS, "-2"); + + verifier.verify(result, qosRequirements, null); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyPacketLossRequirementNotVerified() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setReceivedAll(20); + response.setSentAll(100); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_PACKET_LOSS, "10"); + + final boolean verified = verifier.verify(result, qosRequirements, null); + Assert.assertFalse(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyPacketLossRequirementVerified() { // measurement comes from cache + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + final QoSIntraMeasurementResponseDTO measurement = new QoSIntraMeasurementResponseDTO(); + measurement.setLastMeasurementAt(ZonedDateTime.now()); + response.setMeasurement(measurement); + response.setId(12L); + response.setAvailable(true); + response.setReceivedAll(20); + response.setSentAll(100); + Assert.assertTrue(response.hasRecord()); + when(pingMeasurementCache.get(2L)).thenReturn(response); + + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(2); + result.setProvider(provider); + final Map qosRequirements = new HashMap<>(); + qosRequirements.put(OrchestrationFormRequestDTO.QOS_REQUIREMENT_MAXIMUM_PACKET_LOSS, "85"); + + final boolean verified = verifier.verify(result, qosRequirements, null); + Assert.assertTrue(verified); + } +} \ No newline at end of file diff --git a/orchestrator/src/test/java/eu/arrowhead/core/qos/manager/impl/QoSManagerImplTest.java b/orchestrator/src/test/java/eu/arrowhead/core/qos/manager/impl/QoSManagerImplTest.java new file mode 100644 index 000000000..079b55f46 --- /dev/null +++ b/orchestrator/src/test/java/eu/arrowhead/core/qos/manager/impl/QoSManagerImplTest.java @@ -0,0 +1,434 @@ +package eu.arrowhead.core.qos.manager.impl; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.anyMap; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.util.ReflectionTestUtils; + +import eu.arrowhead.common.dto.shared.OrchestrationFormRequestDTO; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; +import eu.arrowhead.common.dto.shared.ServiceDefinitionResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.core.qos.database.service.QoSReservationDBService; +import eu.arrowhead.core.qos.manager.QoSVerifier; + +@RunWith(SpringRunner.class) +public class QoSManagerImplTest { + + //================================================================================================= + // members + + @InjectMocks + private QoSManagerImpl qosManager; + + @Mock + private QoSReservationDBService qosReservationDBService; + + @Mock + private QoSVerifier verifier; + + @Mock + private QoSVerifier verifier2; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Before + public void setUp() { + @SuppressWarnings({ "unchecked", "rawtypes" }) + final List verifiers = (List) ReflectionTestUtils.getField(qosManager, "verifiers"); + verifiers.clear(); + verifiers.add(verifier); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testFilterReservedProvidersResultListNull() { + qosManager.filterReservedProviders(null, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testFilterReservedProvidersRequesterNull() { + qosManager.filterReservedProviders(List.of(), null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testFilterReservedProvidersRequesterSystemNameNull() { + final SystemRequestDTO requester = new SystemRequestDTO(); + qosManager.filterReservedProviders(List.of(), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testFilterReservedProvidersRequesterSystemNameEmpty() { + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName(" "); + qosManager.filterReservedProviders(List.of(), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testFilterReservedProvidersRequesterAddressNull() { + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + qosManager.filterReservedProviders(List.of(), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testFilterReservedProvidersRequesterAddressEmpty() { + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress(" "); + qosManager.filterReservedProviders(List.of(), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testFilterReservedProvidersRequesterPortNull() { + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress("localhost"); + qosManager.filterReservedProviders(List.of(), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testFilterReservedProvidersResultListEmpty() { + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress("localhost"); + requester.setPort(1234); + final List filtered = qosManager.filterReservedProviders(List.of(), requester); + Assert.assertEquals(0, filtered.size()); + verify(qosReservationDBService, never()).getAllReservationsExceptMine(anyString(), anyString(), anyInt()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testFilterReservedProvidersNothingIsReserved() { + when(qosReservationDBService.getAllReservationsExceptMine(anyString(), anyString(), anyInt())).thenReturn(List.of()); + + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress("localhost"); + requester.setPort(1234); + final List filtered = qosManager.filterReservedProviders(getOrList(3), requester); + Assert.assertEquals(3, filtered.size()); + verify(qosReservationDBService, times(1)).getAllReservationsExceptMine(anyString(), anyString(), anyInt()); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testReserveProvidersTemporarilyResultListNull() { + qosManager.reserveProvidersTemporarily(null, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testReserveProvidersTemporarilyRequesterNull() { + qosManager.reserveProvidersTemporarily(List.of(), null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testReserveProvidersTemporarilyRequesterSystemNameNull() { + final SystemRequestDTO requester = new SystemRequestDTO(); + qosManager.reserveProvidersTemporarily(List.of(), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testReserveProvidersTemporarilyRequesterSystemNameEmpty() { + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName(" "); + qosManager.reserveProvidersTemporarily(List.of(), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testReserveProvidersTemporarilyRequesterAddressNull() { + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + qosManager.reserveProvidersTemporarily(List.of(), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testReserveProvidersTemporarilyRequesterAddressEmpty() { + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress(" "); + qosManager.reserveProvidersTemporarily(List.of(), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testReserveProvidersTemporarilyRequesterPortNull() { + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress("localhost"); + qosManager.reserveProvidersTemporarily(List.of(), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testReserveProvidersTemporarilyResultListEmpty() { + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress("localhost"); + requester.setPort(1234); + final List reserved = qosManager.reserveProvidersTemporarily(List.of(), requester); + Assert.assertEquals(0, reserved.size()); + verify(qosReservationDBService, never()).applyTemporaryLock(anyString(), anyString(), anyInt(), any(OrchestrationResultDTO.class)); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testReserveProvidersTemporarilyLockFailed() { + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress("localhost"); + requester.setPort(1234); + doThrow(ArrowheadException.class).when(qosReservationDBService).applyTemporaryLock(anyString(), anyString(), anyInt(), any(OrchestrationResultDTO.class)); + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + result.setProvider(new SystemResponseDTO(1, "system", "localhost", 1234, null, null, null)); + result.setService(new ServiceDefinitionResponseDTO(1, "service", null, null)); + final List reserved = qosManager.reserveProvidersTemporarily(List.of(result), requester); + Assert.assertEquals(0, reserved.size()); + verify(qosReservationDBService, times(1)).applyTemporaryLock(anyString(), anyString(), anyInt(), any(OrchestrationResultDTO.class)); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testReserveProvidersTemporarilyLockSuccess() { + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress("localhost"); + requester.setPort(1234); + doNothing().when(qosReservationDBService).applyTemporaryLock(anyString(), anyString(), anyInt(), any(OrchestrationResultDTO.class)); + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + result.setProvider(new SystemResponseDTO(1, "system", "localhost", 1234, null, null, null)); + result.setService(new ServiceDefinitionResponseDTO(1, "service", null, null)); + final List reserved = qosManager.reserveProvidersTemporarily(List.of(result), requester); + Assert.assertEquals(1, reserved.size()); + verify(qosReservationDBService, times(1)).applyTemporaryLock(anyString(), anyString(), anyInt(), any(OrchestrationResultDTO.class)); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testConfirmReservationSelectedNull() { + qosManager.confirmReservation(null, null, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testConfirmReservationResultListNull() { + qosManager.confirmReservation(new OrchestrationResultDTO(), null, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testConfirmReservationResultListEmpty() { + qosManager.confirmReservation(new OrchestrationResultDTO(), List.of(), null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testConfirmReservationRequesterNull() { + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + qosManager.confirmReservation(result, List.of(result), null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testConfirmReservationRequesterSystemNameNull() { + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + final SystemRequestDTO requester = new SystemRequestDTO(); + qosManager.confirmReservation(result, List.of(result), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testConfirmReservationRequesterSystemNameEmpty() { + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName(" "); + qosManager.confirmReservation(result, List.of(result), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testConfirmReservationRequesterAddressNull() { + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + qosManager.confirmReservation(result, List.of(result), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testConfirmReservationRequesterAddressEmpty() { + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress(" "); + qosManager.confirmReservation(result, List.of(result), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testConfirmReservationRequesterPortNull() { + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress("localhost"); + qosManager.confirmReservation(result, List.of(result), requester); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testConfirmReservationOk() { + final SystemRequestDTO requester = new SystemRequestDTO(); + requester.setSystemName("system"); + requester.setAddress("localhost"); + requester.setPort(1234); + final List orList = getOrList(3); + doNothing().when(qosReservationDBService).extendReservation(any(OrchestrationResultDTO.class), any(SystemRequestDTO.class)); + doNothing().when(qosReservationDBService).removeTemporaryLock(any(OrchestrationResultDTO.class)); + + qosManager.confirmReservation(orList.get(1), orList, requester); + + verify(qosReservationDBService, times(1)).extendReservation(any(OrchestrationResultDTO.class), any(SystemRequestDTO.class)); + verify(qosReservationDBService, times(2)).removeTemporaryLock(any(OrchestrationResultDTO.class)); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testVerifyServicesResultListNull() { + qosManager.verifyServices(null, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testVerifyServicesRequestNull() { + qosManager.verifyServices(List.of(), null); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyServicesTrue() { + when(verifier.verify(any(OrchestrationResultDTO.class), anyMap(), anyMap())).thenReturn(true); + + final OrchestrationFormRequestDTO request = new OrchestrationFormRequestDTO(); + request.setCommands(Map.of()); + final List verifiedList = qosManager.verifyServices(getOrList(1), request); + verify(verifier, times(1)).verify(any(OrchestrationResultDTO.class), anyMap(), anyMap()); + Assert.assertEquals(1, verifiedList.size()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyServicesFalseNoExclusivity() { + when(verifier.verify(any(OrchestrationResultDTO.class), anyMap(), anyMap())).thenReturn(false); + + final OrchestrationFormRequestDTO request = new OrchestrationFormRequestDTO(); + request.setCommands(Map.of()); + final List verifiedList = qosManager.verifyServices(getOrList(1), request); + verify(verifier, times(1)).verify(any(OrchestrationResultDTO.class), anyMap(), anyMap()); + Assert.assertEquals(0, verifiedList.size()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyServicesFalseWithExclusivity() { + when(verifier.verify(any(OrchestrationResultDTO.class), anyMap(), anyMap())).thenReturn(false); + doNothing().when(qosReservationDBService).removeTemporaryLock(any(OrchestrationResultDTO.class)); + + final OrchestrationFormRequestDTO request = new OrchestrationFormRequestDTO(); + request.setCommands(Map.of(OrchestrationFormRequestDTO.QOS_COMMAND_EXCLUSIVITY, "100")); + final List verifiedList = qosManager.verifyServices(getOrList(1), request); + verify(verifier, times(1)).verify(any(OrchestrationResultDTO.class), anyMap(), anyMap()); + verify(qosReservationDBService).removeTemporaryLock(any(OrchestrationResultDTO.class)); + Assert.assertEquals(0, verifiedList.size()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyServicesNoVerifiers() { + @SuppressWarnings({ "unchecked", "rawtypes" }) + final List verifiers = (List) ReflectionTestUtils.getField(qosManager, "verifiers"); + verifiers.clear(); + when(verifier.verify(any(OrchestrationResultDTO.class), anyMap(), anyMap())).thenReturn(false); + + final OrchestrationFormRequestDTO request = new OrchestrationFormRequestDTO(); + request.setCommands(Map.of()); + final List verifiedList = qosManager.verifyServices(getOrList(1), request); + verify(verifier, never()).verify(any(OrchestrationResultDTO.class), anyMap(), anyMap()); + Assert.assertEquals(1, verifiedList.size()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyServicesFirstVerifierFalse() { + @SuppressWarnings({ "unchecked", "rawtypes" }) + final List verifiers = (List) ReflectionTestUtils.getField(qosManager, "verifiers"); + verifiers.clear(); + verifiers.add(verifier); + verifiers.add(verifier2); + when(verifier.verify(any(OrchestrationResultDTO.class), anyMap(), anyMap())).thenReturn(false); + when(verifier2.verify(any(OrchestrationResultDTO.class), anyMap(), anyMap())).thenReturn(true); + + final OrchestrationFormRequestDTO request = new OrchestrationFormRequestDTO(); + request.setCommands(Map.of()); + final List verifiedList = qosManager.verifyServices(getOrList(1), request); + verify(verifier, times(1)).verify(any(OrchestrationResultDTO.class), anyMap(), anyMap()); + verify(verifier2, never()).verify(any(OrchestrationResultDTO.class), anyMap(), anyMap()); + Assert.assertEquals(0, verifiedList.size()); + } + + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + private List getOrList(final int num) { + final List orList = new ArrayList<>(num); + for (int i = 0; i < num; ++i) { + final SystemResponseDTO provider = new SystemResponseDTO(); + provider.setId(i); + final ServiceDefinitionResponseDTO service = new ServiceDefinitionResponseDTO(); + service.setId(1); + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + result.setProvider(provider); + result.setService(service); + orList.add(result); + } + + return orList; + } +} \ No newline at end of file diff --git a/orchestrator/src/test/java/eu/arrowhead/core/qos/manager/impl/ServiceTimeVerifierTest.java b/orchestrator/src/test/java/eu/arrowhead/core/qos/manager/impl/ServiceTimeVerifierTest.java new file mode 100644 index 000000000..3fdb9f31e --- /dev/null +++ b/orchestrator/src/test/java/eu/arrowhead/core/qos/manager/impl/ServiceTimeVerifierTest.java @@ -0,0 +1,172 @@ +package eu.arrowhead.core.qos.manager.impl; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.test.context.junit4.SpringRunner; + +import eu.arrowhead.common.dto.shared.OrchestrationFormRequestDTO; +import eu.arrowhead.common.dto.shared.OrchestrationResultDTO; +import eu.arrowhead.common.dto.shared.OrchestratorWarnings; +import eu.arrowhead.common.dto.shared.ServiceRegistryRequestDTO; +import eu.arrowhead.core.orchestrator.service.OrchestratorDriver; + +@RunWith(SpringRunner.class) +public class ServiceTimeVerifierTest { + + //================================================================================================= + // members + + private final ServiceTimeVerifier verfier = new ServiceTimeVerifier(); + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testVerifyResultNull() { + verfier.verify(null, null, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testVerifyResultMetadataNull() { + verfier.verify(new OrchestrationResultDTO(), null, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testVerifyResultWarningsNull() { + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + result.setMetadata(Map.of()); + result.setWarnings(null); + verfier.verify(result, null, null); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testVerifyResultCommandsNull() { + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + result.setMetadata(Map.of()); + verfier.verify(result, null, null); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyNoRecommendedTimeNoExclusivityNoChange() { + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + result.setMetadata(Map.of()); + result.getWarnings().add(OrchestratorWarnings.TTL_UNKNOWN); + + final boolean verified = verfier.verify(result, null, Map.of()); + Assert.assertTrue(verified); + Assert.assertEquals(OrchestratorWarnings.TTL_UNKNOWN, result.getWarnings().get(0)); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyIllFormedRecommendedTimeNoExclusivityNoChange() { + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + result.setMetadata(Map.of(ServiceRegistryRequestDTO.KEY_RECOMMENDED_ORCHESTRATION_TIME, "not a number")); + result.getWarnings().add(OrchestratorWarnings.TTL_UNKNOWN); + + final boolean verified = verfier.verify(result, null, Map.of()); + Assert.assertTrue(verified); + Assert.assertEquals(OrchestratorWarnings.TTL_UNKNOWN, result.getWarnings().get(0)); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyNoRecommendedTimeWithExclusivityVerified() { // answer true, calculated time: 15, warnings: TTL_EXPIRING + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + final Map metadata = new HashMap<>(); + result.setMetadata(metadata); + result.getWarnings().add(OrchestratorWarnings.TTL_UNKNOWN); + + final boolean verified = verfier.verify(result, null, Map.of(OrchestrationFormRequestDTO.QOS_COMMAND_EXCLUSIVITY, "10")); + Assert.assertTrue(verified); + Assert.assertEquals("15", result.getMetadata().get(OrchestratorDriver.KEY_CALCULATED_SERVICE_TIME_FRAME)); + Assert.assertTrue(result.getWarnings().indexOf(OrchestratorWarnings.TTL_UNKNOWN) < 0); + Assert.assertEquals(OrchestratorWarnings.TTL_EXPIRING, result.getWarnings().get(0)); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyIllFormedRecommendedTimeWithExclusivityVerified() { // answer true, calculated time: 15, warnings: TTL_EXPIRING + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + final Map metadata = new HashMap<>(); + metadata.put(ServiceRegistryRequestDTO.KEY_RECOMMENDED_ORCHESTRATION_TIME, "not a number"); + result.setMetadata(metadata); + result.getWarnings().add(OrchestratorWarnings.TTL_UNKNOWN); + + final boolean verified = verfier.verify(result, null, Map.of(OrchestrationFormRequestDTO.QOS_COMMAND_EXCLUSIVITY, "10")); + Assert.assertTrue(verified); + Assert.assertEquals("15", result.getMetadata().get(OrchestratorDriver.KEY_CALCULATED_SERVICE_TIME_FRAME)); + Assert.assertTrue(result.getWarnings().indexOf(OrchestratorWarnings.TTL_UNKNOWN) < 0); + Assert.assertEquals(OrchestratorWarnings.TTL_EXPIRING, result.getWarnings().get(0)); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyTooShortRecommendedTimeWithExclusivityNotVerified() { // answer false + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + final Map metadata = new HashMap<>(); + metadata.put(ServiceRegistryRequestDTO.KEY_RECOMMENDED_ORCHESTRATION_TIME, "5"); + result.setMetadata(metadata); + result.getWarnings().add(OrchestratorWarnings.TTL_UNKNOWN); + + final boolean verified = verfier.verify(result, null, Map.of(OrchestrationFormRequestDTO.QOS_COMMAND_EXCLUSIVITY, "10")); + Assert.assertFalse(verified); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyEnoughRecommendedTimeWithExclusivityVerified() { // answer true, calculated time: 15, warnings: TTL_EXPIRING + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + final Map metadata = new HashMap<>(); + metadata.put(ServiceRegistryRequestDTO.KEY_RECOMMENDED_ORCHESTRATION_TIME, "14"); // extra seconds does not count + result.setMetadata(metadata); + result.getWarnings().add(OrchestratorWarnings.TTL_UNKNOWN); + + final boolean verified = verfier.verify(result, null, Map.of(OrchestrationFormRequestDTO.QOS_COMMAND_EXCLUSIVITY, "10")); + Assert.assertTrue(verified); + Assert.assertEquals("15", result.getMetadata().get(OrchestratorDriver.KEY_CALCULATED_SERVICE_TIME_FRAME)); + Assert.assertTrue(result.getWarnings().indexOf(OrchestratorWarnings.TTL_UNKNOWN) < 0); + Assert.assertEquals(OrchestratorWarnings.TTL_EXPIRING, result.getWarnings().get(0)); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyAlmostEnoughRecommendedTimeWithExclusivityVerified() { // answer true, calculated time: 16, warnings: TTL_EXPIRING + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + final Map metadata = new HashMap<>(); + metadata.put(ServiceRegistryRequestDTO.KEY_RECOMMENDED_ORCHESTRATION_TIME, "10"); // extra seconds does not count + result.setMetadata(metadata); + result.getWarnings().add(OrchestratorWarnings.TTL_UNKNOWN); + + final boolean verified = verfier.verify(result, null, Map.of(OrchestrationFormRequestDTO.QOS_COMMAND_EXCLUSIVITY, "11")); + Assert.assertTrue(verified); + Assert.assertEquals("16", result.getMetadata().get(OrchestratorDriver.KEY_CALCULATED_SERVICE_TIME_FRAME)); + Assert.assertTrue(result.getWarnings().indexOf(OrchestratorWarnings.TTL_UNKNOWN) < 0); + Assert.assertEquals(OrchestratorWarnings.TTL_EXPIRING, result.getWarnings().get(0)); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testVerifyEnoughRecommendedTimeWithExclusivityVerifiedNoWarning() { // answer true, calculated time: 126, warnings: none + final OrchestrationResultDTO result = new OrchestrationResultDTO(); + final Map metadata = new HashMap<>(); + metadata.put(ServiceRegistryRequestDTO.KEY_RECOMMENDED_ORCHESTRATION_TIME, "240"); + result.setMetadata(metadata); + result.getWarnings().add(OrchestratorWarnings.TTL_UNKNOWN); + + final boolean verified = verfier.verify(result, null, Map.of(OrchestrationFormRequestDTO.QOS_COMMAND_EXCLUSIVITY, "121")); + Assert.assertTrue(verified); + Assert.assertEquals("126", result.getMetadata().get(OrchestratorDriver.KEY_CALCULATED_SERVICE_TIME_FRAME)); + Assert.assertTrue(result.getWarnings().indexOf(OrchestratorWarnings.TTL_UNKNOWN) < 0); + Assert.assertEquals(0, result.getWarnings().size()); + } +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 785a20381..576c04a1b 100644 --- a/pom.xml +++ b/pom.xml @@ -12,7 +12,7 @@ ${revision} pom core-java-spring - Arrowhead Core Sevices using Spring Boot + Arrowhead Core Services using Spring Boot https://github.com/arrowhead-f/core-java-spring @@ -26,12 +26,18 @@ core-common serviceregistry authorization + certificate-authority orchestrator eventhandler gatekeeper gateway choreographer + systemregistry + deviceregistry + onboarding + qos-monitor deb-installer + docker-all @@ -53,9 +59,20 @@ 3.9 2.0.1 5.15.9 + 1.64 + 1.2 + 5.5.0 UTF-8 + + + spring-repo + Spring Repository + https://repo.spring.io/plugins-release/ + + + org.springframework.boot @@ -147,7 +164,23 @@ ${mysql.jdbc.driver} runtime - + + + sheltekio.javalibs + icmp4j + ${icmp4j.version} + + + net.java.dev.jna + jna + ${jna.version} + + + net.java.dev.jna + jna-platform + ${jna.version} + + + validate + + copy-resources + + + ${basedir}/target + + + src/main/resources + + application.properties + log4j2.xml + + + + + + + + + + jdeb + org.vafer + 1.8 + + + package + + jdeb + + + true + [YYMMddHHmm].${git.commit.id.abbrev} + target/${project.artifactId}_${revision}.deb + true + ${basedir}/src/deb/control + + + file + ${project.build.directory}/${project.build.finalName}.jar + + perm + /usr/share/arrowhead/qos_monitor + 755 + + + + + link + /usr/share/arrowhead/qos_monitor/${project.artifactId}.jar + /usr/share/arrowhead/qos_monitor/${project.build.finalName}.jar + + + + file + ${project.build.directory}/log4j2.xml + + perm + /etc/arrowhead/systems/qos_monitor + 644 + + + + + file + ${project.build.directory}/application.properties + + perm + /etc/arrowhead/systems/qos_monitor + 644 + + + + + link + /usr/share/arrowhead/qos_monitor/application.properties + /etc/arrowhead/systems/qos_monitor/application.properties + + + + file + ${project.basedir}/src/deb/arrowhead-qos-monitor.service + + perm + /etc/systemd/system + 644 + + + + + file + ${project.basedir}/../scripts/qos_monitor_privileges.sql + + perm + /usr/share/arrowhead/conf + + + + + + + + + + \ No newline at end of file diff --git a/qos-monitor/src/deb/arrowhead-qos-monitor.service b/qos-monitor/src/deb/arrowhead-qos-monitor.service new file mode 100644 index 000000000..6be5ed4b8 --- /dev/null +++ b/qos-monitor/src/deb/arrowhead-qos-monitor.service @@ -0,0 +1,14 @@ +[Unit] +Description=arrowhead-qos-monitor +After=network.target mysql.target + +[Service] +WorkingDirectory=/etc/arrowhead/systems/qos_monitor +ExecStart=/usr/bin/java -Dlog4j.configurationFile=file:/etc/arrowhead/systems/qos_monitor/log4j2.xml -jar /usr/share/arrowhead/qos_monitor/arrowhead-qos-monitor.jar +TimeoutStopSec=5 +Type=simple +User=arrowhead +Group=arrowhead + +[Install] +WantedBy=default.target \ No newline at end of file diff --git a/qos-monitor/src/deb/control/config b/qos-monitor/src/deb/control/config new file mode 100644 index 000000000..90d57e988 --- /dev/null +++ b/qos-monitor/src/deb/control/config @@ -0,0 +1,19 @@ +#!/bin/sh -e + +. /usr/share/debconf/confmodule + +if logname 2>/dev/null; then + USER=$(logname) + HOME=$(eval echo "~$USER") +else + USER="root" + HOME="/root" +fi + +# Get installation type +db_input high arrowhead-core-common/db_host || true +db_input high arrowhead-core-common/mysql_password_qos || true +db_input high arrowhead-core-common/sr_host || true + +# Run dialogs +db_go || true \ No newline at end of file diff --git a/qos-monitor/src/deb/control/control b/qos-monitor/src/deb/control/control new file mode 100644 index 000000000..9d4f850cd --- /dev/null +++ b/qos-monitor/src/deb/control/control @@ -0,0 +1,10 @@ +Package: arrowhead-qos-monitor +Version: [[version]] +Section: contrib/java +Priority: optional +Architecture: all +Maintainer: Rajmund Bocsi +Homepage: http://www.arrowhead.eu +Description: Arrowhead QoS Monitor System +Distribution: development +Depends: java-runtime-headless, virtual-mysql-server, arrowhead-core-common \ No newline at end of file diff --git a/qos-monitor/src/deb/control/postinst b/qos-monitor/src/deb/control/postinst new file mode 100644 index 000000000..a33a43110 --- /dev/null +++ b/qos-monitor/src/deb/control/postinst @@ -0,0 +1,103 @@ +#!/bin/sh +# postinst script for arrowhead-event-handler +# +# see: dh_installdeb(1) + +set -e + +. /usr/share/debconf/confmodule + +SYSTEM_NAME="qos_monitor" +PKG_NAME="arrowhead-qos-monitor" + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + +case "$1" in + configure) + + dos2unix -q /etc/systemd/system/${PKG_NAME}.service + + . /usr/share/arrowhead/conf/ahconf.sh + SYSTEM_DIR="${AH_SYSTEMS_DIR}/${SYSTEM_NAME}" + + db_get arrowhead-core-common/mysql_password_qos; system_passwd=$RET || true + db_unregister arrowhead-core-common/mysql_password_qos + + # Generate password (if required) + if [ -z "${system_passwd}" ]; then + system_passwd="$(openssl rand -base64 12)" + fi + + echo "Configuring MySQL database..." >&2 + ah_db_tables_and_user ${SYSTEM_NAME} ${SYSTEM_NAME}_privileges.sql ${system_passwd} + + if [ ! -d "${SYSTEM_DIR}" ]; then + mkdir -p ${SYSTEM_DIR} + fi + + domain_name=${AH_DOMAIN_NAME} + if [ -z ${domain_name} ]; then + domain_name=${OWN_IP} + fi + + ah_cert_signed_system ${SYSTEM_NAME} + + # modify log config and application.properties + + ah_transform_log_file ${SYSTEM_DIR} + + db_get arrowhead-core-common/sr_host; sr_host=$RET || true + + if [ -z ${sr_host} ]; then + sr_host=${OWN_IP} + fi + + db_get arrowhead-core-common/db_host; db_host=$RET || true + + mv ${SYSTEM_DIR}/application.properties ${SYSTEM_DIR}/application.properties.orig + cat ${SYSTEM_DIR}/application.properties.orig | \ + sed -r -e "\#^.*spring\.datasource\.url=#s#.*\$#spring.datasource.url=jdbc:mysql://"${db_host}":3306/arrowhead?serverTimezone=Europe/Budapest#" \ + -e "\#^.*spring\.datasource\.password=#s#.*\$#spring.datasource.password=${system_passwd}#" \ + -e "\#^.*domain\.name=#s#.*\$#domain.name=${domain_name}#" \ + -e "\#^.*sr_address=#s#.*\$#sr_address=${sr_host}#" \ + -e "\#^.*server\.ssl\.key-store=#s#.*\$#server.ssl.key-store=file:${SYSTEM_DIR}/${SYSTEM_NAME}.p12#" \ + -e "\#^.*server\.ssl\.key-store-password=#s#.*\$#server.ssl.key-store-password=${AH_PASS_CERT}#" \ + -e "\#^.*server\.ssl\.key-password=#s#.*\$#server.ssl.key-password=${AH_PASS_CERT}#" \ + -e "\#^.*server\.ssl\.trust-store=#s#.*\$#server.ssl.trust-store=file:${AH_CONF_DIR}/truststore.p12#" \ + -e "\#^.*server\.ssl\.trust-store-password=#s#.*\$#server.ssl.trust-store-password=${AH_PASS_CERT}#" > ${SYSTEM_DIR}/application.properties + + rm ${SYSTEM_DIR}/application.properties.orig + chown arrowhead:arrowhead ${SYSTEM_DIR}/application.properties + chmod 640 ${SYSTEM_DIR}/application.properties + + echo "Starting ${PKG_NAME}..." >&2 + systemctl daemon-reload + systemctl enable ${PKG_NAME}.service + systemctl start ${PKG_NAME}.service + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/qos-monitor/src/deb/control/postrm b/qos-monitor/src/deb/control/postrm new file mode 100644 index 000000000..d38c5c154 --- /dev/null +++ b/qos-monitor/src/deb/control/postrm @@ -0,0 +1,54 @@ +#!/bin/sh +# postrm script for arrowhead-qos-monitor +# +# see: dh_installdeb(1) + +set -e + +. /usr/share/debconf/confmodule + +SYSTEM_NAME="qos_monitor" + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + purge) + AH_CONF_DIR="/etc/arrowhead" + AH_SYSTEMS_DIR="${AH_CONF_DIR}/systems" + SYSTEM_DIR="${AH_SYSTEMS_DIR}/${SYSTEM_NAME}" + + rm -f \ + /var/log/arrowhead/${SYSTEM_NAME}*.log \ + ${SYSTEM_DIR}/log4j2.xml \ + ${SYSTEM_DIR}/application.properties \ + ${SYSTEM_DIR}/${SYSTEM_NAME}.p12 \ + rmdir ${SYSTEM_DIR} 2>/dev/null || true + db_purge + ;; + remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/qos-monitor/src/deb/control/preinst b/qos-monitor/src/deb/control/preinst new file mode 100644 index 000000000..c0279957d --- /dev/null +++ b/qos-monitor/src/deb/control/preinst @@ -0,0 +1,35 @@ +#!/bin/sh +# preinst script for arrowhead-qos-monitor +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `install' +# * `install' +# * `upgrade' +# * `abort-upgrade' +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + install|upgrade) + ;; + + abort-upgrade) + ;; + + *) + echo "preinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 \ No newline at end of file diff --git a/qos-monitor/src/deb/control/prerm b/qos-monitor/src/deb/control/prerm new file mode 100644 index 000000000..1d6c454fc --- /dev/null +++ b/qos-monitor/src/deb/control/prerm @@ -0,0 +1,45 @@ +#!/bin/sh +# prerm script for arrowhead-qos-monitor +# +# see: dh_installdeb(1) + +set -e + +PKG_NAME="arrowhead-qos-monitor" + +# summary of how this script can be called: +# * `remove' +# * `upgrade' +# * `failed-upgrade' +# * `remove' `in-favour' +# * `deconfigure' `in-favour' +# `removing' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + remove) + systemctl stop ${PKG_NAME}.service + systemctl disable ${PKG_NAME}.service + ;; + + upgrade|deconfigure) + ;; + + failed-upgrade) + ;; + + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 \ No newline at end of file diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/QoSMonitorApplicationInitListener.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/QoSMonitorApplicationInitListener.java new file mode 100644 index 000000000..3458d0022 --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/QoSMonitorApplicationInitListener.java @@ -0,0 +1,44 @@ +package eu.arrowhead.core.qos; + +import java.util.Map; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; +import org.springframework.web.util.UriComponents; + +import eu.arrowhead.common.ApplicationInitListener; +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.Utilities; + +@Component +public class QoSMonitorApplicationInitListener extends ApplicationInitListener { + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + @Override + protected void customInit(final ContextRefreshedEvent event) { + logger.debug("customInit started..."); + + final ApplicationContext appContext = event.getApplicationContext(); + @SuppressWarnings("unchecked") + final Map context = appContext.getBean(CommonConstants.ARROWHEAD_CONTEXT, Map.class); + + final String scheme = sslProperties.isSslEnabled() ? CommonConstants.HTTPS : CommonConstants.HTTP; + + final UriComponents queryAll = createQueryAllUri(scheme); + context.put(CoreCommonConstants.SR_QUERY_ALL, queryAll); + } + + //------------------------------------------------------------------------------------------------- + private UriComponents createQueryAllUri(final String scheme) { + logger.debug("createQueryAllUri started..."); + + final String registyUriStr = CommonConstants.SERVICE_REGISTRY_URI + CoreCommonConstants.OP_SERVICE_REGISTRY_QUERY_ALL_URI; + + return Utilities.createURI(scheme, coreSystemRegistrationProperties.getServiceRegistryAddress(), coreSystemRegistrationProperties.getServiceRegistryPort(), registyUriStr); + } +} \ No newline at end of file diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/QoSMonitorController.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/QoSMonitorController.java new file mode 100644 index 000000000..02626d4ae --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/QoSMonitorController.java @@ -0,0 +1,161 @@ +package eu.arrowhead.core.qos; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.CoreDefaults; +import eu.arrowhead.common.CoreUtilities; +import eu.arrowhead.common.CoreUtilities.ValidatedPageParams; +import eu.arrowhead.common.Defaults; +import eu.arrowhead.common.dto.internal.PingMeasurementListResponseDTO; +import eu.arrowhead.common.dto.internal.PingMeasurementResponseDTO; +import eu.arrowhead.common.exception.BadPayloadException; +import eu.arrowhead.core.qos.database.service.QoSDBService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.RestController; + +@Api(tags = { CoreCommonConstants.SWAGGER_TAG_ALL }) +@CrossOrigin(maxAge = Defaults.CORS_MAX_AGE, allowCredentials = Defaults.CORS_ALLOW_CREDENTIALS, + allowedHeaders = { HttpHeaders.ORIGIN, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT, HttpHeaders.AUTHORIZATION } +) +@RestController +@RequestMapping(CommonConstants.QOS_MONITOR_URI) +public class QoSMonitorController { + + //================================================================================================= + // members + private static final String PATH_VARIABLE_ID = "id"; + + private static final String PING_MEASUREMENTS = "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/ping/measurements"; + private static final String QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI = CoreCommonConstants.MGMT_URI + PING_MEASUREMENTS; + private static final String GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_MGMT_URI = QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI + "/{" + PATH_VARIABLE_ID + "}"; + private static final String GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_URI = CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT + "/{" + PATH_VARIABLE_ID + "}"; + + private static final String GET_QOS_MONITOR_PING_MEASUREMENTS_MGMT_DESCRIPTION = "Return requested Ping-Measurements entries by the given parameters"; + private static final String GET_QOS_MONITOR_PING_MEASUREMENTS_MGMT_HTTP_200_MESSAGE = "Ping-Measurement entries returned"; + private static final String GET_QOS_MONITOR_PING_MEASUREMENTS_MGMT_HTTP_400_MESSAGE = "Could not retrieve Ping-Measurement entries"; + + private static final String GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_MGMT_DESCRIPTION = "Return requested Ping-Measurement entry by system id."; + private static final String GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_MGMT_HTTP_200_MESSAGE = "Ping-Measurement entry returned"; + private static final String GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_MGMT_HTTP_400_MESSAGE = "Could not retrieve Ping-Measurement entry"; + + private static final String OP_GET_QOS_MONITOR_PING_MEASUREMENT_BY_SYSTEM_ID_DESCRIPTION = "Return requested Ping-Measurement entry by system id."; + private static final String OP_GET_QOS_MONITOR_PING_MEASUREMENT_BY_SYSTEM_ID_HTTP_200_MESSAGE = "Ping-Measurement entry returned"; + private static final String OP_GET_QOS_MONITOR_PING_MEASUREMENT_BY_SYSTEM_ID_HTTP_400_MESSAGE = "Could not retrieve Ping-Measurement entry"; + + private static final String ID_NOT_VALID_ERROR_MESSAGE = " Id must be greater than 0. "; + + @Autowired + private QoSDBService qoSDBService; + + private final Logger logger = LogManager.getLogger(QoSMonitorController.class); + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return an echo message with the purpose of testing the core service availability", response = String.class, tags = { CoreCommonConstants.SWAGGER_TAG_CLIENT }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = CoreCommonConstants.SWAGGER_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = CommonConstants.ECHO_URI) + public String echoService() { + logger.debug("echoService started..."); + + return "Got it!"; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = GET_QOS_MONITOR_PING_MEASUREMENTS_MGMT_DESCRIPTION, response = PingMeasurementListResponseDTO.class, tags = { CoreCommonConstants.SWAGGER_TAG_MGMT }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_QOS_MONITOR_PING_MEASUREMENTS_MGMT_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_QOS_MONITOR_PING_MEASUREMENTS_MGMT_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody public PingMeasurementListResponseDTO getPingMeasurements( + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_PAGE, required = false) final Integer page, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_ITEM_PER_PAGE, required = false) final Integer size, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_DIRECTION, defaultValue = CoreDefaults.DEFAULT_REQUEST_PARAM_DIRECTION_VALUE) final String direction, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_SORT_FIELD, defaultValue = CommonConstants.COMMON_FIELD_NAME_ID) final String sortField) { + logger.debug("New getMeasurements get request recieved with page: {} and item_per page: {}", page, size); + + final ValidatedPageParams validParameters = CoreUtilities.validatePageParameters(page, size, direction, CommonConstants.QOS_MONITOR_URI + QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI); + final PingMeasurementListResponseDTO measurementResponse = qoSDBService.getPingMeasurementResponse(validParameters.getValidatedPage(), validParameters.getValidatedSize(), + validParameters.getValidatedDirection(), sortField); + + logger.debug("Measurements with page: {} and item_per page: {} retrieved successfully", page, size); + return measurementResponse; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_MGMT_DESCRIPTION, response = PingMeasurementResponseDTO.class, tags = { CoreCommonConstants.SWAGGER_TAG_MGMT }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_MGMT_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_MGMT_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_MGMT_URI, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody public PingMeasurementResponseDTO getManagementPingMeasurementBySystemId(@PathVariable(value = PATH_VARIABLE_ID) final long id) { + logger.debug("New getPingMeasurementBySystemId get request recieved with id: {}", id); + + final String origin = CommonConstants.QOS_MONITOR_URI + GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_MGMT_URI; + if (id < 1) { + throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + final PingMeasurementResponseDTO pingMeasurementResponse = qoSDBService.getPingMeasurementBySystemIdResponse(id); + + if (pingMeasurementResponse.getId() == null) { + + logger.debug("PingMeasurement entry with system id: {} is not available.", id); + + }else { + + logger.debug("PingMeasurement entry with system id: {} successfully retrieved.", id); + } + + return pingMeasurementResponse; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = OP_GET_QOS_MONITOR_PING_MEASUREMENT_BY_SYSTEM_ID_DESCRIPTION, response = PingMeasurementResponseDTO.class, tags = { CoreCommonConstants.SWAGGER_TAG_PRIVATE }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = OP_GET_QOS_MONITOR_PING_MEASUREMENT_BY_SYSTEM_ID_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = OP_GET_QOS_MONITOR_PING_MEASUREMENT_BY_SYSTEM_ID_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_URI, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody public PingMeasurementResponseDTO getPingMeasurementBySystemId(@PathVariable(value = PATH_VARIABLE_ID) final long id) { + logger.debug("New getPingMeasurementBySystemId get request recieved with id: {}", id); + + final String origin = CommonConstants.QOS_MONITOR_URI + GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_URI; + if (id < 1) { + throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + final PingMeasurementResponseDTO pingMeasurementResponse = qoSDBService.getPingMeasurementBySystemIdResponse(id); + + logger.debug("PingMeasurement entry with system id: {} successfully retrieved", id); + return pingMeasurementResponse; + } +} \ No newline at end of file diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/QoSMonitorMain.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/QoSMonitorMain.java new file mode 100644 index 000000000..2346305aa --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/QoSMonitorMain.java @@ -0,0 +1,31 @@ +package eu.arrowhead.core.qos; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.database.repository.RefreshableRepositoryImpl; +import eu.arrowhead.core.qos.measurement.properties.PingMeasurementProperties; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@SpringBootApplication +@EnableConfigurationProperties(PingMeasurementProperties.class) +@ComponentScan (CommonConstants.BASE_PACKAGE) +@EntityScan (CoreCommonConstants.DATABASE_ENTITY_PACKAGE) +@EnableJpaRepositories (basePackages = CoreCommonConstants.DATABASE_REPOSITORY_PACKAGE, repositoryBaseClass = RefreshableRepositoryImpl.class) +@EnableSwagger2 +public class QoSMonitorMain { + + //================================================================================================= + // members + + //------------------------------------------------------------------------------------------------- + public static void main(final String[] args) { + SpringApplication.run(QoSMonitorMain.class, args); + } +} \ No newline at end of file diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/database/service/QoSDBService.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/database/service/QoSDBService.java new file mode 100644 index 000000000..7ee5fa246 --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/database/service/QoSDBService.java @@ -0,0 +1,452 @@ +package eu.arrowhead.core.qos.database.service; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.icmp4j.IcmpPingResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort.Direction; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.database.entity.QoSIntraMeasurement; +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurement; +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurementLog; +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurementLogDetails; +import eu.arrowhead.common.database.entity.System; +import eu.arrowhead.common.database.repository.QoSIntraMeasurementPingRepository; +import eu.arrowhead.common.database.repository.QoSIntraMeasurementRepository; +import eu.arrowhead.common.database.repository.QoSIntraPingMeasurementLogDetailsRepository; +import eu.arrowhead.common.database.repository.QoSIntraPingMeasurementLogRepository; +import eu.arrowhead.common.database.repository.SystemRepository; +import eu.arrowhead.common.dto.internal.DTOConverter; +import eu.arrowhead.common.dto.internal.PingMeasurementListResponseDTO; +import eu.arrowhead.common.dto.internal.PingMeasurementResponseDTO; +import eu.arrowhead.common.dto.shared.QoSMeasurementType; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.common.exception.InvalidParameterException; +import eu.arrowhead.core.qos.dto.PingMeasurementCalculationsDTO; + +@Service +public class QoSDBService { + + //================================================================================================= + // members + + private static final String LESS_THAN_ONE_ERROR_MESSAGE= " must be greater than zero."; + private static final String NOT_AVAILABLE_SORTABLE_FIELD_ERROR_MESSAGE = " sortable field is not available."; + private static final String NOT_IN_DB_ERROR_MESSAGE = " is not available in database"; + private static final String EMPTY_OR_NULL_ERROR_MESSAGE = " is empty or null"; + private static final String NULL_ERROR_MESSAGE = " is null"; + + @Autowired + private QoSIntraMeasurementRepository qoSIntraMeasurementRepository; + + @Autowired + private QoSIntraMeasurementPingRepository qoSIntraMeasurementPingRepository; + + @Autowired + private QoSIntraPingMeasurementLogRepository qoSIntraPingMeasurementLogRepository; + + @Autowired + private QoSIntraPingMeasurementLogDetailsRepository qoSIntraPingMeasurementLogDetailsRepository; + + @Autowired + private SystemRepository systemRepository; + + protected Logger logger = LogManager.getLogger(QoSDBService.class); + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Transactional (rollbackFor = ArrowheadException.class) + public void updateCountStartedAt() { + logger.debug("updateCountStartedAt started..."); + + try { + final List measurementList = qoSIntraMeasurementPingRepository.findAll(); + for (final QoSIntraPingMeasurement qoSIntraPingMeasurement : measurementList) { + qoSIntraPingMeasurement.setSent(0); + qoSIntraPingMeasurement.setReceived(0); + qoSIntraPingMeasurement.setCountStartedAt(ZonedDateTime.now()); + } + qoSIntraMeasurementPingRepository.saveAll(measurementList); + qoSIntraMeasurementPingRepository.flush(); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + + } + + //------------------------------------------------------------------------------------------------- + @Transactional (rollbackFor = ArrowheadException.class) + public QoSIntraMeasurement createMeasurement(final System system, final QoSMeasurementType ping, final ZonedDateTime aroundNow) { + logger.debug("createMeasurement started..."); + + final QoSIntraMeasurement measurement = new QoSIntraMeasurement(system, QoSMeasurementType.PING, aroundNow); + measurement.setSystem(system); + measurement.setMeasurementType(QoSMeasurementType.PING); + + try { + qoSIntraMeasurementRepository.saveAndFlush(measurement); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + + return measurement; + } + + //------------------------------------------------------------------------------------------------- + @Transactional (rollbackFor = ArrowheadException.class) + public QoSIntraMeasurement getOrCreateMeasurement(final SystemResponseDTO systemResponseDTO) { + logger.debug("getMeasurement started..."); + + validateSystemResponseDTO(systemResponseDTO); + + final System system; + final Optional systemOptional = systemRepository.findBySystemNameAndAddressAndPort( + systemResponseDTO.getSystemName(), + systemResponseDTO.getAddress(), + systemResponseDTO.getPort()); + if (systemOptional.isPresent()) { + system = systemOptional.get(); + } else { + throw new InvalidParameterException("Requested system" + NOT_IN_DB_ERROR_MESSAGE); + } + + final QoSIntraMeasurement measurement; + final Optional qoSIntraMeasurementOptional = qoSIntraMeasurementRepository.findBySystemAndMeasurementType(system, QoSMeasurementType.PING); + if (qoSIntraMeasurementOptional.isEmpty()) { + final ZonedDateTime aroundNow = ZonedDateTime.now(); + measurement = createMeasurement(system, QoSMeasurementType.PING, aroundNow); + }else { + measurement = qoSIntraMeasurementOptional.get(); + } + + return measurement; + } + + //------------------------------------------------------------------------------------------------- + @Transactional (rollbackFor = ArrowheadException.class) + public void createPingMeasurement(final QoSIntraMeasurement measurementParam, final PingMeasurementCalculationsDTO calculations, final ZonedDateTime aroundNow) { + logger.debug("createPingMeasurement started..."); + + if (measurementParam == null) { + throw new InvalidParameterException("QoSIntraMeasurement" + NULL_ERROR_MESSAGE); + } + if (calculations == null) { + throw new InvalidParameterException("PingMeasurementCalculationsDTO" + NULL_ERROR_MESSAGE); + } + if (aroundNow == null) { + throw new InvalidParameterException("ZonedDateTime" + NULL_ERROR_MESSAGE); + } + + final QoSIntraPingMeasurement pingMeasurement = new QoSIntraPingMeasurement(); + + pingMeasurement.setMeasurement(measurementParam); + pingMeasurement.setAvailable(calculations.isAvailable()); + pingMeasurement.setMaxResponseTime(calculations.getMaxResponseTime()); + pingMeasurement.setMinResponseTime(calculations.getMinResponseTime()); + pingMeasurement.setMeanResponseTimeWithoutTimeout(calculations.getMeanResponseTimeWithoutTimeout()); + pingMeasurement.setMeanResponseTimeWithTimeout(calculations.getMeanResponseTimeWithTimeout()); + pingMeasurement.setJitterWithoutTimeout(calculations.getJitterWithoutTimeout()); + pingMeasurement.setJitterWithTimeout(calculations.getJitterWithTimeout()); + pingMeasurement.setLostPerMeasurementPercent(calculations.getLostPerMeasurementPercent()); + pingMeasurement.setCountStartedAt(aroundNow); + pingMeasurement.setLastAccessAt(calculations.isAvailable() ? aroundNow : null); + pingMeasurement.setSent(calculations.getSentInThisPing()); + pingMeasurement.setSentAll(calculations.getSentInThisPing()); + pingMeasurement.setReceived(calculations.getReceivedInThisPing()); + pingMeasurement.setReceivedAll(calculations.getReceivedInThisPing()); + + try { + + qoSIntraMeasurementPingRepository.saveAndFlush(pingMeasurement); + + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + + } + + //------------------------------------------------------------------------------------------------- + public Optional getPingMeasurementByMeasurement(final QoSIntraMeasurement measurement) { + logger.debug("getPingMeasurementByMeasurement started..."); + + if (measurement == null) { + throw new InvalidParameterException("QoSIntraMeasurement" + NULL_ERROR_MESSAGE); + } + + try { + return qoSIntraMeasurementPingRepository.findByMeasurement(measurement); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional (rollbackFor = ArrowheadException.class) + public QoSIntraPingMeasurementLog logMeasurementToDB(final String address, final PingMeasurementCalculationsDTO calculations, final ZonedDateTime aroundNow) { + logger.debug("logMeasurementToDB started..."); + + if (Utilities.isEmpty(address)) { + throw new InvalidParameterException("Address" + EMPTY_OR_NULL_ERROR_MESSAGE); + } else if (calculations == null) { + throw new InvalidParameterException("PingMeasurementCalculationsDTO" + NULL_ERROR_MESSAGE); + } else if (aroundNow == null) { + throw new InvalidParameterException("ZonedDateTime" + NULL_ERROR_MESSAGE); + } + + final QoSIntraPingMeasurementLog measurementLog = new QoSIntraPingMeasurementLog(); + measurementLog.setMeasuredSystemAddress(address); + measurementLog.setAvailable(calculations.isAvailable()); + measurementLog.setMinResponseTime(calculations.getMinResponseTime()); + measurementLog.setMaxResponseTime(calculations.getMaxResponseTime()); + measurementLog.setMeanResponseTimeWithoutTimeout(calculations.getMeanResponseTimeWithoutTimeout()); + measurementLog.setMeanResponseTimeWithTimeout(calculations.getMeanResponseTimeWithTimeout()); + measurementLog.setJitterWithoutTimeout(calculations.getJitterWithoutTimeout()); + measurementLog.setJitterWithTimeout(calculations.getJitterWithTimeout()); + measurementLog.setLostPerMeasurementPercent(calculations.getLostPerMeasurementPercent()); + measurementLog.setSent(calculations.getSentInThisPing()); + measurementLog.setReceived(calculations.getReceivedInThisPing()); + measurementLog.setMeasuredAt(aroundNow); + + try { + return qoSIntraPingMeasurementLogRepository.saveAndFlush(measurementLog); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + + } + + //------------------------------------------------------------------------------------------------- + @Transactional (rollbackFor = ArrowheadException.class) + public void logMeasurementDetailsToDB(final QoSIntraPingMeasurementLog measurementLogSaved, + final List responseList, final ZonedDateTime aroundNow) { + logger.debug("logMeasurementDetailsToDB started..."); + + if (responseList == null || responseList.isEmpty()) { + throw new InvalidParameterException("List" + EMPTY_OR_NULL_ERROR_MESSAGE); + } else if (measurementLogSaved == null) { + throw new InvalidParameterException("QoSIntraPingMeasurementLog" + NULL_ERROR_MESSAGE); + } else if (aroundNow == null) { + throw new InvalidParameterException("ZonedDateTime" + NULL_ERROR_MESSAGE); + } + + final List measurementLogDetailsList = new ArrayList<>(responseList.size()); + + int measurementSequenece = 0; + for (final IcmpPingResponse icmpPingResponse : responseList) { + + final QoSIntraPingMeasurementLogDetails measurementLogDetails = new QoSIntraPingMeasurementLogDetails(); + measurementLogDetails.setMeasurementLog(measurementLogSaved); + measurementLogDetails.setMeasurementSequeneceNumber( measurementSequenece++ ); + measurementLogDetails.setSuccessFlag(icmpPingResponse.getSuccessFlag()); + measurementLogDetails.setTimeoutFlag(icmpPingResponse.getTimeoutFlag()); + measurementLogDetails.setErrorMessage(icmpPingResponse.getErrorMessage()); + measurementLogDetails.setThrowable(icmpPingResponse.getThrowable() == null ? null : icmpPingResponse.getThrowable().toString()); + measurementLogDetails.setSize(icmpPingResponse.getSize()); + measurementLogDetails.setTtl(icmpPingResponse.getTtl()); + measurementLogDetails.setRtt(icmpPingResponse.getRtt()); + measurementLogDetails.setDuration((int) icmpPingResponse.getDuration()); + measurementLogDetails.setMeasuredAt(aroundNow); + + measurementLogDetailsList.add(measurementLogDetails); + } + + try { + qoSIntraPingMeasurementLogDetailsRepository.saveAll(measurementLogDetailsList); + qoSIntraPingMeasurementLogDetailsRepository.flush(); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional (rollbackFor = ArrowheadException.class) + public void updatePingMeasurement(final QoSIntraMeasurement measurement, + final PingMeasurementCalculationsDTO calculations, final QoSIntraPingMeasurement pingMeasurement,final ZonedDateTime aroundNow) { + logger.debug("updatePingMeasurement started..."); + + if (measurement == null) { + throw new InvalidParameterException("QoSIntraMeasurement" + NULL_ERROR_MESSAGE); + } else if (calculations == null) { + throw new InvalidParameterException("PingMeasurementCalculationsDTO" + NULL_ERROR_MESSAGE); + } else if (pingMeasurement == null) { + throw new InvalidParameterException("QoSIntraPingMeasurement" + NULL_ERROR_MESSAGE); + } else if (aroundNow == null) { + throw new InvalidParameterException("ZonedDateTime" + NULL_ERROR_MESSAGE); + } + + pingMeasurement.setMeasurement(measurement); + pingMeasurement.setAvailable(calculations.isAvailable()); + pingMeasurement.setMaxResponseTime(calculations.getMaxResponseTime()); + pingMeasurement.setMinResponseTime(calculations.getMinResponseTime()); + pingMeasurement.setMeanResponseTimeWithoutTimeout(calculations.getMeanResponseTimeWithoutTimeout()); + pingMeasurement.setMeanResponseTimeWithTimeout(calculations.getMeanResponseTimeWithTimeout()); + pingMeasurement.setJitterWithoutTimeout(calculations.getJitterWithoutTimeout()); + pingMeasurement.setJitterWithTimeout(calculations.getJitterWithTimeout()); + pingMeasurement.setLostPerMeasurementPercent(calculations.getLostPerMeasurementPercent()); + pingMeasurement.setCountStartedAt(pingMeasurement.getCountStartedAt()); + pingMeasurement.setLastAccessAt(calculations.isAvailable() ? aroundNow : pingMeasurement.getLastAccessAt()); + pingMeasurement.setSent(pingMeasurement.getSent() + calculations.getSentInThisPing()); + pingMeasurement.setSentAll(pingMeasurement.getSentAll() + calculations.getSentInThisPing()); + pingMeasurement.setReceived(pingMeasurement.getReceived() + calculations.getReceivedInThisPing()); + pingMeasurement.setReceivedAll(pingMeasurement.getReceivedAll() + calculations.getReceivedInThisPing()); + + try { + + qoSIntraMeasurementPingRepository.saveAndFlush(pingMeasurement); + + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + + } + + //------------------------------------------------------------------------------------------------- + @Transactional (rollbackFor = ArrowheadException.class) + public void updateMeasurement(final ZonedDateTime aroundNow, final QoSIntraMeasurement measurement) { + logger.debug("updateMeasurement started..."); + + if (measurement == null) { + throw new InvalidParameterException("QoSIntraMeasurement" + NULL_ERROR_MESSAGE); + } else if (aroundNow == null) { + throw new InvalidParameterException("ZonedDateTime" + NULL_ERROR_MESSAGE); + } + + measurement.setLastMeasurementAt(aroundNow); + try { + qoSIntraMeasurementRepository.saveAndFlush(measurement); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + public PingMeasurementListResponseDTO getPingMeasurementResponse(final int page, final int size, final Direction direction, final String sortField) { + logger.debug("getPingMeasurementResponse started..."); + + return DTOConverter.convertQoSIntraPingMeasurementPageToPingMeasurementListResponseDTO(getPingMeasurementPage(page, size, direction, sortField)); + } + + //------------------------------------------------------------------------------------------------- + public Page getPingMeasurementPage(final int page, final int size, final Direction direction, final String sortField) { + logger.debug("getPingMeasurementPage started..."); + + final int validatedPage = page < 0 ? 0 : page; + final int validatedSize = size < 1 ? Integer.MAX_VALUE : size; + final Direction validatedDirection = direction == null ? Direction.ASC : direction; + final String validatedSortField = Utilities.isEmpty(sortField) ? CommonConstants.COMMON_FIELD_NAME_ID : sortField.trim(); + + if (!QoSIntraPingMeasurement.SORTABLE_FIELDS_BY.contains(validatedSortField)) { + throw new InvalidParameterException(validatedSortField + NOT_AVAILABLE_SORTABLE_FIELD_ERROR_MESSAGE); + } + + try { + return qoSIntraMeasurementPingRepository.findAll(PageRequest.of(validatedPage, validatedSize, validatedDirection, validatedSortField)); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + public PingMeasurementResponseDTO getPingMeasurementBySystemIdResponse(final long id) { + logger.debug("getPingMeasurementBySystemIdResponse started ..."); + + final QoSIntraPingMeasurement pingMeausrement = getPingMeasurementBySystemId(id); + if (pingMeausrement == null ) { + + final PingMeasurementResponseDTO response = new PingMeasurementResponseDTO(); + response.setId( null ); + + return response; + } + + return DTOConverter.convertQoSIntraPingMeasurementToPingMeasurementResponseDTO(pingMeausrement); + } + + //------------------------------------------------------------------------------------------------- + public QoSIntraPingMeasurement getPingMeasurementBySystemId(final long id) { + logger.debug("getPingMeasurementBySystemId started ..."); + + if (id < 1) { + throw new InvalidParameterException("SystemId" + LESS_THAN_ONE_ERROR_MESSAGE); + } + + final System system; + final Optional systemOptional; + try { + + systemOptional = systemRepository.findById(id); + if (systemOptional.isPresent()) { + system = systemOptional.get(); + } else { + throw new InvalidParameterException("Requested system" + NOT_IN_DB_ERROR_MESSAGE); + } + + final QoSIntraMeasurement measurement; + final Optional qoSIntraMeasurementOptional = qoSIntraMeasurementRepository.findBySystemAndMeasurementType(system, QoSMeasurementType.PING); + if (qoSIntraMeasurementOptional.isEmpty()) { + + return null; + } else { + measurement = qoSIntraMeasurementOptional.get(); + } + + final Optional measurementOptional = qoSIntraMeasurementPingRepository.findByMeasurement(measurement); + if (measurementOptional.isEmpty()) { + + return null; + } else { + + return measurementOptional.get(); + } + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + private void validateSystemResponseDTO(final SystemResponseDTO systemResponseDTO) { + logger.debug("validateSystemRequestDTO started..."); + + if (systemResponseDTO == null) { + throw new InvalidParameterException("SystemRequestDTO" + NULL_ERROR_MESSAGE); + } + + if (Utilities.isEmpty(systemResponseDTO.getSystemName())) { + throw new InvalidParameterException("System name" + EMPTY_OR_NULL_ERROR_MESSAGE); + } + + if (Utilities.isEmpty(systemResponseDTO.getAddress())) { + throw new InvalidParameterException("System address" + EMPTY_OR_NULL_ERROR_MESSAGE); + } + } +} \ No newline at end of file diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/dto/PingMeasurementCalculationsDTO.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/dto/PingMeasurementCalculationsDTO.java new file mode 100644 index 000000000..fb8fe090a --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/dto/PingMeasurementCalculationsDTO.java @@ -0,0 +1,76 @@ +package eu.arrowhead.core.qos.dto; + +import java.io.Serializable; +import java.time.ZonedDateTime; + +public class PingMeasurementCalculationsDTO implements Serializable{ + + //================================================================================================= + // members + + private static final long serialVersionUID = -1645860899758857162L; + + private boolean available; + private Integer maxResponseTime; + private Integer minResponseTime; + private Integer meanResponseTimeWithTimeout; + private Integer meanResponseTimeWithoutTimeout; + private Integer jitterWithTimeout; + private Integer jitterWithoutTimeout; + private Integer sentInThisPing; + private Integer receivedInThisPing; + private Integer lostPerMeasurementPercent; + private ZonedDateTime measuredAt; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public PingMeasurementCalculationsDTO() {} + + //------------------------------------------------------------------------------------------------- + public PingMeasurementCalculationsDTO(final boolean available, final Integer maxResponseTime, final Integer minResponseTime, + final Integer meanResponseTimeWithTimeout, final Integer meanResponseTimeWithoutTimeout, final Integer jitterWithTimeout, + final Integer jitterWithoutTimeout, final Integer sentInThisPing, final Integer receivedInThisPing, final Integer lostPerMeasurementPercent, + final ZonedDateTime measuredAt) { + + this.available = available; + this.maxResponseTime = maxResponseTime; + this.minResponseTime = minResponseTime; + this.meanResponseTimeWithTimeout = meanResponseTimeWithTimeout; + this.meanResponseTimeWithoutTimeout = meanResponseTimeWithoutTimeout; + this.jitterWithTimeout = jitterWithTimeout; + this.jitterWithoutTimeout = jitterWithoutTimeout; + this.sentInThisPing = sentInThisPing; + this.receivedInThisPing = receivedInThisPing; + this.lostPerMeasurementPercent = lostPerMeasurementPercent; + this.measuredAt = measuredAt; + } + + //------------------------------------------------------------------------------------------------- + public boolean isAvailable() { return available; } + public Integer getMaxResponseTime() { return maxResponseTime; } + public Integer getMinResponseTime() { return minResponseTime; } + public Integer getMeanResponseTimeWithTimeout() { return meanResponseTimeWithTimeout; } + public Integer getMeanResponseTimeWithoutTimeout() { return meanResponseTimeWithoutTimeout; } + public Integer getJitterWithTimeout() { return jitterWithTimeout; } + public Integer getJitterWithoutTimeout() { return jitterWithoutTimeout; } + public Integer getSentInThisPing() { return sentInThisPing; } + public Integer getReceivedInThisPing() { return receivedInThisPing; } + public Integer getLostPerMeasurementPercent() { return lostPerMeasurementPercent; } + public ZonedDateTime getMeasuredAt() { return measuredAt; } + + //------------------------------------------------------------------------------------------------- + public void setAvailable(final boolean available) { this.available = available; } + public void setMaxResponseTime(final Integer maxResponseTime) { this.maxResponseTime = maxResponseTime; } + public void setMinResponseTime(final Integer minResponseTime) { this.minResponseTime = minResponseTime; } + public void setMeanResponseTimeWithTimeout(final Integer meanResponseTimeWithTimeout) { this.meanResponseTimeWithTimeout = meanResponseTimeWithTimeout; } + public void setMeanResponseTimeWithoutTimeout(final Integer meanResponseTimeWithoutTimeout) { this.meanResponseTimeWithoutTimeout = meanResponseTimeWithoutTimeout; } + public void setJitterWithTimeout(final Integer jitterWithTimeout) { this.jitterWithTimeout = jitterWithTimeout; } + public void setJitterWithoutTimeout(final Integer jitterWithoutTimeout) { this.jitterWithoutTimeout = jitterWithoutTimeout; } + public void setSentInThisPing(final Integer sentInThisPing) { this.sentInThisPing = sentInThisPing; } + public void setReceivedInThisPing(final Integer receivedInThisPing) { this.receivedInThisPing = receivedInThisPing; } + public void setLostPerMeasurementPercent(final Integer lostPerMeasurementPercent) { this.lostPerMeasurementPercent = lostPerMeasurementPercent; } + public void setMeasuredAt(final ZonedDateTime measuredAt) { this.measuredAt = measuredAt; } + +} \ No newline at end of file diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/measurement/properties/PingMeasurementProperties.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/measurement/properties/PingMeasurementProperties.java new file mode 100644 index 000000000..09e3a28c6 --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/measurement/properties/PingMeasurementProperties.java @@ -0,0 +1,72 @@ +package eu.arrowhead.core.qos.measurement.properties; + +import javax.annotation.PostConstruct; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; +import org.springframework.util.Assert; + +@Configuration +@ConfigurationProperties(prefix = "ping") +public class PingMeasurementProperties { + + //================================================================================================= + // members + + private int timeToRepeat; + private int timeout; + private int packetSize; + private int rest; + private int availableFromSuccessPercent; + private boolean logMeasurementsToDB; + private boolean logMeasurementsDetailsToDB; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public PingMeasurementProperties() {} + + //------------------------------------------------------------------------------------------------- + public PingMeasurementProperties(final int timeToRepeat, final int timeout, final int pocketSize, + final int rest, final int availableFromSuccessPercent, final boolean logMeasurementsToDB, + final boolean logMeasurementsDetailsToDB) { + + this.timeToRepeat = timeToRepeat; + this.timeout = timeout; + this.packetSize = pocketSize; + this.rest = rest; + this.availableFromSuccessPercent = availableFromSuccessPercent; + this.logMeasurementsToDB = logMeasurementsToDB; + this.logMeasurementsDetailsToDB = logMeasurementsDetailsToDB; + } + + //------------------------------------------------------------------------------------------------- + public int getTimeToRepeat() { return timeToRepeat; } + public int getTimeout() { return timeout; } + public int getPacketSize() { return packetSize; } + public int getRest() { return rest; } + public int getAvailableFromSuccessPercent() { return availableFromSuccessPercent; } + public boolean getLogMeasurementsToDB() { return logMeasurementsToDB; } + public boolean getLogMeasurementsDetailsToDB() {return logMeasurementsDetailsToDB; } + + //------------------------------------------------------------------------------------------------- + public void setTimeToRepeat(final int timeToRepeat) { this.timeToRepeat = timeToRepeat; } + public void setTimeout(final int timeout) { this.timeout = timeout; } + public void setPacketSize(final int packetSize) { this.packetSize = packetSize; } + public void setRest(final int rest) { this.rest = rest; } + public void setAvailableFromSuccessPercent(final int availableFromSuccessPercent) { this.availableFromSuccessPercent = availableFromSuccessPercent; } + public void setLogMeasurementsToDB(final boolean logMeasurementsToDB) { this.logMeasurementsToDB = logMeasurementsToDB; } + public void setLogMeasurementsDetailsToDB(final boolean logMeasurementsDetailsToDB) { this.logMeasurementsDetailsToDB = logMeasurementsDetailsToDB; } + + //------------------------------------------------------------------------------------------------- + @PostConstruct + private void validateFields() { + + Assert.isTrue(timeToRepeat > 0 && timeToRepeat <= 100, "Time to repeat must be greater than 0 and not greater than 100"); + Assert.isTrue(timeout >= 0 && timeout < 10000, "timeout must be greater than or equal 0 and not greater than 10 000"); + Assert.isTrue((packetSize == 32 || packetSize == 56 || packetSize == 64), "packetSize has to be 32 or 56 or 64"); + Assert.isTrue(rest >= 0 && rest <= 10000, "rest must be greater than 0 and not greater than 10 000"); + Assert.isTrue(availableFromSuccessPercent > 0 && availableFromSuccessPercent <= 100, "availableFromSuccessPercent must be greater than 0 and not greater than 100"); + } +} \ No newline at end of file diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/quartz/task/CountRestarterTask.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/quartz/task/CountRestarterTask.java new file mode 100644 index 000000000..f0c37379c --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/quartz/task/CountRestarterTask.java @@ -0,0 +1,58 @@ +package eu.arrowhead.core.qos.quartz.task; + +import java.util.Map; + +import javax.annotation.Resource; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.core.qos.database.service.QoSDBService; + +@Component +@DisallowConcurrentExecution +public class CountRestarterTask implements Job { + + //================================================================================================= + // members + + protected Logger logger = LogManager.getLogger(CountRestarterTask.class); + + @Autowired + private QoSDBService qoSDBService; + + @Resource(name = CommonConstants.ARROWHEAD_CONTEXT) + private Map arrowheadContext; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Override + public void execute(final JobExecutionContext context) throws JobExecutionException { + logger.debug("STARTED: count restarter task"); + + if (arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)) { + + return; + } + + qoSDBService.updateCountStartedAt(); + + logger.debug("Finished: count restarter task"); + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + +} \ No newline at end of file diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/quartz/task/CountRestarterTaskConfig.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/quartz/task/CountRestarterTaskConfig.java new file mode 100644 index 000000000..c650c1fdd --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/quartz/task/CountRestarterTaskConfig.java @@ -0,0 +1,74 @@ +package eu.arrowhead.core.qos.quartz.task; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.quartz.CronTriggerFactoryBean; +import org.springframework.scheduling.quartz.JobDetailFactoryBean; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; + +import eu.arrowhead.common.quartz.AutoWiringSpringBeanQuartzTaskFactory; + +@Configuration +public class CountRestarterTaskConfig { + + //================================================================================================= + // members + + protected Logger logger = LogManager.getLogger(CountRestarterTaskConfig.class); + + @Autowired + private ApplicationContext applicationContext; //NOSONAR + + private static final int SCHEDULER_DELAY = 7; + private static final String CRON_EXPRESSION_MIDNIGHT_EVERY_DAY= "0 0 0 ? * * *"; + private static final String NAME_OF_TRIGGER = "Counter_Restart_Task_Trigger"; + private static final String NAME_OF_TASK = "Counter_Restart_Task_Detail"; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Bean + public SchedulerFactoryBean counterRestarterTaskSheduler() { + final AutoWiringSpringBeanQuartzTaskFactory jobFactory = new AutoWiringSpringBeanQuartzTaskFactory(); + jobFactory.setApplicationContext(applicationContext); + + final SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean(); + + schedulerFactory.setJobFactory(jobFactory); + schedulerFactory.setJobDetails(counterRestartTaskDetails().getObject()); + schedulerFactory.setTriggers(counterRestartTaskTrigger().getObject()); + schedulerFactory.setStartupDelay(SCHEDULER_DELAY); + + logger.info("CountRestarterTask task adjusted."); + + return schedulerFactory; + } + + //------------------------------------------------------------------------------------------------- + @Bean + public CronTriggerFactoryBean counterRestartTaskTrigger() { + + CronTriggerFactoryBean trigger = new CronTriggerFactoryBean(); + trigger.setJobDetail(counterRestartTaskDetails().getObject()); + trigger.setCronExpression(CRON_EXPRESSION_MIDNIGHT_EVERY_DAY); + trigger.setName(NAME_OF_TRIGGER); + + return trigger; + } + + //------------------------------------------------------------------------------------------------- + @Bean + public JobDetailFactoryBean counterRestartTaskDetails() { + final JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean(); + jobDetailFactory.setJobClass(CountRestarterTask.class); + jobDetailFactory.setName(NAME_OF_TASK); + jobDetailFactory.setDurability(true); + + return jobDetailFactory; + } +} \ No newline at end of file diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/quartz/task/PingTask.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/quartz/task/PingTask.java new file mode 100644 index 000000000..6712d2cff --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/quartz/task/PingTask.java @@ -0,0 +1,350 @@ +package eu.arrowhead.core.qos.quartz.task; + +import java.time.ZonedDateTime; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.stream.Collectors; + +import javax.annotation.Resource; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.icmp4j.IcmpPingResponse; +import org.quartz.DisallowConcurrentExecution; +import org.quartz.Job; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpMethod; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.util.Assert; +import org.springframework.web.util.UriComponents; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.database.entity.QoSIntraMeasurement; +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurement; +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurementLog; +import eu.arrowhead.common.dto.internal.ServiceRegistryListResponseDTO; +import eu.arrowhead.common.dto.shared.ServiceRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.common.exception.InvalidParameterException; +import eu.arrowhead.common.http.HttpService; +import eu.arrowhead.core.qos.database.service.QoSDBService; +import eu.arrowhead.core.qos.dto.PingMeasurementCalculationsDTO; +import eu.arrowhead.core.qos.measurement.properties.PingMeasurementProperties; +import eu.arrowhead.core.qos.service.PingService; + +@Component +@DisallowConcurrentExecution +public class PingTask implements Job { + + //================================================================================================= + // members + private static final String NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE = " is null or blank."; + + private static final int INVALID_CALCULATION_VALUE = -1; + + protected Logger logger = LogManager.getLogger(PingTask.class); + + @Autowired + private PingMeasurementProperties pingMeasurementProperties; + + @Autowired + private PingService pingService; + + @Autowired + private QoSDBService qoSDBService; + + @Autowired + private HttpService httpService; + + @Resource(name = CommonConstants.ARROWHEAD_CONTEXT) + private Map arrowheadContext; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Override + public void execute(final JobExecutionContext context) throws JobExecutionException { + logger.debug("STARTED: ping task"); + + if (arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)) { + + logger.debug("Finished: ping task can not run if server is in standalon mode"); + return; + } + + final List systems = getSystemsToMeasure(); + if (systems == null || systems.isEmpty()) { + + return; + } + + final HashMap pingCache = new HashMap<>(systems.size()); + for (final SystemResponseDTO systemResponseDTO : systems) { + + final String address = systemResponseDTO.getAddress(); + if (pingCache.containsKey(address)) { + + copyCalculationsToPingMeasurement(systemResponseDTO, pingCache.get(address)); + + }else { + + final PingMeasurementCalculationsDTO calculations = pingSystem(systemResponseDTO); + pingCache.put(address, calculations); + + } + + } + + logger.debug("Finished: ping task success"); + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + private List getSystemsToMeasure() { + logger.debug("getSystemToMeasure started..."); + + final ServiceRegistryListResponseDTO serviceRegistryListResponseDTO = queryServiceRegistryAll(); + if(serviceRegistryListResponseDTO == null || serviceRegistryListResponseDTO.getData() == null || serviceRegistryListResponseDTO.getData().isEmpty()) { + + return null; + } + final List systemList = serviceRegistryListResponseDTO.getData().stream().map(ServiceRegistryResponseDTO::getProvider).collect(Collectors.toList()); + + return systemList; + } + + //------------------------------------------------------------------------------------------------- + private PingMeasurementCalculationsDTO calculatePingMeasurementValues(final List responseList, final ZonedDateTime aroundNow) { + logger.debug("calculatePingMeasurementValues started..."); + + final int sentInThisPing = responseList.size(); + Assert.isTrue(sentInThisPing > 0, "Sent in this Ping value must be greater than zero"); + + final int timeout = pingMeasurementProperties.getTimeout() + 1; + + int receivedInThisPing = 0; + long maxResponseTime = 0; + long minResponseTime = Integer.MAX_VALUE; + double sumOfDurationForMeanResponseTimeWithTimeout = 0; + double sumOfDurationForMeanResponseTimeWithoutTimeout = 0; + int meanResponseTimeWithoutTimeoutMembersCount = 0; + + for (final IcmpPingResponse icmpPingResponse : responseList) { + + final boolean successFlag = icmpPingResponse.getSuccessFlag(); + + if (successFlag) { + ++receivedInThisPing; + final long duration = icmpPingResponse.getDuration(); + + if (duration > maxResponseTime) { + maxResponseTime = duration; + } + + if (duration < minResponseTime) { + minResponseTime = duration; + } + + sumOfDurationForMeanResponseTimeWithoutTimeout += duration; + sumOfDurationForMeanResponseTimeWithTimeout += duration; + ++meanResponseTimeWithoutTimeoutMembersCount; + + } else { + sumOfDurationForMeanResponseTimeWithTimeout += timeout; + } + } + + final boolean available = calculateAvailable(sentInThisPing, receivedInThisPing); + final int lostPerMeasurementPercent = (int) (receivedInThisPing == 0 ? 100 : 100 - ((double)receivedInThisPing / sentInThisPing) * 100); + + final double meanResponseTimeWithTimeout = responseList.size() < 1 ? INVALID_CALCULATION_VALUE : sumOfDurationForMeanResponseTimeWithTimeout / responseList.size(); + final double meanResponseTimeWithoutTimeout = meanResponseTimeWithoutTimeoutMembersCount < 1 ? INVALID_CALCULATION_VALUE : sumOfDurationForMeanResponseTimeWithoutTimeout / meanResponseTimeWithoutTimeoutMembersCount; + + double sumOfDiffsForJitterWithTimeout = 0; + double sumOfDiffsForJitterWithoutTimeout = 0; + for (final IcmpPingResponse icmpPingResponse : responseList) { + + final boolean successFlag = icmpPingResponse.getSuccessFlag(); + final double duration; + if (successFlag) { + duration = icmpPingResponse.getDuration(); + sumOfDiffsForJitterWithoutTimeout += Math.pow( (duration - meanResponseTimeWithoutTimeout), 2); + } else { + duration = timeout; + } + + sumOfDiffsForJitterWithTimeout += Math.pow( (duration - meanResponseTimeWithTimeout), 2); + } + final double jitterWithTimeout = meanResponseTimeWithoutTimeoutMembersCount < 1 ? INVALID_CALCULATION_VALUE : Math.sqrt(sumOfDiffsForJitterWithTimeout / meanResponseTimeWithoutTimeoutMembersCount); + final double jitterWithoutTimeout = responseList.size() < 1 ? INVALID_CALCULATION_VALUE : Math.sqrt(sumOfDiffsForJitterWithoutTimeout / responseList.size()); + + final PingMeasurementCalculationsDTO calculations = new PingMeasurementCalculationsDTO(); + calculations.setAvailable(available); + calculations.setMinResponseTime(available ? (int) minResponseTime : null); + calculations.setMaxResponseTime(available ? (int) maxResponseTime : null); + calculations.setMeanResponseTimeWithTimeout(available ? (int) Math.round(meanResponseTimeWithTimeout) : null); + calculations.setMeanResponseTimeWithoutTimeout(available ? (int) Math.round(meanResponseTimeWithoutTimeout) : null); + calculations.setJitterWithTimeout(available ? (int) Math.round(jitterWithTimeout) : null); + calculations.setJitterWithoutTimeout(available ? (int) Math.round(jitterWithoutTimeout) : null); + calculations.setSentInThisPing(sentInThisPing); + calculations.setReceivedInThisPing(receivedInThisPing); + calculations.setLostPerMeasurementPercent(lostPerMeasurementPercent); + calculations.setMeasuredAt(aroundNow); + + return calculations; + } + + //------------------------------------------------------------------------------------------------- + private PingMeasurementCalculationsDTO pingSystem(final SystemResponseDTO systemResponseDTO ) { + logger.debug("pingSystem started..."); + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + + if (systemResponseDTO == null || Utilities.isEmpty(systemResponseDTO.getAddress())) { + throw new InvalidParameterException("System.address" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE); + } + + final String address = systemResponseDTO.getAddress(); + + final List responseList = pingService.getPingResponseList(address); + + final QoSIntraMeasurement measurement = qoSDBService.getOrCreateMeasurement(systemResponseDTO); + final PingMeasurementCalculationsDTO calculationsDTO = handlePingMeasurement(measurement, responseList, aroundNow); + + qoSDBService.updateMeasurement(aroundNow, measurement); + + return calculationsDTO; + + } + + //------------------------------------------------------------------------------------------------- + private void copyCalculationsToPingMeasurement(final SystemResponseDTO systemResponseDTO, final PingMeasurementCalculationsDTO calculationsDTO) { + logger.debug("copyCalculationsToPingMeasurement started..."); + + final ZonedDateTime aroundNow = calculationsDTO.getMeasuredAt(); + + if (systemResponseDTO == null || Utilities.isEmpty(systemResponseDTO.getAddress())) { + throw new InvalidParameterException("System.address" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE); + } + + final QoSIntraMeasurement measurement = qoSDBService.getOrCreateMeasurement(systemResponseDTO); + handlePingMeasurement(measurement, aroundNow, calculationsDTO); + + qoSDBService.updateMeasurement(aroundNow, measurement); + + } + + //------------------------------------------------------------------------------------------------- + private PingMeasurementCalculationsDTO handlePingMeasurement(final QoSIntraMeasurement measurement, + final List responseList, final ZonedDateTime aroundNow) { + logger.debug("handelPingMeasurement started..."); + + final PingMeasurementCalculationsDTO calculationsDTO = calculatePingMeasurementValues(responseList, aroundNow); + final Optional pingMeasurementOptional = qoSDBService.getPingMeasurementByMeasurement(measurement); + + if (pingMeasurementOptional.isEmpty()) { + + qoSDBService.createPingMeasurement(measurement, calculationsDTO, aroundNow); + + if (pingMeasurementProperties.getLogMeasurementsToDB()) { + + final QoSIntraPingMeasurementLog measurementLogSaved = qoSDBService.logMeasurementToDB(measurement.getSystem().getAddress(), calculationsDTO, aroundNow); + + if (pingMeasurementProperties.getLogMeasurementsDetailsToDB() && measurementLogSaved != null) { + + qoSDBService.logMeasurementDetailsToDB(measurementLogSaved, responseList, aroundNow); + } + } + + } else { + + qoSDBService.updatePingMeasurement(measurement, calculationsDTO, pingMeasurementOptional.get(), aroundNow); + + if(pingMeasurementProperties.getLogMeasurementsToDB()) { + + final QoSIntraPingMeasurementLog measurementLogSaved = qoSDBService.logMeasurementToDB(measurement.getSystem().getAddress(), calculationsDTO, aroundNow); + + if(pingMeasurementProperties.getLogMeasurementsDetailsToDB() && measurementLogSaved != null) { + + qoSDBService.logMeasurementDetailsToDB(measurementLogSaved, responseList, aroundNow); + } + } + } + + return calculationsDTO; + } + + //------------------------------------------------------------------------------------------------- + private void handlePingMeasurement(final QoSIntraMeasurement measurement, final ZonedDateTime aroundNow, final PingMeasurementCalculationsDTO calculationsDTO) { + logger.debug("handelPingMeasurement started..."); + + final Optional pingMeasurementOptional = qoSDBService.getPingMeasurementByMeasurement(measurement); + + if (pingMeasurementOptional.isEmpty()) { + + qoSDBService.createPingMeasurement(measurement, calculationsDTO, aroundNow); + + } else { + + qoSDBService.updatePingMeasurement(measurement, calculationsDTO, pingMeasurementOptional.get(), aroundNow); + + } + + } + + //------------------------------------------------------------------------------------------------- + private ServiceRegistryListResponseDTO queryServiceRegistryAll() { + logger.debug("queryServiceRegistryAll started..."); + + try { + final UriComponents queryBySystemDTOUri = getQueryAllUri(); + final ResponseEntity response = httpService.sendRequest(queryBySystemDTOUri, HttpMethod.GET, ServiceRegistryListResponseDTO.class); + + return response.getBody(); + + } catch (final ArrowheadException ex) { + + logger.debug("Exception: " + ex.getMessage()); + throw ex; + + } + + } + + //------------------------------------------------------------------------------------------------- + private UriComponents getQueryAllUri() { + logger.debug("getQueryUri started..."); + + if (arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)) { + try { + return (UriComponents) arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL); + } catch (final ClassCastException ex) { + throw new ArrowheadException("QoS Mointor can't find Service Registry Query All URI."); + } + } else { + throw new ArrowheadException("QoS Mointor can't find Service Registry Query All URI."); + } + } + + //------------------------------------------------------------------------------------------------- + private boolean calculateAvailable(final int sentInThisPing, final int availableCount) { + logger.debug("calculateAvailable started..."); + + final int availableFromSuccessPercent = pingMeasurementProperties.getAvailableFromSuccessPercent(); + final double availablePercent = 100 - ((sentInThisPing - availableCount) / (double)sentInThisPing) * 100 ; + + return availableFromSuccessPercent <= Math.round(availablePercent); + } + +} diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/quartz/task/PingTaskConfig.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/quartz/task/PingTaskConfig.java new file mode 100644 index 000000000..19d8f598f --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/quartz/task/PingTaskConfig.java @@ -0,0 +1,80 @@ +package eu.arrowhead.core.qos.quartz.task; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.quartz.SimpleTrigger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.ApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.scheduling.quartz.JobDetailFactoryBean; +import org.springframework.scheduling.quartz.SchedulerFactoryBean; +import org.springframework.scheduling.quartz.SimpleTriggerFactoryBean; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.quartz.AutoWiringSpringBeanQuartzTaskFactory; + +@Configuration +public class PingTaskConfig { + + //================================================================================================= + // members + + protected Logger logger = LogManager.getLogger(PingTaskConfig.class); + + @Autowired + private ApplicationContext applicationContext; //NOSONAR + + @Value(CoreCommonConstants.$PING_TTL_INTERVAL_WD) + private int ttlInterval; + + private static final int SCHEDULER_DELAY = 1; + + private static final String NAME_OF_TRIGGER = "Intra_Cloud_Ping_Task_Trigger"; + private static final String NAME_OF_TASK = "Intra_Cloud_Ping_Task_Detail"; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Bean + public SchedulerFactoryBean pingSheduler() { + final AutoWiringSpringBeanQuartzTaskFactory jobFactory = new AutoWiringSpringBeanQuartzTaskFactory(); + jobFactory.setApplicationContext(applicationContext); + + final SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean(); + + schedulerFactory.setJobFactory(jobFactory); + schedulerFactory.setJobDetails(intraCloudPingTaskDetails().getObject()); + schedulerFactory.setTriggers(intraCloudPingTaskTrigger().getObject()); + schedulerFactory.setStartupDelay(SCHEDULER_DELAY); + logger.info("Ping task adjusted with ttl interval: {} minutes", ttlInterval); + + return schedulerFactory; + } + + //------------------------------------------------------------------------------------------------- + @Bean + public SimpleTriggerFactoryBean intraCloudPingTaskTrigger() { + final SimpleTriggerFactoryBean trigger = new SimpleTriggerFactoryBean(); + trigger.setJobDetail(intraCloudPingTaskDetails().getObject()); + trigger.setRepeatInterval(ttlInterval * CommonConstants.CONVERSION_MILLISECOND_TO_MINUTE); + trigger.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY); + trigger.setName(NAME_OF_TRIGGER); + + return trigger; + } + + //------------------------------------------------------------------------------------------------- + @Bean + public JobDetailFactoryBean intraCloudPingTaskDetails() { + final JobDetailFactoryBean jobDetailFactory = new JobDetailFactoryBean(); + jobDetailFactory.setJobClass(PingTask.class); + jobDetailFactory.setName(NAME_OF_TASK); + jobDetailFactory.setDurability(true); + + return jobDetailFactory; + } +} \ No newline at end of file diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/security/QoSMonitorSecurityConfig.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/security/QoSMonitorSecurityConfig.java new file mode 100644 index 000000000..783b13167 --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/security/QoSMonitorSecurityConfig.java @@ -0,0 +1,12 @@ +package eu.arrowhead.core.qos.security; + +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + +import eu.arrowhead.common.security.DefaultSecurityConfig; + +@Configuration +@EnableWebSecurity +public class QoSMonitorSecurityConfig extends DefaultSecurityConfig { + +} \ No newline at end of file diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/security/QosMonitorAccessControlFilter.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/security/QosMonitorAccessControlFilter.java new file mode 100644 index 000000000..2aef9c5d3 --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/security/QosMonitorAccessControlFilter.java @@ -0,0 +1,42 @@ +package eu.arrowhead.core.qos.security; + +import java.util.Map; + +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.core.CoreSystem; +import eu.arrowhead.common.security.CoreSystemAccessControlFilter; + +@Component +@ConditionalOnProperty(name = CommonConstants.SERVER_SSL_ENABLED, matchIfMissing = true) +public class QosMonitorAccessControlFilter extends CoreSystemAccessControlFilter { + + //================================================================================================= + // members + private static final CoreSystem[] allowedCoreSystemsForGetMeasurements = { CoreSystem.ORCHESTRATOR }; + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + @Override + protected void checkClientAuthorized(final String clientCN, final String method, final String requestTarget, final String requestJSON, final Map queryParams) { + super.checkClientAuthorized(clientCN, method, requestTarget, requestJSON, queryParams); + + final String cloudCN = getServerCloudCN(); + + if (requestTarget.endsWith(CommonConstants.ECHO_URI)) { + // Everybody in the local cloud can test the server => no further check is necessary + } else if ( requestTarget.contains( CoreCommonConstants.MGMT_URI ) ) { + // Only the local System Operator can use these methods + checkIfLocalSystemOperator(clientCN, cloudCN, requestTarget); + } else if (requestTarget.contains(CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT)) { + // Only the specified core systems can use these methods + checkIfClientIsAnAllowedCoreSystem(clientCN, cloudCN, allowedCoreSystemsForGetMeasurements, requestTarget); + } + } + +} \ No newline at end of file diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/service/PingService.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/service/PingService.java new file mode 100644 index 000000000..d8e746465 --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/service/PingService.java @@ -0,0 +1,74 @@ +package eu.arrowhead.core.qos.service; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.icmp4j.IcmpPingRequest; +import org.icmp4j.IcmpPingResponse; +import org.icmp4j.IcmpPingUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.exception.InvalidParameterException; +import eu.arrowhead.core.qos.measurement.properties.PingMeasurementProperties; + +@Service +public class PingService { + + //================================================================================================= + // members + + private static final String EMPTY_OR_NULL_ERROR_MESSAGE = " is empty or null"; + + @Autowired + private PingMeasurementProperties pingMeasurementProperties; + + protected Logger logger = LogManager.getLogger(PingMeasurementProperties.class); + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public List getPingResponseList(final String address) { + logger.debug("getPingResponseList started..."); + + if (Utilities.isEmpty(address)) { + throw new InvalidParameterException("Address" + EMPTY_OR_NULL_ERROR_MESSAGE); + } + + final List responseList = new ArrayList<>(pingMeasurementProperties.getTimeToRepeat()); + try { + final IcmpPingRequest request = IcmpPingUtil.createIcmpPingRequest(); + request.setHost(address); + request.setTimeout(pingMeasurementProperties.getTimeout()); + request.setPacketSize(pingMeasurementProperties.getPacketSize()); + + for (int count = 0; count < pingMeasurementProperties.getTimeToRepeat(); count ++) { + IcmpPingResponse response; + try { + response = IcmpPingUtil.executePingRequest (request); + final String formattedResponse = IcmpPingUtil.formatResponse(response); + logger.debug(formattedResponse); + + responseList.add(response); + } catch (final Exception ex) { + response = new IcmpPingResponse(); + response.setErrorMessage(ex.getMessage()); + response.setSuccessFlag(false); + response.setThrowable(ex); + + responseList.add(response); + } + + Thread.sleep(pingMeasurementProperties.getRest()); + } + } catch (final InterruptedException | IllegalArgumentException ex) { + logger.debug("" + ex.getMessage()); + } + + return responseList; + } +} \ No newline at end of file diff --git a/qos-monitor/src/main/java/eu/arrowhead/core/qos/swagger/QoSMonitorSwaggerConfig.java b/qos-monitor/src/main/java/eu/arrowhead/core/qos/swagger/QoSMonitorSwaggerConfig.java new file mode 100644 index 000000000..fff5fc603 --- /dev/null +++ b/qos-monitor/src/main/java/eu/arrowhead/core/qos/swagger/QoSMonitorSwaggerConfig.java @@ -0,0 +1,28 @@ +package eu.arrowhead.core.qos.swagger; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.swagger.DefaultSwaggerConfig; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@EnableSwagger2 +@Configuration +public class QoSMonitorSwaggerConfig extends DefaultSwaggerConfig { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public QoSMonitorSwaggerConfig() { + super(CommonConstants.CORE_SYSTEM_QOS_MONITOR); + } + + //------------------------------------------------------------------------------------------------- + @Bean + public Docket customizeSwagger() { + return configureSwaggerForCoreSystem(this.getClass().getPackageName()); + } +} \ No newline at end of file diff --git a/qos-monitor/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/qos-monitor/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..2ff6b2339 --- /dev/null +++ b/qos-monitor/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,77 @@ +{"properties": [ + { + "name": "core_system_name", + "type": "java.lang.String", + "description": "A description for 'core_system_name'" + }, + { + "name": "sr_address", + "type": "java.lang.String", + "description": "A description for 'sr_address'" + }, + { + "name": "sr_port", + "type": "java.lang.Integer", + "description": "A description for 'sr_port'" + }, + { + "name": "disable.hostname.verifier", + "type": "java.lang.Boolean", + "description": "A description for 'disable.hostname.verifier'" + }, + { + "name": "domain.name", + "type": "java.lang.String", + "description": "A description for 'domain.name'" + }, + { + "name": "domain.port", + "type": "java.lang.Integer", + "description": "A description for 'domain.port'" + }, + { + "name": "log_all_request_and_response", + "type": "java.lang.Boolean", + "description": "A description for 'log_all_request_and_response'" + }, + { + "name": "gatekeeper_is_present", + "type": "java.lang.Boolean", + "description": "A description for 'gatekeeper_is_present'" + }, + { + "name": "ping.packet_size", + "type": "java.lang.Integer", + "description": "A description for 'ping.pocket_size'" + }, + { + "name": "ping.time_to_repeat", + "type": "java.lang.Integer", + "description": "A description for 'ping.time_to_repeat'" + }, + { + "name": "cloud_ping_ttl_interval_minutes", + "type": "java.lang.String", + "description": "A description for 'cloud_ping_ttl_interval_minutes'" + }, + { + "name": "ping_ttl_interval_minutes", + "type": "java.lang.String", + "description": "A description for 'ping_ttl_interval_minutes'" + }, + { + "name": "ping.available_from_success_percent", + "type": "java.lang.Integer", + "description": "A description for 'ping.available_from_success_percent'" + }, + { + "name": "ping.logMeasurementsToDB", + "type": "java.lang.Boolean", + "description": "A description for 'ping.logMeasurementsToDB'" + }, + { + "name": "ping.logMeasurementsDetailsToDB", + "type": "java.lang.Boolean", + "description": "A description for 'ping.logMeasurementsDetailsToDB'" + } +]} \ No newline at end of file diff --git a/qos-monitor/src/main/resources/application.properties b/qos-monitor/src/main/resources/application.properties new file mode 100644 index 000000000..75a0539ca --- /dev/null +++ b/qos-monitor/src/main/resources/application.properties @@ -0,0 +1,97 @@ +############################################ +### APPLICATION PARAMETERS ### +############################################ + +# Database connection (mandatory) +# Change the server timezone if neccessary +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/arrowhead?serverTimezone=Europe/Budapest +spring.datasource.username=qos_monitor +spring.datasource.password=RLY3UEx6nx4kSXy +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +# use true only for debugging +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.hibernate.ddl-auto=none + +# QoS Monitor web-server parameters +server.address=0.0.0.0 +server.port=8451 +domain.name=127.0.0.1 +domain.port=8451 + +############################################ +### CUSTOM PARAMETERS ### +############################################ + +# Name of the core system +core_system_name=QOS_MONITOR + +# Show all request/response in debug log +log_all_request_and_response=false + +# Service Registry web-server parameters (to register the QoS Monitor services) +sr_address=127.0.0.1 +sr_port=8443 + +# Gatekeeper core system is present +gatekeeper_is_present=true + +# Monitor timings +cloud_ping_ttl_interval_minutes=2 + +ping_ttl_interval_minutes=2 + +############################################ +### PING MEASUREMENT PARAMETERS ### +############################################ + +# Set times to repeat the ping per measurement +# must be greater than 0 and not greater than 100 +ping.time_to_repeat=35 + +# Set timeout of ping +# must be greater than or equal 0 and not greater than 10 000 +ping.timeout=5000 + +# Set packet size of ping +# must be 32 or 56 or 64 +ping.packet_size=32 + +# Set millsec to sleep between single pings in a measurement +# must be greater than 999 and not greater than 10 000 +ping.rest=1000 + +# Set succes percentage of individual pings to accept measurement as available +# must be greater than 0 and not greater than 100 +ping.available_from_success_percent=1 + +# Set to persist individual measurement to DB +ping.logMeasurementsToDB=true + +# Set to persist individual measurement details to DB +ping.logMeasurementsDetailsToDB=false + +############################################ +### SECURE MODE ### +############################################ + +# configure secure mode + +# Set this to false to disable https mode +server.ssl.enabled=true + +server.ssl.key-store-type=PKCS12 +server.ssl.key-store=classpath:certificates/qos_monitor.p12 +server.ssl.key-store-password=123456 +server.ssl.key-alias=qos_monitor +server.ssl.key-password=123456 +server.ssl.client-auth=need +server.ssl.trust-store-type=PKCS12 +server.ssl.trust-store=classpath:certificates/truststore.p12 +server.ssl.trust-store-password=123456 + +#If true, http client does not check whether the hostname is match one of the server's SAN in its certificate +#Just for testing, DO NOT USE this feature in production environment +disable.hostname.verifier=false diff --git a/qos-monitor/src/main/resources/certificates/qos_monitor.p12 b/qos-monitor/src/main/resources/certificates/qos_monitor.p12 new file mode 100644 index 000000000..86c68f35b Binary files /dev/null and b/qos-monitor/src/main/resources/certificates/qos_monitor.p12 differ diff --git a/qos-monitor/src/main/resources/certificates/truststore.p12 b/qos-monitor/src/main/resources/certificates/truststore.p12 new file mode 100644 index 000000000..57c1c5f43 Binary files /dev/null and b/qos-monitor/src/main/resources/certificates/truststore.p12 differ diff --git a/qos-monitor/src/main/resources/log4j2.xml b/qos-monitor/src/main/resources/log4j2.xml new file mode 100644 index 000000000..8025b4d46 --- /dev/null +++ b/qos-monitor/src/main/resources/log4j2.xml @@ -0,0 +1,46 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex + + INFO + INFO + . + + + + + + + + ${LOG_PATTERN} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/qos-monitor/src/main/resources/swagger/swagger-ui.html b/qos-monitor/src/main/resources/swagger/swagger-ui.html new file mode 100644 index 000000000..5f1488c02 --- /dev/null +++ b/qos-monitor/src/main/resources/swagger/swagger-ui.html @@ -0,0 +1,75 @@ + + + + + + QoS Monitor + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/qos-monitor/src/test/java/.placeholder b/qos-monitor/src/test/java/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/qos-monitor/src/test/java/eu/arrowhead/core/qos/QoSMonitorControllerTest.java b/qos-monitor/src/test/java/eu/arrowhead/core/qos/QoSMonitorControllerTest.java new file mode 100644 index 000000000..f68ba2513 --- /dev/null +++ b/qos-monitor/src/test/java/eu/arrowhead/core/qos/QoSMonitorControllerTest.java @@ -0,0 +1,383 @@ +package eu.arrowhead.core.qos; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.dto.internal.PingMeasurementListResponseDTO; +import eu.arrowhead.common.dto.internal.PingMeasurementResponseDTO; +import eu.arrowhead.common.dto.internal.QoSIntraMeasurementResponseDTO; +import eu.arrowhead.common.dto.shared.ErrorMessageDTO; +import eu.arrowhead.common.dto.shared.QoSMeasurementType; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.common.exception.ExceptionType; +import eu.arrowhead.core.qos.database.service.QoSDBService; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = QoSMonitorMain.class) +@ContextConfiguration(classes = { QoSMonitorTestContext.class }) +public class QoSMonitorControllerTest { + + //================================================================================================= + // members + + private static final String PATH_VARIABLE_ID = "id"; + private static final String PING_MEASUREMENTS = "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/ping/measurements"; + private static final String QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI = CoreCommonConstants.MGMT_URI + PING_MEASUREMENTS; + private static final String GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_MGMT_URI = QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI + "/{" + PATH_VARIABLE_ID + "}"; + private static final String GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_URI = CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT + "/{" + PATH_VARIABLE_ID + "}"; + + private static final String ID_NOT_VALID_ERROR_MESSAGE = " Id must be greater than 0. "; + private static final String PAGE_OR_SIZE_ERROR_MESSAGE = "Defined page or size could not be with undefined size or page."; + + + @Autowired + private WebApplicationContext wac; + + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean(name = "mockQoSDBService") + QoSDBService qoSDBService; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Before + public void setup() { + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void echoTest() throws Exception { + this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + CommonConstants.ECHO_URI) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } + + //================================================================================================= + // Test of getPingMeasurements + + //------------------------------------------------------------------------------------------------- + @Test + public void getPingMeasurementsWithoutParametersTest() throws Exception { + final PingMeasurementListResponseDTO pingMeasurementListResponseDTO = getPingMeasurementListResponseDTOForTest(); + + when(qoSDBService.getPingMeasurementResponse( anyInt(), anyInt(), any(), anyString())).thenReturn(pingMeasurementListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final PingMeasurementListResponseDTO responseBody = objectMapper.readValue(response.getResponse().getContentAsString(), PingMeasurementListResponseDTO.class); + assertEquals(pingMeasurementListResponseDTO.getData().size(), responseBody.getData().size()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void getPingMeasurementsWithPageAndSizeParametersTest() throws Exception { + final int responseSize = 3; + final PingMeasurementListResponseDTO pingMeasurementListResponseDTO = getPingMeasurementListResponseDTOForTest(responseSize); + + when(qoSDBService.getPingMeasurementResponse( anyInt(), anyInt(), any(), anyString())).thenReturn(pingMeasurementListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI) + .param("page", "0") + .param("item_per_page", String.valueOf(responseSize)) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final PingMeasurementListResponseDTO responseBody = objectMapper.readValue(response.getResponse().getContentAsString(), PingMeasurementListResponseDTO.class); + assertEquals(pingMeasurementListResponseDTO.getData().size(), responseBody.getData().size()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void getPingMeasurementsWithNullPageButDefinedSizeParameterTest() throws Exception { + final int responseSize = 3; + final PingMeasurementListResponseDTO pingMeasurementListResponseDTO = getPingMeasurementListResponseDTOForTest(responseSize); + + when(qoSDBService.getPingMeasurementResponse( anyInt(), anyInt(), any(), anyString())).thenReturn(pingMeasurementListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI) + .param("item_per_page", String.valueOf(responseSize)) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + + final ErrorMessageDTO responseBody = objectMapper.readValue(response.getResponse().getContentAsString(), ErrorMessageDTO.class); + assertEquals(ExceptionType.BAD_PAYLOAD, responseBody.getExceptionType()); + assertTrue(responseBody.getErrorMessage().contains(PAGE_OR_SIZE_ERROR_MESSAGE)); + assertEquals(CommonConstants.QOS_MONITOR_URI + QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI, responseBody.getOrigin()); + } + + //================================================================================================= + // Test of getManagementPingMeasurementBySystemId + + //------------------------------------------------------------------------------------------------- + @Test + public void getManagementPingMeasurementBySystemIdTest() throws Exception { + final int requestedId = 1; + final PingMeasurementResponseDTO pingMeasurementResponseDTO = getPingMeasurementResponseDTOForTest(); + + when(qoSDBService.getPingMeasurementBySystemIdResponse(anyLong())).thenReturn(pingMeasurementResponseDTO); + + final MvcResult response = this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI + "/" + requestedId) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final PingMeasurementResponseDTO responseBody = objectMapper.readValue(response.getResponse().getContentAsString(), PingMeasurementResponseDTO.class); + assertEquals(requestedId, responseBody.getMeasurement().getSystem().getId()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void getManagementPingMeasurementBySystemIdInvalidSystemIdTest() throws Exception { + final int requestedId = 0; + final PingMeasurementResponseDTO pingMeasurementResponseDTO = getPingMeasurementResponseDTOForTest(); + + when(qoSDBService.getPingMeasurementBySystemIdResponse(anyLong())).thenReturn(pingMeasurementResponseDTO); + + final MvcResult response = this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI + "/" + requestedId) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + + final ErrorMessageDTO responseBody = objectMapper.readValue(response.getResponse().getContentAsString(), ErrorMessageDTO.class); + assertEquals(ExceptionType.BAD_PAYLOAD, responseBody.getExceptionType()); + assertEquals(ID_NOT_VALID_ERROR_MESSAGE, responseBody.getErrorMessage()); + assertEquals(CommonConstants.QOS_MONITOR_URI + GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_MGMT_URI, responseBody.getOrigin()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void getManagementPingMeasurementBySystemIdDBExceptionTest() throws Exception { + final int requestedId = 1; + + when(qoSDBService.getPingMeasurementBySystemIdResponse(anyLong())).thenThrow(new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG)); + + final MvcResult response = this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI + "/" + requestedId) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isInternalServerError()) + .andReturn(); + + final ErrorMessageDTO responseBody = objectMapper.readValue(response.getResponse().getContentAsString(), ErrorMessageDTO.class); + assertEquals(ExceptionType.ARROWHEAD, responseBody.getExceptionType()); + assertEquals(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG, responseBody.getErrorMessage()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void getManagementPingMeasurementBySystemIdNoMeasurementInDBTest() throws Exception { + final int requestedId = 1; + final PingMeasurementResponseDTO pingMeasurementResponseDTO = new PingMeasurementResponseDTO(); + pingMeasurementResponseDTO.setId( null ); + + when(qoSDBService.getPingMeasurementBySystemIdResponse(anyLong())).thenReturn(pingMeasurementResponseDTO); + + final MvcResult response = this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI + "/" + requestedId) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final PingMeasurementResponseDTO responseBody = objectMapper.readValue(response.getResponse().getContentAsString(), PingMeasurementResponseDTO.class); + assertNull(responseBody.getId()); + } + + //================================================================================================= + // Test of getPingMeasurementBySystemIdResponse + + //------------------------------------------------------------------------------------------------- + @Test + public void getPingMeasurementBySystemIdTest() throws Exception { + final int requestedId = 1; + final PingMeasurementResponseDTO pingMeasurementResponseDTO = getPingMeasurementResponseDTOForTest(); + + when(qoSDBService.getPingMeasurementBySystemIdResponse(anyLong())).thenReturn(pingMeasurementResponseDTO); + + final MvcResult response = this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT + "/" + requestedId) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final PingMeasurementResponseDTO responseBody = objectMapper.readValue(response.getResponse().getContentAsString(), PingMeasurementResponseDTO.class); + assertEquals(requestedId, responseBody.getMeasurement().getSystem().getId()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void getPingMeasurementBySystemIdInvalidSystemIdTest() throws Exception { + final int requestedId = 0; + final PingMeasurementResponseDTO pingMeasurementResponseDTO = getPingMeasurementResponseDTOForTest(); + + when(qoSDBService.getPingMeasurementBySystemIdResponse(anyLong())).thenReturn(pingMeasurementResponseDTO); + + final MvcResult response = this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT + "/" + requestedId) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + + final ErrorMessageDTO responseBody = objectMapper.readValue(response.getResponse().getContentAsString(), ErrorMessageDTO.class); + assertEquals(ExceptionType.BAD_PAYLOAD, responseBody.getExceptionType()); + assertEquals(ID_NOT_VALID_ERROR_MESSAGE, responseBody.getErrorMessage()); + assertEquals(CommonConstants.QOS_MONITOR_URI + GET_QOS_MONITOR_PING_MEASUREMENTS_BY_SYSTEM_ID_URI, responseBody.getOrigin()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void getPingMeasurementBySystemIdDBExceptionTest() throws Exception { + final int requestedId = 1; + + when(qoSDBService.getPingMeasurementBySystemIdResponse(anyLong())).thenThrow(new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG)); + + final MvcResult response = this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT + "/" + requestedId) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isInternalServerError()) + .andReturn(); + + final ErrorMessageDTO responseBody = objectMapper.readValue(response.getResponse().getContentAsString(), ErrorMessageDTO.class); + assertEquals(ExceptionType.ARROWHEAD, responseBody.getExceptionType()); + assertEquals(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG, responseBody.getErrorMessage()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void getPingMeasurementBySystemIdNoMeasurementInDBTest() throws Exception { + final int requestedId = 1; + final PingMeasurementResponseDTO pingMeasurementResponseDTO = new PingMeasurementResponseDTO(); + pingMeasurementResponseDTO.setId( null ); + + when(qoSDBService.getPingMeasurementBySystemIdResponse(anyLong())).thenReturn(pingMeasurementResponseDTO); + + final MvcResult response = this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT + "/" + requestedId) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final PingMeasurementResponseDTO responseBody = objectMapper.readValue(response.getResponse().getContentAsString(), PingMeasurementResponseDTO.class); + assertNull(responseBody.getId()); + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + private PingMeasurementListResponseDTO getPingMeasurementListResponseDTOForTest() { + + final int responseSize = 3; + final List pingMeasurementList = new ArrayList<>(3); + + for (int i = 0; i < responseSize; i++) { + pingMeasurementList.add(getPingMeasurementResponseDTOForTest()); + } + + return new PingMeasurementListResponseDTO(pingMeasurementList, responseSize); + } + + //------------------------------------------------------------------------------------------------- + private PingMeasurementListResponseDTO getPingMeasurementListResponseDTOForTest(final int responseSize) { + + final List pingMeasurementList = new ArrayList<>(responseSize); + + for (int i = 0; i < responseSize; i++) { + pingMeasurementList.add(getPingMeasurementResponseDTOForTest()); + } + + return new PingMeasurementListResponseDTO(pingMeasurementList, responseSize); + } + + //------------------------------------------------------------------------------------------------- + private PingMeasurementResponseDTO getPingMeasurementResponseDTOForTest() { + + final QoSIntraMeasurementResponseDTO qoSIntraMeasurementResponseDTO = getQoSIntraMeasurementResponseDTOForTest(); + + final PingMeasurementResponseDTO pingMeasurementResponseDTO = new PingMeasurementResponseDTO(); + pingMeasurementResponseDTO.setId(1L); + pingMeasurementResponseDTO.setMeasurement(qoSIntraMeasurementResponseDTO); + pingMeasurementResponseDTO.setAvailable(true); + pingMeasurementResponseDTO.setLastAccessAt(ZonedDateTime.now()); + pingMeasurementResponseDTO.setMinResponseTime(1); + pingMeasurementResponseDTO.setMaxResponseTime(1); + pingMeasurementResponseDTO.setMeanResponseTimeWithTimeout(1); + pingMeasurementResponseDTO.setMeanResponseTimeWithoutTimeout(1); + pingMeasurementResponseDTO.setJitterWithTimeout(0); + pingMeasurementResponseDTO.setJitterWithoutTimeout(0); + pingMeasurementResponseDTO.setLostPerMeasurementPercent(0); + pingMeasurementResponseDTO.setSent(35); + pingMeasurementResponseDTO.setReceived(35); + pingMeasurementResponseDTO.setCountStartedAt(ZonedDateTime.now()); + pingMeasurementResponseDTO.setSentAll(35); + pingMeasurementResponseDTO.setReceivedAll(35); + pingMeasurementResponseDTO.setCreatedAt(ZonedDateTime.now()); + pingMeasurementResponseDTO.setUpdatedAt(ZonedDateTime.now()); + + return pingMeasurementResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + private QoSIntraMeasurementResponseDTO getQoSIntraMeasurementResponseDTOForTest() { + + final SystemResponseDTO system = getSystemResponseDTOForTest(); + + return new QoSIntraMeasurementResponseDTO( + 1,//measurement.getId(), + system, + QoSMeasurementType.PING,//measurement.getMeasurementType(), + ZonedDateTime.now(),//measurement.getLastMeasurementAt(), + ZonedDateTime.now(),//measurement.getCreatedAt(), + ZonedDateTime.now());//measurement.getUpdatedAt()); + } + + //------------------------------------------------------------------------------------------------- + private SystemResponseDTO getSystemResponseDTOForTest() { + + return new SystemResponseDTO( + 1L, + "testSystemName",//system.getSystemName(), + "localhost",//system.getAddress(), + 12345,//system.getPort(), + "authinfo",//system.getAuthenticationInfo(), + Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now()), + Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now())); + + } + +} diff --git a/qos-monitor/src/test/java/eu/arrowhead/core/qos/QoSMonitorTestContext.java b/qos-monitor/src/test/java/eu/arrowhead/core/qos/QoSMonitorTestContext.java new file mode 100644 index 000000000..98d9170f7 --- /dev/null +++ b/qos-monitor/src/test/java/eu/arrowhead/core/qos/QoSMonitorTestContext.java @@ -0,0 +1,22 @@ +package eu.arrowhead.core.qos; + +import org.mockito.Mockito; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; + +import eu.arrowhead.core.qos.database.service.QoSDBService; + +@Configuration +public class QoSMonitorTestContext { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Bean + @Primary // This bean is primary only in test context + public QoSDBService mockQoSDBService() { + return Mockito.mock(QoSDBService.class); + } +} diff --git a/qos-monitor/src/test/java/eu/arrowhead/core/qos/StandaloneModeInQoSMonitorTests.java b/qos-monitor/src/test/java/eu/arrowhead/core/qos/StandaloneModeInQoSMonitorTests.java new file mode 100644 index 000000000..2c3ef196c --- /dev/null +++ b/qos-monitor/src/test/java/eu/arrowhead/core/qos/StandaloneModeInQoSMonitorTests.java @@ -0,0 +1,10 @@ +package eu.arrowhead.core.qos; + +import org.springframework.stereotype.Component; + +import eu.arrowhead.common.testhelper.StandaloneModeInTests; + +@Component +public class StandaloneModeInQoSMonitorTests extends StandaloneModeInTests { + +} diff --git a/qos-monitor/src/test/java/eu/arrowhead/core/qos/database/service/QoSDBServiceTest.java b/qos-monitor/src/test/java/eu/arrowhead/core/qos/database/service/QoSDBServiceTest.java new file mode 100644 index 000000000..c16ed51cf --- /dev/null +++ b/qos-monitor/src/test/java/eu/arrowhead/core/qos/database/service/QoSDBServiceTest.java @@ -0,0 +1,1724 @@ +package eu.arrowhead.core.qos.database.service; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; + +import org.hibernate.HibernateException; +import org.icmp4j.IcmpPingResponse; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort.Direction; +import org.springframework.test.context.junit4.SpringRunner; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.database.entity.QoSIntraMeasurement; +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurement; +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurementLog; +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurementLogDetails; +import eu.arrowhead.common.database.entity.System; +import eu.arrowhead.common.database.repository.QoSIntraMeasurementPingRepository; +import eu.arrowhead.common.database.repository.QoSIntraMeasurementRepository; +import eu.arrowhead.common.database.repository.QoSIntraPingMeasurementLogDetailsRepository; +import eu.arrowhead.common.database.repository.QoSIntraPingMeasurementLogRepository; +import eu.arrowhead.common.database.repository.SystemRepository; +import eu.arrowhead.common.dto.internal.DTOConverter; +import eu.arrowhead.common.dto.shared.QoSMeasurementType; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.common.exception.InvalidParameterException; +import eu.arrowhead.core.qos.dto.PingMeasurementCalculationsDTO; + +@RunWith(SpringRunner.class) +public class QoSDBServiceTest { + + //================================================================================================= + // members + @InjectMocks + private QoSDBService qoSDBService; + + @Mock + private QoSIntraMeasurementRepository qoSIntraMeasurementRepository; + + @Mock + private QoSIntraMeasurementPingRepository qoSIntraMeasurementPingRepository; + + @Mock + private QoSIntraPingMeasurementLogRepository qoSIntraPingMeasurementLogRepository; + + @Mock + private QoSIntraPingMeasurementLogDetailsRepository qoSIntraPingMeasurementLogDetailsRepository; + + @Mock + private SystemRepository systemRepository; + + private static final String LESS_THAN_ONE_ERROR_MESSAGE= " must be greater than zero."; + private static final String NOT_AVAILABLE_SORTABLE_FIELD_ERROR_MESSAGE = " sortable field is not available."; + private static final String NOT_IN_DB_ERROR_MESSAGE = " is not available in database"; + private static final String EMPTY_OR_NULL_ERROR_MESSAGE = " is empty or null"; + private static final String NULL_ERROR_MESSAGE = " is null"; + + //================================================================================================= + // methods + + //================================================================================================= + // Tests of updateCountStartedAt + + //------------------------------------------------------------------------------------------------- + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void testUpdateCountStartedAt() { + + final ZonedDateTime testStartedAt = ZonedDateTime.now().minusMinutes(1); + final List measurementList = getQosIntraPingMeasurementListForTest(); + final ArgumentCaptor valueCapture = ArgumentCaptor.forClass(List.class); + + when(qoSIntraMeasurementPingRepository.findAll()).thenReturn(measurementList); + when(qoSIntraMeasurementPingRepository.saveAll(valueCapture.capture())).thenReturn(List.of()); + doNothing().when(qoSIntraMeasurementPingRepository).flush(); + + qoSDBService.updateCountStartedAt(); + + verify(qoSIntraMeasurementPingRepository, times(1)).findAll(); + verify(qoSIntraMeasurementPingRepository, times(1)).saveAll(any()); + verify(qoSIntraMeasurementPingRepository, times(1)).flush(); + + final List captured = valueCapture.getValue(); + assertEquals(measurementList.size(), captured.size()); + for (final QoSIntraPingMeasurement qoSIntraPingMeasurement : captured) { + + assertEquals(0, qoSIntraPingMeasurement.getSent()); + assertEquals(0, qoSIntraPingMeasurement.getReceived()); + assertTrue(qoSIntraPingMeasurement.getCountStartedAt().isAfter(testStartedAt)); + } + } + + //------------------------------------------------------------------------------------------------- + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test(expected = ArrowheadException.class) + public void testUpdateCountStartedAtFlushThrowDatabaseException() { + + final ZonedDateTime testStartedAt = ZonedDateTime.now().minusMinutes(1);; + final List measurementList = getQosIntraPingMeasurementListForTest(); + final ArgumentCaptor valueCapture = ArgumentCaptor.forClass(List.class); + + when(qoSIntraMeasurementPingRepository.findAll()).thenReturn(measurementList); + when(qoSIntraMeasurementPingRepository.saveAll(valueCapture.capture())).thenReturn(List.of()); + doThrow(HibernateException.class).when(qoSIntraMeasurementPingRepository).flush(); + + try { + + qoSDBService.updateCountStartedAt(); + + } catch (final Exception ex) { + + assertEquals(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG, ex.getMessage()); + + verify(qoSIntraMeasurementPingRepository, times(1)).findAll(); + verify(qoSIntraMeasurementPingRepository, times(1)).saveAll(any()); + verify(qoSIntraMeasurementPingRepository, times(1)).flush(); + + final List captured = valueCapture.getValue(); + assertEquals(measurementList.size(), captured.size()); + + for (final QoSIntraPingMeasurement qoSIntraPingMeasurement : captured) { + + assertEquals(0, qoSIntraPingMeasurement.getSent()); + assertEquals(0, qoSIntraPingMeasurement.getReceived()); + assertTrue(qoSIntraPingMeasurement.getCountStartedAt().isAfter(testStartedAt)); + } + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test(expected = ArrowheadException.class) + public void testUpdateCountStartedAtSaveAllThrowDatabaseException() { + + final ZonedDateTime testStartedAt = ZonedDateTime.now().minusMinutes(1); + final List measurementList = getQosIntraPingMeasurementListForTest(); + final ArgumentCaptor valueCapture = ArgumentCaptor.forClass(List.class); + + when(qoSIntraMeasurementPingRepository.findAll()).thenReturn(measurementList); + when(qoSIntraMeasurementPingRepository.saveAll(valueCapture.capture())).thenThrow(HibernateException.class); + doNothing().when(qoSIntraMeasurementPingRepository).flush(); + + try { + + qoSDBService.updateCountStartedAt(); + + } catch (final Exception ex) { + + assertEquals(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG, ex.getMessage()); + + verify(qoSIntraMeasurementPingRepository, times(1)).findAll(); + verify(qoSIntraMeasurementPingRepository, times(1)).saveAll(any()); + verify(qoSIntraMeasurementPingRepository, times(0)).flush(); + + final List captured = valueCapture.getValue(); + assertEquals(measurementList.size(), captured.size()); + + for (final QoSIntraPingMeasurement qoSIntraPingMeasurement : captured) { + + assertEquals(0, qoSIntraPingMeasurement.getSent()); + assertEquals(0, qoSIntraPingMeasurement.getReceived()); + assertTrue(qoSIntraPingMeasurement.getCountStartedAt().isAfter(testStartedAt)); + } + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testUpdateCountStartedAtFindAllThrowDatabaseException() { + + final List measurementList = getQosIntraPingMeasurementListForTest(); + + when(qoSIntraMeasurementPingRepository.findAll()).thenThrow(HibernateException.class); + when(qoSIntraMeasurementPingRepository.saveAll(any())).thenReturn(measurementList); + doNothing().when(qoSIntraMeasurementPingRepository).flush(); + + try { + + qoSDBService.updateCountStartedAt(); + + } catch (final Exception ex) { + + assertEquals(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG, ex.getMessage()); + + verify(qoSIntraMeasurementPingRepository, times(1)).findAll(); + verify(qoSIntraMeasurementPingRepository, times(0)).saveAll(any()); + verify(qoSIntraMeasurementPingRepository, times(0)).flush(); + + throw ex; + } + + } + + //================================================================================================= + // Tests of createMeasurement + + //------------------------------------------------------------------------------------------------- + @Test + public void testCreateMeasurement() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final System system = getSystemForTest(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final ArgumentCaptor valueCapture = ArgumentCaptor.forClass(QoSIntraMeasurement.class); + + when(qoSIntraMeasurementRepository.saveAndFlush(valueCapture.capture())).thenReturn(measurement); + + qoSDBService.createMeasurement(system, QoSMeasurementType.PING, aroundNow); + + verify(qoSIntraMeasurementRepository, times(1)).saveAndFlush(any()); + + final QoSIntraMeasurement captured = valueCapture.getValue(); + assertEquals(system.getId(), captured.getSystem().getId()); + assertEquals(QoSMeasurementType.PING, captured.getMeasurementType()); + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testCreateMeasurementSaveAndFlushThrowException() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final System system = getSystemForTest(); + + final ArgumentCaptor valueCapture = ArgumentCaptor.forClass(QoSIntraMeasurement.class); + + when(qoSIntraMeasurementRepository.saveAndFlush(valueCapture.capture())).thenThrow(HibernateException.class); + + qoSDBService.createMeasurement(system, QoSMeasurementType.PING, aroundNow); + + verify(qoSIntraMeasurementRepository, times(1)).saveAndFlush(any()); + + final QoSIntraMeasurement captured = valueCapture.getValue(); + assertEquals(system.getId(), captured.getSystem().getId()); + assertEquals(QoSMeasurementType.PING, captured.getMeasurementType()); + + } + + //================================================================================================= + // Tests of getMeasurement + + //------------------------------------------------------------------------------------------------- + @Test + public void testGetMeasurement() { + + final SystemResponseDTO systemResponseDTO = getSystemResponseDTOForTest(); + final System system = getSystemForTest(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + when(systemRepository.findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt())).thenReturn(Optional.of(system)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.of(measurement)); + + qoSDBService.getOrCreateMeasurement(systemResponseDTO); + + verify(systemRepository, times(1)).findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt()); + verify(qoSIntraMeasurementRepository, times(1)).findBySystemAndMeasurementType(any(), any()); + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testGetMeasurementRequestedSystemNotInDB() { + + final SystemResponseDTO systemResponseDTO = getSystemResponseDTOForTest(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + when(systemRepository.findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt())).thenReturn(Optional.ofNullable(null)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.of(measurement)); + + try { + + qoSDBService.getOrCreateMeasurement(systemResponseDTO); + + } catch (final Exception ex) { + + assertEquals("Requested system" + NOT_IN_DB_ERROR_MESSAGE, ex.getMessage()); + + verify(systemRepository, times(1)).findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt()); + verify(qoSIntraMeasurementRepository, times(0)).findBySystemAndMeasurementType(any(), any()); + + throw ex; + } + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testGetMeasurementMeasurementNotInDB() { + + final SystemResponseDTO systemResponseDTO = getSystemResponseDTOForTest(); + final System system = getSystemForTest(); + + when(systemRepository.findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt())).thenReturn(Optional.of(system)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.ofNullable(null)); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + when(qoSIntraMeasurementRepository.saveAndFlush(any())).thenReturn(measurement); + + qoSDBService.getOrCreateMeasurement(systemResponseDTO); + + verify(systemRepository, times(1)).findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt()); + verify(qoSIntraMeasurementRepository, times(1)).findBySystemAndMeasurementType(any(), any()); + verify(qoSIntraMeasurementRepository, times(1)).saveAndFlush(any()); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testGetMeasurementNullRequestParameter() { + + final System system = getSystemForTest(); + final SystemResponseDTO systemResponseDTO = null; + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + when(systemRepository.findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt())).thenReturn(Optional.of(system)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.of(measurement)); + + try { + + qoSDBService.getOrCreateMeasurement(systemResponseDTO); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("SystemRequestDTO" + NULL_ERROR_MESSAGE)); + + verify(systemRepository, times(0)).findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt()); + verify(qoSIntraMeasurementRepository, times(0)).findBySystemAndMeasurementType(any(), any()); + + throw ex; + } + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testGetMeasurementSystemNameIsNullSystemResponseDTOParameter() { + + final System system = getSystemForTest(); + final SystemResponseDTO systemResponseDTO = getSystemResponseDTOForTest(); + systemResponseDTO.setSystemName(null); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + when(systemRepository.findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt())).thenReturn(Optional.of(system)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.of(measurement)); + + try { + + qoSDBService.getOrCreateMeasurement(systemResponseDTO); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("System name" + EMPTY_OR_NULL_ERROR_MESSAGE)); + + verify(systemRepository, times(0)).findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt()); + verify(qoSIntraMeasurementRepository, times(0)).findBySystemAndMeasurementType(any(), any()); + + throw ex; + } + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testGetMeasurementSystemNameIsEmptySystemResponseDTOParameter() { + + final System system = getSystemForTest(); + final SystemResponseDTO systemResponseDTO = getSystemResponseDTOForTest(); + systemResponseDTO.setSystemName(" "); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + when(systemRepository.findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt())).thenReturn(Optional.of(system)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.of(measurement)); + + try { + + qoSDBService.getOrCreateMeasurement(systemResponseDTO); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("System name" + EMPTY_OR_NULL_ERROR_MESSAGE)); + + verify(systemRepository, times(0)).findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt()); + verify(qoSIntraMeasurementRepository, times(0)).findBySystemAndMeasurementType(any(), any()); + + throw ex; + } + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testGetMeasurementSystemAddressIsNullSystemResponseDTOParameter() { + + final System system = getSystemForTest(); + final SystemResponseDTO systemResponseDTO = getSystemResponseDTOForTest(); + systemResponseDTO.setAddress(null); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + when(systemRepository.findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt())).thenReturn(Optional.of(system)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.of(measurement)); + + try { + + qoSDBService.getOrCreateMeasurement(systemResponseDTO); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("System address" + EMPTY_OR_NULL_ERROR_MESSAGE)); + + verify(systemRepository, times(0)).findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt()); + verify(qoSIntraMeasurementRepository, times(0)).findBySystemAndMeasurementType(any(), any()); + + throw ex; + } + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testGetMeasurementSystemAddressIsEmptySystemResponseDTOParameter() { + + final System system = getSystemForTest(); + final SystemResponseDTO systemResponseDTO = getSystemResponseDTOForTest(); + systemResponseDTO.setAddress(" "); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + when(systemRepository.findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt())).thenReturn(Optional.of(system)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.of(measurement)); + + try { + + qoSDBService.getOrCreateMeasurement(systemResponseDTO); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("System address" + EMPTY_OR_NULL_ERROR_MESSAGE)); + + verify(systemRepository, times(0)).findBySystemNameAndAddressAndPort(anyString(), anyString(), anyInt()); + verify(qoSIntraMeasurementRepository, times(0)).findBySystemAndMeasurementType(any(), any()); + + throw ex; + } + } + + //================================================================================================= + // Tests of createMeasurement + + //------------------------------------------------------------------------------------------------- + @Test + public void testCreatePingMeasurement() { + + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + final QoSIntraMeasurement measurementParam = getQoSIntraMeasurementForTest(); + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + final ZonedDateTime aroundNow = ZonedDateTime.now(); + + when(qoSIntraMeasurementPingRepository.saveAndFlush(any())).thenReturn(pingMeasurement); + + qoSDBService.createPingMeasurement(measurementParam, calculations, aroundNow); + + verify(qoSIntraMeasurementPingRepository, times(1)).saveAndFlush(any()); + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testCreatePingMeasurementWithNullMeasurementParameter() { + + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + final QoSIntraMeasurement measurementParam = null; + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + final ZonedDateTime aroundNow = ZonedDateTime.now(); + + when(qoSIntraMeasurementPingRepository.saveAndFlush(any())).thenReturn(pingMeasurement); + + try { + + qoSDBService.createPingMeasurement(measurementParam, calculations, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("QoSIntraMeasurement" + NULL_ERROR_MESSAGE)); + verify(qoSIntraMeasurementPingRepository, times(0)).saveAndFlush(any()); + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testCreatePingMeasurementWithNullCalculationsParameter() { + + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + final QoSIntraMeasurement measurementParam = getQoSIntraMeasurementForTest(); + final PingMeasurementCalculationsDTO calculations = null;//getCalculationsForTest(); + final ZonedDateTime aroundNow = ZonedDateTime.now(); + + when(qoSIntraMeasurementPingRepository.saveAndFlush(any())).thenReturn(pingMeasurement); + + try { + + qoSDBService.createPingMeasurement(measurementParam, calculations, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("PingMeasurementCalculationsDTO" + NULL_ERROR_MESSAGE)); + verify(qoSIntraMeasurementPingRepository, times(0)).saveAndFlush(any()); + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testCreatePingMeasurementWithNullAroundNowParameter() { + + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + final QoSIntraMeasurement measurementParam = getQoSIntraMeasurementForTest(); + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + final ZonedDateTime aroundNow = null;//ZonedDateTime.now(); + + when(qoSIntraMeasurementPingRepository.saveAndFlush(any())).thenReturn(pingMeasurement); + + try { + + qoSDBService.createPingMeasurement(measurementParam, calculations, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("ZonedDateTime" + NULL_ERROR_MESSAGE)); + verify(qoSIntraMeasurementPingRepository, times(0)).saveAndFlush(any()); + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testCreatePingMeasurementSaveAndFlushThrowsDatabseException() { + + final QoSIntraMeasurement measurementParam = getQoSIntraMeasurementForTest(); + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + final ZonedDateTime aroundNow = ZonedDateTime.now(); + + when(qoSIntraMeasurementPingRepository.saveAndFlush(any())).thenThrow(HibernateException.class); + + try { + + qoSDBService.createPingMeasurement(measurementParam, calculations, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG)); + verify(qoSIntraMeasurementPingRepository, times(1)).saveAndFlush(any()); + throw ex; + } + + } + + //================================================================================================= + // Tests of getPingMeasurementByMeasurement + + //------------------------------------------------------------------------------------------------- + @Test + public void testGetPingMeasurementByMeasurement() { + + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + final QoSIntraMeasurement measurementParam = getQoSIntraMeasurementForTest(); + + when(qoSIntraMeasurementPingRepository.findByMeasurement(any())).thenReturn(Optional.of(pingMeasurement)); + + qoSDBService.getPingMeasurementByMeasurement(measurementParam); + + verify(qoSIntraMeasurementPingRepository, times(1)).findByMeasurement(any()); + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testGetPingMeasurementByMeasurementWithNullMeasurementParameter() { + + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + final QoSIntraMeasurement measurementParam = null;//getQoSIntraMeasurementForTest(); + + when(qoSIntraMeasurementPingRepository.findByMeasurement(any())).thenReturn(Optional.of(pingMeasurement)); + + try { + + qoSDBService.getPingMeasurementByMeasurement(measurementParam); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("QoSIntraMeasurement" + NULL_ERROR_MESSAGE)); + verify(qoSIntraMeasurementPingRepository, times(0)).findByMeasurement(any()); + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testGetPingMeasurementByMeasurementFindByMeasurementThrowsException() { + + final QoSIntraMeasurement measurementParam = getQoSIntraMeasurementForTest(); + + when(qoSIntraMeasurementPingRepository.findByMeasurement(any())).thenThrow(HibernateException.class); + + try { + + qoSDBService.getPingMeasurementByMeasurement(measurementParam); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG)); + verify(qoSIntraMeasurementPingRepository, times(1)).findByMeasurement(any()); + throw ex; + } + + } + + //================================================================================================= + // Tests of logMeasurementToDB + + //------------------------------------------------------------------------------------------------- + @Test + public void testLogMeasurementToDB() { + + final String address = "address"; + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + + final QoSIntraPingMeasurementLog measurementLog = new QoSIntraPingMeasurementLog(); + + when(qoSIntraPingMeasurementLogRepository.saveAndFlush(any())).thenReturn(measurementLog); + + qoSDBService.logMeasurementToDB(address, calculations, aroundNow); + + verify(qoSIntraPingMeasurementLogRepository, times(1)).saveAndFlush(any()); + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testLogMeasurementToDBWithNullAddressParameter() { + + final String address = null;//"address"; + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + + final QoSIntraPingMeasurementLog measurementLog = new QoSIntraPingMeasurementLog(); + + when(qoSIntraPingMeasurementLogRepository.saveAndFlush(any())).thenReturn(measurementLog); + + try { + + qoSDBService.logMeasurementToDB(address, calculations, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("Address" + EMPTY_OR_NULL_ERROR_MESSAGE)); + verify(qoSIntraPingMeasurementLogRepository, times(0)).saveAndFlush(any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testLogMeasurementToDBWithEmptyAddressParameter() { + + final String address = " ";//"address"; + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + + final QoSIntraPingMeasurementLog measurementLog = new QoSIntraPingMeasurementLog(); + + when(qoSIntraPingMeasurementLogRepository.saveAndFlush(any())).thenReturn(measurementLog); + + try { + + qoSDBService.logMeasurementToDB(address, calculations, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("Address" + EMPTY_OR_NULL_ERROR_MESSAGE)); + verify(qoSIntraPingMeasurementLogRepository, times(0)).saveAndFlush(any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testLogMeasurementToDBWithNullAroundNowParameter() { + + final String address = "address"; + final ZonedDateTime aroundNow = null;//ZonedDateTime.now(); + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + + final QoSIntraPingMeasurementLog measurementLog = new QoSIntraPingMeasurementLog(); + + when(qoSIntraPingMeasurementLogRepository.saveAndFlush(any())).thenReturn(measurementLog); + + try { + + qoSDBService.logMeasurementToDB(address, calculations, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("ZonedDateTime" + NULL_ERROR_MESSAGE)); + verify(qoSIntraPingMeasurementLogRepository, times(0)).saveAndFlush(any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testLogMeasurementToDBWithNullCalculationsParameter() { + + final String address = "address"; + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final PingMeasurementCalculationsDTO calculations = null;//getCalculationsForTest(); + + final QoSIntraPingMeasurementLog measurementLog = new QoSIntraPingMeasurementLog(); + + when(qoSIntraPingMeasurementLogRepository.saveAndFlush(any())).thenReturn(measurementLog); + + try { + + qoSDBService.logMeasurementToDB(address, calculations, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("PingMeasurementCalculationsDTO" + NULL_ERROR_MESSAGE)); + verify(qoSIntraPingMeasurementLogRepository, times(0)).saveAndFlush(any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testLogMeasurementToDBSaveAndFlushThrowException() { + + final String address = "address"; + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + + when(qoSIntraPingMeasurementLogRepository.saveAndFlush(any())).thenThrow(HibernateException.class); + + try { + + qoSDBService.logMeasurementToDB(address, calculations, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG)); + verify(qoSIntraPingMeasurementLogRepository, times(1)).saveAndFlush(any()); + + throw ex; + } + + } + + //================================================================================================= + // Tests of logMeasurementDetailsToDB + + //------------------------------------------------------------------------------------------------- + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test + public void testLogMeasurementDetailsToDB() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final List responseList = getResponseListForTest(); + final QoSIntraPingMeasurementLog measurementLogSaved = new QoSIntraPingMeasurementLog(); + + final ArgumentCaptor valueCapture = ArgumentCaptor.forClass(List.class); + final List measurementLogDetailsList = List.of(new QoSIntraPingMeasurementLogDetails()); + + when(qoSIntraPingMeasurementLogDetailsRepository.saveAll(valueCapture.capture())).thenReturn(measurementLogDetailsList); + doNothing().when(qoSIntraPingMeasurementLogDetailsRepository).flush(); + + qoSDBService.logMeasurementDetailsToDB(measurementLogSaved, responseList, aroundNow); + + verify(qoSIntraPingMeasurementLogDetailsRepository, times(1)).saveAll(any()); + verify(qoSIntraPingMeasurementLogDetailsRepository, times(1)).flush(); + + final List captured = valueCapture.getValue(); + assertEquals(responseList.size(), captured.size()); + for (final QoSIntraPingMeasurementLogDetails qoSIntraPingMeasurementLogDetails : captured) { + + assertNotNull(qoSIntraPingMeasurementLogDetails.getMeasurementLog()); + assertNotNull(qoSIntraPingMeasurementLogDetails.isSuccessFlag()); + assertNotNull(qoSIntraPingMeasurementLogDetails.getMeasuredAt()); + + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testLogMeasurementDetailsToDBWithNullResponseListParameter() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final List responseList = null;//getResponseListForTest(); + final QoSIntraPingMeasurementLog measurementLogSaved = new QoSIntraPingMeasurementLog(); + + final List measurementLogDetailsList = List.of(new QoSIntraPingMeasurementLogDetails()); + + when(qoSIntraPingMeasurementLogDetailsRepository.saveAll(any())).thenReturn(measurementLogDetailsList); + doNothing().when(qoSIntraPingMeasurementLogDetailsRepository).flush(); + + try { + + qoSDBService.logMeasurementDetailsToDB(measurementLogSaved, responseList, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("List" + EMPTY_OR_NULL_ERROR_MESSAGE)); + verify(qoSIntraPingMeasurementLogDetailsRepository, times(0)).saveAll(any()); + verify(qoSIntraPingMeasurementLogDetailsRepository, times(0)).flush(); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testLogMeasurementDetailsToDBWithEmptyResponseListParameter() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final List responseList = List.of();//getResponseListForTest(); + final QoSIntraPingMeasurementLog measurementLogSaved = new QoSIntraPingMeasurementLog(); + + final List measurementLogDetailsList = List.of(new QoSIntraPingMeasurementLogDetails()); + + when(qoSIntraPingMeasurementLogDetailsRepository.saveAll(any())).thenReturn(measurementLogDetailsList); + doNothing().when(qoSIntraPingMeasurementLogDetailsRepository).flush(); + + try { + + qoSDBService.logMeasurementDetailsToDB(measurementLogSaved, responseList, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("List" + EMPTY_OR_NULL_ERROR_MESSAGE)); + verify(qoSIntraPingMeasurementLogDetailsRepository, times(0)).saveAll(any()); + verify(qoSIntraPingMeasurementLogDetailsRepository, times(0)).flush(); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testLogMeasurementDetailsToDBWithNullMeasurementLogSavedParameter() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final List responseList = getResponseListForTest(); + final QoSIntraPingMeasurementLog measurementLogSaved = null;//new QoSIntraPingMeasurementLog(); + + final List measurementLogDetailsList = List.of(new QoSIntraPingMeasurementLogDetails()); + + when(qoSIntraPingMeasurementLogDetailsRepository.saveAll(any())).thenReturn(measurementLogDetailsList); + doNothing().when(qoSIntraPingMeasurementLogDetailsRepository).flush(); + + try { + + qoSDBService.logMeasurementDetailsToDB(measurementLogSaved, responseList, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("QoSIntraPingMeasurementLog" + NULL_ERROR_MESSAGE)); + verify(qoSIntraPingMeasurementLogDetailsRepository, times(0)).saveAll(any()); + verify(qoSIntraPingMeasurementLogDetailsRepository, times(0)).flush(); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testLogMeasurementDetailsToDBWithNullAroundNowParameter() { + + final ZonedDateTime aroundNow = null;//ZonedDateTime.now(); + final List responseList = getResponseListForTest(); + final QoSIntraPingMeasurementLog measurementLogSaved = new QoSIntraPingMeasurementLog(); + + final List measurementLogDetailsList = List.of(new QoSIntraPingMeasurementLogDetails()); + + when(qoSIntraPingMeasurementLogDetailsRepository.saveAll(any())).thenReturn(measurementLogDetailsList); + doNothing().when(qoSIntraPingMeasurementLogDetailsRepository).flush(); + + try { + + qoSDBService.logMeasurementDetailsToDB(measurementLogSaved, responseList, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("ZonedDateTime" + NULL_ERROR_MESSAGE)); + verify(qoSIntraPingMeasurementLogDetailsRepository, times(0)).saveAll(any()); + verify(qoSIntraPingMeasurementLogDetailsRepository, times(0)).flush(); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test(expected = ArrowheadException.class) + public void testLogMeasurementDetailsToDBSaveAllThrowsException() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final List responseList = getResponseListForTest(); + final QoSIntraPingMeasurementLog measurementLogSaved = new QoSIntraPingMeasurementLog(); + + final ArgumentCaptor valueCapture = ArgumentCaptor.forClass(List.class); + + when(qoSIntraPingMeasurementLogDetailsRepository.saveAll(valueCapture.capture())).thenThrow(HibernateException.class); + doNothing().when(qoSIntraPingMeasurementLogDetailsRepository).flush(); + + try { + + qoSDBService.logMeasurementDetailsToDB(measurementLogSaved, responseList, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG)); + verify(qoSIntraPingMeasurementLogDetailsRepository, times(1)).saveAll(any()); + verify(qoSIntraPingMeasurementLogDetailsRepository, times(0)).flush(); + + final List captured = valueCapture.getValue(); + assertEquals(responseList.size(), captured.size()); + for (final QoSIntraPingMeasurementLogDetails qoSIntraPingMeasurementLogDetails : captured) { + + assertNotNull(qoSIntraPingMeasurementLogDetails.getMeasurementLog()); + assertNotNull(qoSIntraPingMeasurementLogDetails.isSuccessFlag()); + assertNotNull(qoSIntraPingMeasurementLogDetails.getMeasuredAt()); + + } + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Test(expected = ArrowheadException.class) + public void testLogMeasurementDetailsToDBFlushThrowsException() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final List responseList = getResponseListForTest(); + final QoSIntraPingMeasurementLog measurementLogSaved = new QoSIntraPingMeasurementLog(); + + final ArgumentCaptor valueCapture = ArgumentCaptor.forClass(List.class); + final List measurementLogDetailsList = List.of(new QoSIntraPingMeasurementLogDetails()); + + when(qoSIntraPingMeasurementLogDetailsRepository.saveAll(valueCapture.capture())).thenReturn(measurementLogDetailsList); + doThrow(HibernateException.class).when(qoSIntraPingMeasurementLogDetailsRepository).flush(); + + try { + + qoSDBService.logMeasurementDetailsToDB(measurementLogSaved, responseList, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG)); + verify(qoSIntraPingMeasurementLogDetailsRepository, times(1)).saveAll(any()); + verify(qoSIntraPingMeasurementLogDetailsRepository, times(1)).flush(); + + final List captured = valueCapture.getValue(); + assertEquals(responseList.size(), captured.size()); + for (final QoSIntraPingMeasurementLogDetails qoSIntraPingMeasurementLogDetails : captured) { + + assertNotNull(qoSIntraPingMeasurementLogDetails.getMeasurementLog()); + assertNotNull(qoSIntraPingMeasurementLogDetails.isSuccessFlag()); + assertNotNull(qoSIntraPingMeasurementLogDetails.getMeasuredAt()); + + } + + throw ex; + } + + } + + //================================================================================================= + // Tests of updatePingMeasurement + + //------------------------------------------------------------------------------------------------- + @Test + public void testUpdatePingMeasurement() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + calculations.setAvailable(true); + + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + pingMeasurement.setAvailable(true); + + final ArgumentCaptor valueCapture = ArgumentCaptor.forClass(QoSIntraPingMeasurement.class); + + when(qoSIntraMeasurementPingRepository.saveAndFlush(valueCapture.capture())).thenReturn(pingMeasurement); + + qoSDBService.updatePingMeasurement(measurement, calculations, pingMeasurement, aroundNow); + + verify(qoSIntraMeasurementPingRepository, times(1)).saveAndFlush(any()); + + final QoSIntraPingMeasurement captured = valueCapture.getValue(); + assertTrue( calculations.isAvailable() == captured.isAvailable()); + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testUpdatePingMeasurementSaveAndFlushThrowsException() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + calculations.setAvailable(true); + + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + pingMeasurement.setAvailable(true); + + final ArgumentCaptor valueCapture = ArgumentCaptor.forClass(QoSIntraPingMeasurement.class); + + when(qoSIntraMeasurementPingRepository.saveAndFlush(valueCapture.capture())).thenThrow(HibernateException.class); + + try { + + qoSDBService.updatePingMeasurement(measurement, calculations, pingMeasurement, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG)); + verify(qoSIntraMeasurementPingRepository, times(1)).saveAndFlush(any()); + + final QoSIntraPingMeasurement captured = valueCapture.getValue(); + assertTrue( calculations.isAvailable() == captured.isAvailable()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testUpdatePingMeasurementWithNullMeasurementParameter() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final QoSIntraMeasurement measurement = null;//getQoSIntraMeasurementForTest(); + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + when(qoSIntraMeasurementPingRepository.saveAndFlush(any())).thenReturn(pingMeasurement); + + try { + + qoSDBService.updatePingMeasurement(measurement, calculations, pingMeasurement, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("QoSIntraMeasurement" + NULL_ERROR_MESSAGE)); + verify(qoSIntraMeasurementPingRepository, times(0)).saveAndFlush(any()); + + throw ex; + } + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testUpdatePingMeasurementWithNullCalculationsParameter() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + final PingMeasurementCalculationsDTO calculations = null;//getCalculationsForTest(); + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + when(qoSIntraMeasurementPingRepository.saveAndFlush(any())).thenReturn(pingMeasurement); + + try { + + qoSDBService.updatePingMeasurement(measurement, calculations, pingMeasurement, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("PingMeasurementCalculationsDTO" + NULL_ERROR_MESSAGE)); + verify(qoSIntraMeasurementPingRepository, times(0)).saveAndFlush(any()); + + throw ex; + } + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testUpdatePingMeasurementWithNullPingMeasurementParameter() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + final QoSIntraPingMeasurement pingMeasurement = null;//getQosIntraPingMeasurementForTest(); + + when(qoSIntraMeasurementPingRepository.saveAndFlush(any())).thenReturn(pingMeasurement); + + try { + + qoSDBService.updatePingMeasurement(measurement, calculations, pingMeasurement, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("QoSIntraPingMeasurement" + NULL_ERROR_MESSAGE)); + verify(qoSIntraMeasurementPingRepository, times(0)).saveAndFlush(any()); + + throw ex; + } + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testUpdatePingMeasurementWithNullAroundNowParameter() { + + final ZonedDateTime aroundNow = null;//ZonedDateTime.now(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + final PingMeasurementCalculationsDTO calculations = getCalculationsForTest(); + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + when(qoSIntraMeasurementPingRepository.saveAndFlush(any())).thenReturn(pingMeasurement); + + try { + + qoSDBService.updatePingMeasurement(measurement, calculations, pingMeasurement, aroundNow); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("ZonedDateTime" + NULL_ERROR_MESSAGE)); + verify(qoSIntraMeasurementPingRepository, times(0)).saveAndFlush(any()); + + throw ex; + } + } + + //================================================================================================= + // Tests of updateMeasurement + + //------------------------------------------------------------------------------------------------- + @Test + public void testUpdateMeasurement() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final ArgumentCaptor valueCapture = ArgumentCaptor.forClass( QoSIntraMeasurement.class); + + when(qoSIntraMeasurementRepository.saveAndFlush(valueCapture.capture())).thenReturn(measurement); + + qoSDBService.updateMeasurement(aroundNow, measurement); + + verify(qoSIntraMeasurementRepository, times(1)).saveAndFlush(any()); + + final QoSIntraMeasurement captured = valueCapture.getValue(); + assertTrue( aroundNow == captured.getLastMeasurementAt()); + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testUpdateMeasurementSaveAndFlushThrowsException() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final ArgumentCaptor valueCapture = ArgumentCaptor.forClass( QoSIntraMeasurement.class); + + when(qoSIntraMeasurementRepository.saveAndFlush(valueCapture.capture())).thenThrow(HibernateException.class); + + try { + + qoSDBService.updateMeasurement(aroundNow, measurement); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG)); + verify(qoSIntraMeasurementRepository, times(1)).saveAndFlush(any()); + + final QoSIntraMeasurement captured = valueCapture.getValue(); + assertTrue( aroundNow == captured.getLastMeasurementAt()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testUpdateMeasurementWithNullMeasurementParameter() { + + final ZonedDateTime aroundNow = ZonedDateTime.now(); + final QoSIntraMeasurement measurement = null;//getQoSIntraMeasurementForTest(); + + when(qoSIntraMeasurementRepository.saveAndFlush(any())).thenReturn(measurement); + + try { + + qoSDBService.updateMeasurement(aroundNow, measurement); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("QoSIntraMeasurement" + NULL_ERROR_MESSAGE)); + verify(qoSIntraMeasurementRepository, times(0)).saveAndFlush(any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testUpdateMeasurementWithNullAroundNowParameter() { + + final ZonedDateTime aroundNow = null;//ZonedDateTime.now(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + when(qoSIntraMeasurementRepository.saveAndFlush(any())).thenReturn(measurement); + + try { + + qoSDBService.updateMeasurement(aroundNow, measurement); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("ZonedDateTime" + NULL_ERROR_MESSAGE)); + verify(qoSIntraMeasurementRepository, times(0)).saveAndFlush(any()); + + throw ex; + } + + } + + //================================================================================================= + // Tests of getPingMeasurementResponse + + //------------------------------------------------------------------------------------------------- + @Test + public void testGetPingMeasurementResponse() { + + final int page = 0; + final int size = 0; + final Direction direction = Direction.ASC; + final String sortField = CommonConstants.COMMON_FIELD_NAME_ID; + + final Page pageResponse = getPageOfPingMeasurementForTest(); + + when(qoSIntraMeasurementPingRepository.findAll(any(PageRequest.class))).thenReturn(pageResponse); + + qoSDBService.getPingMeasurementResponse(page, size, direction, sortField); + + verify(qoSIntraMeasurementPingRepository, times(1)).findAll(any(PageRequest.class)); + + } + + //================================================================================================= + // Tests of getPingMeasurementPage + + //------------------------------------------------------------------------------------------------- + @Test + public void testGetPingMeasurementPage() { + + final int page = 0; + final int size = 0; + final Direction direction = Direction.ASC; + final String sortField = CommonConstants.COMMON_FIELD_NAME_ID; + + final Page pageResponse = getPageOfPingMeasurementForTest(); + + when(qoSIntraMeasurementPingRepository.findAll(any(PageRequest.class))).thenReturn(pageResponse); + + qoSDBService.getPingMeasurementPage(page, size, direction, sortField); + + verify(qoSIntraMeasurementPingRepository, times(1)).findAll(any(PageRequest.class)); + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testGetPingMeasurementPageWithInvalidSortField() { + + final int page = 0; + final int size = 0; + final Direction direction = Direction.ASC; + final String sortField = "invalid_sort_field"; + + final Page pageResponse = getPageOfPingMeasurementForTest(); + + when(qoSIntraMeasurementPingRepository.findAll(any(PageRequest.class))).thenReturn(pageResponse); + + try { + + qoSDBService.getPingMeasurementPage(page, size, direction, sortField); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains(NOT_AVAILABLE_SORTABLE_FIELD_ERROR_MESSAGE)); + verify(qoSIntraMeasurementPingRepository, times(0)).findAll(any(PageRequest.class)); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testGetPingMeasurementPagefindAllThrowsException() { + + final int page = 0; + final int size = 0; + final Direction direction = Direction.ASC; + final String sortField = CommonConstants.COMMON_FIELD_NAME_ID; + + when(qoSIntraMeasurementPingRepository.findAll(any(PageRequest.class))).thenThrow(HibernateException.class); + + try { + + qoSDBService.getPingMeasurementPage(page, size, direction, sortField); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG)); + verify(qoSIntraMeasurementPingRepository, times(1)).findAll(any(PageRequest.class)); + + throw ex; + } + + } + + //================================================================================================= + // Tests of getPingMeasurementBySystemId + + //------------------------------------------------------------------------------------------------- + @Test + public void testGetPingMeasurementBySystemId() { + + final long id = 1L; + final System system = getSystemForTest(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + when(systemRepository.findById(anyLong())).thenReturn(Optional.of(system)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.of(measurement)); + when(qoSIntraMeasurementPingRepository.findByMeasurement(any())).thenReturn(Optional.of(pingMeasurement)); + + qoSDBService.getPingMeasurementBySystemId(id); + + verify(systemRepository, times(1)).findById(anyLong()); + verify(qoSIntraMeasurementRepository, times(1)).findBySystemAndMeasurementType(any(), any()); + verify(qoSIntraMeasurementPingRepository, times(1)).findByMeasurement(any()); + + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testGetPingMeasurementBySystemIdNoPingMeasurementInDB() { + + final long id = 1L; + final System system = getSystemForTest(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + + when(systemRepository.findById(anyLong())).thenReturn(Optional.of(system)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.of(measurement)); + when(qoSIntraMeasurementPingRepository.findByMeasurement(any())).thenReturn(Optional.ofNullable(null)); + + final QoSIntraPingMeasurement response = qoSDBService.getPingMeasurementBySystemId(id); + + assertNull(response); + + verify(systemRepository, times(1)).findById(anyLong()); + verify(qoSIntraMeasurementRepository, times(1)).findBySystemAndMeasurementType(any(), any()); + verify(qoSIntraMeasurementPingRepository, times(1)).findByMeasurement(any()); + + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testGetPingMeasurementBySystemIdNoMeasurementInDB() { + + final long id = 1L; + final System system = getSystemForTest(); + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + when(systemRepository.findById(anyLong())).thenReturn(Optional.of(system)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.ofNullable(null)); + when(qoSIntraMeasurementPingRepository.findByMeasurement(any())).thenReturn(Optional.of(pingMeasurement)); + + final QoSIntraPingMeasurement response = qoSDBService.getPingMeasurementBySystemId(id); + + assertNull(response); + + verify(systemRepository, times(1)).findById(anyLong()); + verify(qoSIntraMeasurementRepository, times(1)).findBySystemAndMeasurementType(any(), any()); + verify(qoSIntraMeasurementPingRepository, times(0)).findByMeasurement(any()); + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testGetPingMeasurementBySystemIdNoSystemInDB() { + + final long id = 1L; + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + when(systemRepository.findById(anyLong())).thenReturn(Optional.ofNullable(null)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.of(measurement)); + when(qoSIntraMeasurementPingRepository.findByMeasurement(any())).thenReturn(Optional.of(pingMeasurement)); + + try { + + qoSDBService.getPingMeasurementBySystemId(id); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("Requested system" + NOT_IN_DB_ERROR_MESSAGE)); + verify(systemRepository, times(1)).findById(anyLong()); + verify(qoSIntraMeasurementRepository, times(0)).findBySystemAndMeasurementType(any(), any()); + verify(qoSIntraMeasurementPingRepository, times(0)).findByMeasurement(any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testGetPingMeasurementBySystemIdWithInvalidIdParameter() { + + final long id = -1L; + final System system = getSystemForTest(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + when(systemRepository.findById(anyLong())).thenReturn(Optional.of(system)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.of(measurement)); + when(qoSIntraMeasurementPingRepository.findByMeasurement(any())).thenReturn(Optional.of(pingMeasurement)); + + try { + + qoSDBService.getPingMeasurementBySystemId(id); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains("SystemId" + LESS_THAN_ONE_ERROR_MESSAGE)); + verify(systemRepository, times(0)).findById(anyLong()); + verify(qoSIntraMeasurementRepository, times(0)).findBySystemAndMeasurementType(any(), any()); + verify(qoSIntraMeasurementPingRepository, times(0)).findByMeasurement(any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testGetPingMeasurementBySystemIdFindByIdThrowsException() { + + final long id = 1L; + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + when(systemRepository.findById(anyLong())).thenThrow(HibernateException.class); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.of(measurement)); + when(qoSIntraMeasurementPingRepository.findByMeasurement(any())).thenReturn(Optional.of(pingMeasurement)); + + try { + + qoSDBService.getPingMeasurementBySystemId(id); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG)); + verify(systemRepository, times(1)).findById(anyLong()); + verify(qoSIntraMeasurementRepository, times(0)).findBySystemAndMeasurementType(any(), any()); + verify(qoSIntraMeasurementPingRepository, times(0)).findByMeasurement(any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testGetPingMeasurementBySystemIdFindBySystemAndMeasurementTypeThrowsException() { + + final long id = 1L; + final System system = getSystemForTest(); + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + + when(systemRepository.findById(anyLong())).thenReturn(Optional.of(system)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenThrow(HibernateException.class); + when(qoSIntraMeasurementPingRepository.findByMeasurement(any())).thenReturn(Optional.of(pingMeasurement)); + + try { + + qoSDBService.getPingMeasurementBySystemId(id); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG)); + verify(systemRepository, times(1)).findById(anyLong()); + verify(qoSIntraMeasurementRepository, times(1)).findBySystemAndMeasurementType(any(), any()); + verify(qoSIntraMeasurementPingRepository, times(0)).findByMeasurement(any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testGetPingMeasurementBySystemIdFindByMeasurementThrowsException() { + + final long id = 1L; + final System system = getSystemForTest(); + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + when(systemRepository.findById(anyLong())).thenReturn(Optional.of(system)); + when(qoSIntraMeasurementRepository.findBySystemAndMeasurementType(any(), any())).thenReturn(Optional.of(measurement)); + when(qoSIntraMeasurementPingRepository.findByMeasurement(any())).thenThrow(HibernateException.class); + + try { + + qoSDBService.getPingMeasurementBySystemId(id); + + } catch (final Exception ex) { + + assertTrue(ex.getMessage().contains(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG)); + verify(systemRepository, times(1)).findById(anyLong()); + verify(qoSIntraMeasurementRepository, times(1)).findBySystemAndMeasurementType(any(), any()); + verify(qoSIntraMeasurementPingRepository, times(1)).findByMeasurement(any()); + + throw ex; + } + + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + private List getQosIntraPingMeasurementListForTest() { + + final int sizeOfMeasurementList = 3; + final List qoSIntraPingMeasurementList = new ArrayList<>(sizeOfMeasurementList); + + for (int i = 0; i < sizeOfMeasurementList; i++) { + + qoSIntraPingMeasurementList.add(getQosIntraPingMeasurementForTest()); + } + + return qoSIntraPingMeasurementList; + } + + //------------------------------------------------------------------------------------------------- + private QoSIntraPingMeasurement getQosIntraPingMeasurementForTest() { + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurement pingMeasurement = new QoSIntraPingMeasurement(); + + pingMeasurement.setMeasurement(measurement); + pingMeasurement.setAvailable(true); + pingMeasurement.setMaxResponseTime(1); + pingMeasurement.setMinResponseTime(1); + pingMeasurement.setMeanResponseTimeWithoutTimeout(1); + pingMeasurement.setMeanResponseTimeWithTimeout(1); + pingMeasurement.setJitterWithoutTimeout(1); + pingMeasurement.setJitterWithTimeout(1); + pingMeasurement.setLostPerMeasurementPercent(0); + pingMeasurement.setCountStartedAt(ZonedDateTime.now()); + pingMeasurement.setLastAccessAt(ZonedDateTime.now()); + pingMeasurement.setSent(35); + pingMeasurement.setSentAll(35); + pingMeasurement.setReceived(35); + pingMeasurement.setReceivedAll(35); + + return pingMeasurement; + } + + //------------------------------------------------------------------------------------------------- + private QoSIntraMeasurement getQoSIntraMeasurementForTest() { + + final System system = getSystemForTest(); + final QoSIntraMeasurement measurement = new QoSIntraMeasurement( + system, + QoSMeasurementType.PING, + ZonedDateTime.now()); + + return measurement; + } + + //------------------------------------------------------------------------------------------------- + private System getSystemForTest() { + + final System system = new System( + "testSystem", + "address", + 12345, + "authenticationInfo"); + + return system; + } + + //------------------------------------------------------------------------------------------------- + private SystemResponseDTO getSystemResponseDTOForTest() { + + return DTOConverter.convertSystemToSystemResponseDTO(getSystemForTest()); + } + + //------------------------------------------------------------------------------------------------- + private List getResponseListForTest() { + + final int sizeOfList = 3; + final List responseList = new ArrayList<>(3); + + for (int i = 0; i < sizeOfList; i++) { + responseList.add(getIcmpResponseForTest()); + } + + return responseList; + } + + //------------------------------------------------------------------------------------------------- + private IcmpPingResponse getIcmpResponseForTest() { + + final IcmpPingResponse response = new IcmpPingResponse(); + response.setDuration(1); + response.setRtt(1); + response.setSuccessFlag(true); + response.setTimeoutFlag(false); + response.setSize(32); + response.setTtl(64); + + return response; + } + + //------------------------------------------------------------------------------------------------- + private PingMeasurementCalculationsDTO getCalculationsForTest() { + + final PingMeasurementCalculationsDTO calculatiions = new PingMeasurementCalculationsDTO( + true,//available, + 1,//maxResponseTime, + 1,//minResponseTime, + 1,//meanResponseTimeWithTimeout, + 1,//meanResponseTimeWithoutTimeout, + 1,//jitterWithTimeout, + 1,//jitterWithoutTimeout, + 35,//sentInThisPing, + 35,//receivedInThisPing, + 0, + ZonedDateTime.now());//lostPerMeasurementPercent); + + return calculatiions; + } + + //------------------------------------------------------------------------------------------------- + @SuppressWarnings("unused") + private PageImpl getPageOfMeasurementForTest() { + + final List meausrementList = List.of(getQoSIntraMeasurementForTest()); + + return new PageImpl(meausrementList); + } + + //------------------------------------------------------------------------------------------------- + private PageImpl getPageOfPingMeasurementForTest() { + + final List pingMeausrementList = getQosIntraPingMeasurementListForTest(); + + return new PageImpl(pingMeausrementList); + } +} diff --git a/qos-monitor/src/test/java/eu/arrowhead/core/qos/quartz/task/CountRestarterTaskTest.java b/qos-monitor/src/test/java/eu/arrowhead/core/qos/quartz/task/CountRestarterTaskTest.java new file mode 100644 index 000000000..5cd30d082 --- /dev/null +++ b/qos-monitor/src/test/java/eu/arrowhead/core/qos/quartz/task/CountRestarterTaskTest.java @@ -0,0 +1,151 @@ +package eu.arrowhead.core.qos.quartz.task; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.util.List; +import java.util.Map; + +import org.apache.logging.log4j.Logger; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.util.ReflectionTestUtils; + +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.core.qos.database.service.QoSDBService; + +@RunWith(SpringRunner.class) +public class CountRestarterTaskTest { + + //================================================================================================= + // members + @InjectMocks + private final CountRestarterTask counRestarterTask = new CountRestarterTask(); + + @Mock + private QoSDBService qoSDBService; + + @Mock + private Map arrowheadContext; + + @Mock + private JobExecutionContext jobExecutionContext; + + private Logger logger; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Before + public void setUp() throws Exception { + logger = mock(Logger.class); + ReflectionTestUtils.setField(counRestarterTask, "logger", logger); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteServerIsInStandalonMode() { + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(true); + + doNothing().when(qoSDBService).updateCountStartedAt(); + + try { + + counRestarterTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(qoSDBService, times(0)).updateCountStartedAt(); + + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecute() { + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + + doNothing().when(qoSDBService).updateCountStartedAt(); + + try { + + counRestarterTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(qoSDBService, times(1)).updateCountStartedAt(); + + } + + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testExecuteUpdateCountStartedAtThrowsException() { + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + + doThrow(ArrowheadException.class).when(qoSDBService).updateCountStartedAt(); + + try { + + counRestarterTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + + fail(); + + }catch (final ArrowheadException ex) { + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(qoSDBService, times(1)).updateCountStartedAt(); + + throw ex; + } + + } +} diff --git a/qos-monitor/src/test/java/eu/arrowhead/core/qos/quartz/task/PingTaskTest.java b/qos-monitor/src/test/java/eu/arrowhead/core/qos/quartz/task/PingTaskTest.java new file mode 100644 index 000000000..87caf0fe9 --- /dev/null +++ b/qos-monitor/src/test/java/eu/arrowhead/core/qos/quartz/task/PingTaskTest.java @@ -0,0 +1,2414 @@ +package eu.arrowhead.core.qos.quartz.task; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.time.ZonedDateTime; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Optional; + +import org.apache.logging.log4j.Logger; +import org.icmp4j.IcmpPingResponse; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.quartz.JobExecutionContext; +import org.quartz.JobExecutionException; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.util.ReflectionTestUtils; +import org.springframework.web.util.UriComponents; + +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.database.entity.QoSIntraMeasurement; +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurement; +import eu.arrowhead.common.database.entity.QoSIntraPingMeasurementLog; +import eu.arrowhead.common.database.entity.System; +import eu.arrowhead.common.dto.internal.DTOConverter; +import eu.arrowhead.common.dto.internal.ServiceRegistryListResponseDTO; +import eu.arrowhead.common.dto.shared.QoSMeasurementType; +import eu.arrowhead.common.dto.shared.ServiceDefinitionResponseDTO; +import eu.arrowhead.common.dto.shared.ServiceInterfaceResponseDTO; +import eu.arrowhead.common.dto.shared.ServiceRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.ServiceSecurityType; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.common.exception.InvalidParameterException; +import eu.arrowhead.common.http.HttpService; +import eu.arrowhead.core.qos.database.service.QoSDBService; +import eu.arrowhead.core.qos.dto.PingMeasurementCalculationsDTO; +import eu.arrowhead.core.qos.measurement.properties.PingMeasurementProperties; +import eu.arrowhead.core.qos.service.PingService; + +@RunWith(SpringRunner.class) +public class PingTaskTest { + + //================================================================================================= + // members + @InjectMocks + private final PingTask pingTask = new PingTask(); + + @Mock + private PingService pingService; + + @Mock + private QoSDBService qoSDBService; + + @Mock + private HttpService httpService; + + @Mock + private PingMeasurementProperties pingMeasurementProperties; + + @Mock + private Map arrowheadContext; + + @Mock + private JobExecutionContext jobExecutionContext; + + private Logger logger; + + final static int TIME_TO_REPEAT_PING = 3; + + private static final String NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE = " is null or blank."; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Before + public void setUp() throws Exception { + logger = mock(Logger.class); + ReflectionTestUtils.setField(pingTask, "logger", logger); + + when(pingMeasurementProperties.getLogMeasurementsToDB()).thenReturn(true); + when(pingMeasurementProperties.getLogMeasurementsDetailsToDB()).thenReturn(true); + } + + //================================================================================================= + // Tests of execute + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteMeasurementIsInDB() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurement pingMeasurement = getQosIntraPingMeasurementForTest(); + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.of(pingMeasurement)); + //when(qoSDBService.createPingMeasurement(any(), any(), any())).thenReturn(pingMeasurement); + doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, atLeastOnce()).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).updatePingMeasurement(any(), any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteMeasurementIsNotInDB() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, atLeastOnce()).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteWhenMultiplySystemHasSameAddressPingOnlyCalledOnce() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, times(1)).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteWhenMultiplySystemHasDifferentAddressPingCalledMultiplyTimes() { + + final int NUMBER_OF_PROVIDERS = 10; + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOWithDifferentProviderAddressForTest(10); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(NUMBER_OF_PROVIDERS)).getTimeout(); + verify(pingService, times(NUMBER_OF_PROVIDERS)).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteServerIsInStandalonMode() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(true); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(0)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(0)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(0)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(0)).getTimeout(); + verify(pingService, times(0)).getPingResponseList(anyString()); + verify(qoSDBService,times(0)).getOrCreateMeasurement(any()); + + verify(qoSDBService, times(0)).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, times(0)).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteNoSystemsToMeasure() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = new ServiceRegistryListResponseDTO(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(0)).getTimeout(); + verify(pingService, times(0)).getPingResponseList(anyString()); + verify(qoSDBService,times(0)).getOrCreateMeasurement(any()); + + verify(qoSDBService, times(0)).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, times(0)).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testExecuteServiceRegistryUriNotInContext() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(false); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } catch (final ArrowheadException ex) { + + assertTrue(ex.getMessage().contains("QoS Mointor can't find Service Registry Query All URI.")); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(0)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(0)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(0)).getTimeout(); + verify(pingService, times(0)).getPingResponseList(anyString()); + verify(qoSDBService,times(0)).getOrCreateMeasurement(any()); + + verify(qoSDBService, times(0)).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, times(0)).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementDetailsToDB(any(), any(), any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testExecuteServiceRegistryUriContextValueNotUriType() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenThrow(ClassCastException.class); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } catch (final ArrowheadException ex) { + + assertTrue(ex.getMessage().contains("QoS Mointor can't find Service Registry Query All URI.")); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(0)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(0)).getTimeout(); + verify(pingService, times(0)).getPingResponseList(anyString()); + verify(qoSDBService,times(0)).getOrCreateMeasurement(any()); + + verify(qoSDBService, times(0)).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, times(0)).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementDetailsToDB(any(), any(), any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testExecuteSystemToMeasureHasNullAddressParameter() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOWithNullSystemAddressForTest(); + + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } catch (final InvalidParameterException ex) { + + assertTrue(ex.getMessage().contains("System.address" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE)); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(0)).getTimeout(); + verify(pingService, times(0)).getPingResponseList(anyString()); + verify(qoSDBService,times(0)).getOrCreateMeasurement(any()); + + verify(qoSDBService, times(0)).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, times(0)).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementDetailsToDB(any(), any(), any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = InvalidParameterException.class) + public void testExecuteSystemToMeasureHasEmptyAddressParameter() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOWithEmptySystemAddressForTest(); + + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } catch (final InvalidParameterException ex) { + + assertTrue(ex.getMessage().contains("System.address" + NULL_OR_BLANK_PARAMETER_ERROR_MESSAGE)); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(0)).getTimeout(); + verify(pingService, times(0)).getPingResponseList(anyString()); + verify(qoSDBService,times(0)).getOrCreateMeasurement(any()); + + verify(qoSDBService, times(0)).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, times(0)).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementDetailsToDB(any(), any(), any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testExecuteGetPingResponseListThrowsException() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenThrow(ArrowheadException.class); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } catch (final ArrowheadException ex) { + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingService, times(1)).getPingResponseList(anyString()); + verify(pingMeasurementProperties, times(0)).getTimeout(); + verify(qoSDBService,times(0)).getOrCreateMeasurement(any()); + + verify(qoSDBService, times(0)).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, times(0)).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementDetailsToDB(any(), any(), any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testExecuteGetMeasurementThrowsException() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + //final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenThrow(ArrowheadException.class); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } catch (final ArrowheadException ex) { + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingService, times(1)).getPingResponseList(anyString()); + verify(qoSDBService,times(1)).getOrCreateMeasurement(any()); + verify(pingMeasurementProperties, times(0)).getTimeout(); + + verify(qoSDBService, times(0)).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, times(0)).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementDetailsToDB(any(), any(), any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = IllegalArgumentException.class) + public void testExecuteWithEmptyResponseList() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getEmptyResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } catch (final IllegalArgumentException ex) { + + assertTrue(ex.getMessage().contains("Sent in this Ping value must be greater than zero")); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingService, times(1)).getPingResponseList(anyString()); + verify(qoSDBService,times(1)).getOrCreateMeasurement(any()); + verify(pingMeasurementProperties, times(0)).getTimeout(); + + verify(qoSDBService, times(0)).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, times(0)).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementDetailsToDB(any(), any(), any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteCalculationsDTOIsPresent() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor calculationsValueCapture = ArgumentCaptor.forClass(PingMeasurementCalculationsDTO.class); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + when(pingMeasurementProperties.getAvailableFromSuccessPercent()).thenReturn(1); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), calculationsValueCapture.capture(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + final PingMeasurementCalculationsDTO calculations = calculationsValueCapture.getValue(); + assertNotNull(calculations); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, atLeastOnce()).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteAvailableCalculation() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor calculationsValueCapture = ArgumentCaptor.forClass(PingMeasurementCalculationsDTO.class); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + when(pingMeasurementProperties.getAvailableFromSuccessPercent()).thenReturn(32); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), calculationsValueCapture.capture(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + final PingMeasurementCalculationsDTO calculations = calculationsValueCapture.getValue(); + assertNotNull(calculations); + assertTrue(calculations.isAvailable()); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, atLeastOnce()).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteAvailableCalculationWith100PercentNotOK() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = get100LongResponseListWithIncementingResponseTimeAnd10PercentLossForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor calculationsValueCapture = ArgumentCaptor.forClass(PingMeasurementCalculationsDTO.class); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + when(pingMeasurementProperties.getAvailableFromSuccessPercent()).thenReturn(100); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), calculationsValueCapture.capture(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + final PingMeasurementCalculationsDTO calculations = calculationsValueCapture.getValue(); + assertNotNull(calculations); + assertTrue(!calculations.isAvailable()); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, atLeastOnce()).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteAvailableCalculationWith100PercentOK() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = get100LongResponseListWithIncementingResponseTimeAnd0PercentLossForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor calculationsValueCapture = ArgumentCaptor.forClass(PingMeasurementCalculationsDTO.class); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + when(pingMeasurementProperties.getAvailableFromSuccessPercent()).thenReturn(100); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), calculationsValueCapture.capture(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + final PingMeasurementCalculationsDTO calculations = calculationsValueCapture.getValue(); + assertNotNull(calculations); + assertTrue(calculations.isAvailable()); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, atLeastOnce()).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteAvailableCalculationWith1PercentOK() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = get100LongResponseListWith99PercentLossForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor calculationsValueCapture = ArgumentCaptor.forClass(PingMeasurementCalculationsDTO.class); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + when(pingMeasurementProperties.getAvailableFromSuccessPercent()).thenReturn(1); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), calculationsValueCapture.capture(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + final PingMeasurementCalculationsDTO calculations = calculationsValueCapture.getValue(); + assertNotNull(calculations); + assertTrue(calculations.isAvailable()); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, atLeastOnce()).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteAvailableCalculationWith1PercentNotOK() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = get100LongResponseListWith99Point9PercentLossForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor calculationsValueCapture = ArgumentCaptor.forClass(PingMeasurementCalculationsDTO.class); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + when(pingMeasurementProperties.getAvailableFromSuccessPercent()).thenReturn(1); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), calculationsValueCapture.capture(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + final PingMeasurementCalculationsDTO calculations = calculationsValueCapture.getValue(); + assertNotNull(calculations); + assertTrue(calculations.isAvailable()); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, atLeastOnce()).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteAvailableCalculationWithNotAvailable() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor calculationsValueCapture = ArgumentCaptor.forClass(PingMeasurementCalculationsDTO.class); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + when(pingMeasurementProperties.getAvailableFromSuccessPercent()).thenReturn(34); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), calculationsValueCapture.capture(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + final PingMeasurementCalculationsDTO calculations = calculationsValueCapture.getValue(); + assertNotNull(calculations); + assertTrue(!calculations.isAvailable()); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, atLeastOnce()).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteMinResponseTime() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = get100LongResponseListWithIncementingResponseTimeAnd10PercentLossForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor calculationsValueCapture = ArgumentCaptor.forClass(PingMeasurementCalculationsDTO.class); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), calculationsValueCapture.capture(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + final PingMeasurementCalculationsDTO calculations = calculationsValueCapture.getValue(); + assertNotNull(calculations); + assertTrue(1 == calculations.getMinResponseTime()); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, atLeastOnce()).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteMaxResponseTime() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = get100LongResponseListWithIncementingResponseTimeAnd10PercentLossForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor calculationsValueCapture = ArgumentCaptor.forClass(PingMeasurementCalculationsDTO.class); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), calculationsValueCapture.capture(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + final PingMeasurementCalculationsDTO calculations = calculationsValueCapture.getValue(); + assertNotNull(calculations); + assertTrue(90 == calculations.getMaxResponseTime()); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, atLeastOnce()).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteMeanResponseTimeCalculations() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = get100LongResponseListWithIncementingResponseTimeAnd10PercentLossForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor calculationsValueCapture = ArgumentCaptor.forClass(PingMeasurementCalculationsDTO.class); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), calculationsValueCapture.capture(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + final PingMeasurementCalculationsDTO calculations = calculationsValueCapture.getValue(); + assertNotNull(calculations); + assertTrue(46 == calculations.getMeanResponseTimeWithoutTimeout()); + assertTrue(541 == calculations.getMeanResponseTimeWithTimeout()); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, atLeastOnce()).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testExecuteJitterCalculations() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = get100LongResponseListWithIncementingResponseTimeAnd10PercentLossForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor calculationsValueCapture = ArgumentCaptor.forClass(PingMeasurementCalculationsDTO.class); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), calculationsValueCapture.capture(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } + + final PingMeasurementCalculationsDTO calculations = calculationsValueCapture.getValue(); + assertNotNull(calculations); + assertTrue(1567 == calculations.getJitterWithTimeout()); + assertTrue(25 == calculations.getJitterWithoutTimeout()); + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingMeasurementProperties, times(1)).getTimeout(); + verify(pingService, atLeastOnce()).getPingResponseList(anyString()); + verify(qoSDBService, atLeastOnce()).getOrCreateMeasurement(any()); + + verify(qoSDBService, atLeastOnce()).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, atLeastOnce()).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, atLeastOnce()).logMeasurementDetailsToDB(any(), any(), any()); + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testExecuteGetPingMeasurementByMeasurementThrowsException() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenThrow(ArrowheadException.class); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } catch (final ArrowheadException ex) { + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingService, times(1)).getPingResponseList(anyString()); + verify(qoSDBService,times(1)).getOrCreateMeasurement(any()); + verify(pingMeasurementProperties, atLeastOnce()).getTimeout(); + + verify(qoSDBService, times(1)).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, times(0)).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementDetailsToDB(any(), any(), any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testExecuteCreatePingMeasurementThrowsException() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doThrow(ArrowheadException.class).when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } catch (final ArrowheadException ex) { + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingService, times(1)).getPingResponseList(anyString()); + verify(qoSDBService,times(1)).getOrCreateMeasurement(any()); + verify(pingMeasurementProperties, atLeastOnce()).getTimeout(); + + verify(qoSDBService, times(1)).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, times(1)).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementDetailsToDB(any(), any(), any()); + + throw ex; + } + + } + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testExecuteLogMeasurementToDBThrowsException() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenThrow(ArrowheadException.class); + doNothing().when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } catch (final ArrowheadException ex) { + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingService, times(1)).getPingResponseList(anyString()); + verify(qoSDBService,times(1)).getOrCreateMeasurement(any()); + verify(pingMeasurementProperties, atLeastOnce()).getTimeout(); + + verify(qoSDBService, times(1)).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, times(1)).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, times(1)).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, times(0)).logMeasurementDetailsToDB(any(), any(), any()); + + throw ex; + } + + } + + + //------------------------------------------------------------------------------------------------- + @Test(expected = ArrowheadException.class) + public void testExecuteLogMeasurementDetailsToDBThrowsException() { + + final UriComponents uri = Utilities.createURI("HTTPS", "localhost", 12345, "serviceregistry"); + + final ServiceRegistryListResponseDTO serviceRegistryResponse = getServiceRegistryListResponseDTOForTest(); + + final ResponseEntity httpResponse = new ResponseEntity(serviceRegistryResponse, HttpStatus.OK); + + final List responseList = getResponseListForTest(); + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurementLog measurementLog = getOrCreateMeasurementLogForTest(); + + final ArgumentCaptor debugValueCapture = ArgumentCaptor.forClass(String.class); + doNothing().when(logger).debug( debugValueCapture.capture()); + + when(arrowheadContext.containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE)).thenReturn(false); + when(arrowheadContext.containsKey(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(true); + when(arrowheadContext.get(CoreCommonConstants.SR_QUERY_ALL)).thenReturn(uri); + + when(httpService.sendRequest(uri, HttpMethod.GET, ServiceRegistryListResponseDTO.class)).thenReturn(httpResponse); + + when(pingMeasurementProperties.getTimeout()).thenReturn(5000); + + when(pingService.getPingResponseList(anyString())).thenReturn(responseList); + + when(qoSDBService.getOrCreateMeasurement(any(SystemResponseDTO.class))).thenReturn(measurement); + + //in handleMeasurement + when(qoSDBService.getPingMeasurementByMeasurement(any(QoSIntraMeasurement.class))).thenReturn(Optional.ofNullable(null)); + doNothing().when(qoSDBService).createPingMeasurement(any(), any(), any()); + //doNothing().when(qoSDBService).updatePingMeasurement(any(), any(), any(), any()); + when(qoSDBService.logMeasurementToDB(any(), any(), any())).thenReturn(measurementLog); + doThrow(ArrowheadException.class).when(qoSDBService).logMeasurementDetailsToDB(any(), any(), any()); + + try { + + pingTask.execute(jobExecutionContext); + + } catch (final JobExecutionException ex) { + fail(); + } catch (final ArrowheadException ex) { + + verify(logger, atLeastOnce()).debug(any(String.class)); + final List debugMessages = debugValueCapture.getAllValues(); + assertNotNull(debugMessages); + + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SERVER_STANDALONE_MODE); + verify(arrowheadContext, times(1)).containsKey(CoreCommonConstants.SR_QUERY_ALL); + verify(arrowheadContext, times(1)).get(CoreCommonConstants.SR_QUERY_ALL); + verify(httpService, times(1)).sendRequest(any(), any(), any()); + verify(pingService, times(1)).getPingResponseList(anyString()); + verify(qoSDBService,times(1)).getOrCreateMeasurement(any()); + verify(pingMeasurementProperties, atLeastOnce()).getTimeout(); + + verify(qoSDBService, times(1)).getPingMeasurementByMeasurement(any()); + verify(qoSDBService, times(1)).createPingMeasurement(any(), any(), any()); + verify(qoSDBService, times(1)).logMeasurementToDB(any(), any(), any()); + verify(qoSDBService, times(1)).logMeasurementDetailsToDB(any(), any(), any()); + + throw ex; + } + + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + public ServiceRegistryListResponseDTO getServiceRegistryListResponseDTOForTest() { + + final int sizeOfResponse = 3; + final ServiceRegistryListResponseDTO serviceRegistryListResponseDTO = new ServiceRegistryListResponseDTO(); + final List responseList = new ArrayList<>(sizeOfResponse); + + for (int i = 0; i < sizeOfResponse; i++) { + responseList.add(getServiceRegistryResponseDTOForTest()); + } + + serviceRegistryListResponseDTO.setCount(sizeOfResponse); + serviceRegistryListResponseDTO.setData(responseList); + + return serviceRegistryListResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + public ServiceRegistryListResponseDTO getServiceRegistryListResponseDTOWithDifferentProviderAddressForTest(final int numberOfProviders) { + + final int sizeOfResponse = numberOfProviders; + final ServiceRegistryListResponseDTO serviceRegistryListResponseDTO = new ServiceRegistryListResponseDTO(); + final List responseList = new ArrayList<>(sizeOfResponse); + + for (int i = 0; i < sizeOfResponse; i++) { + final ServiceRegistryResponseDTO response = getServiceRegistryResponseDTOForTest(); + response.getProvider().setAddress("address" + i); + + responseList.add(response); + } + + serviceRegistryListResponseDTO.setCount(sizeOfResponse); + serviceRegistryListResponseDTO.setData(responseList); + + return serviceRegistryListResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + public ServiceRegistryListResponseDTO getServiceRegistryListResponseDTOWithNullSystemAddressForTest() { + + final int sizeOfResponse = 3; + final ServiceRegistryListResponseDTO serviceRegistryListResponseDTO = new ServiceRegistryListResponseDTO(); + final List responseList = new ArrayList<>(sizeOfResponse); + + for (int i = 0; i < sizeOfResponse; i++) { + responseList.add(getServiceRegistryResponseDTOWithNullSystemAddressForTest()); + } + + serviceRegistryListResponseDTO.setCount(sizeOfResponse); + serviceRegistryListResponseDTO.setData(responseList); + + return serviceRegistryListResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + public ServiceRegistryListResponseDTO getServiceRegistryListResponseDTOWithEmptySystemAddressForTest() { + + final int sizeOfResponse = 3; + final ServiceRegistryListResponseDTO serviceRegistryListResponseDTO = new ServiceRegistryListResponseDTO(); + final List responseList = new ArrayList<>(sizeOfResponse); + + for (int i = 0; i < sizeOfResponse; i++) { + responseList.add(getServiceRegistryResponseDTOWithEmptySystemAddressForTest()); + } + + serviceRegistryListResponseDTO.setCount(sizeOfResponse); + serviceRegistryListResponseDTO.setData(responseList); + + return serviceRegistryListResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + public ServiceRegistryResponseDTO getServiceRegistryResponseDTOForTest() { + + final ServiceRegistryResponseDTO serviceRegistryResponseDTO = new ServiceRegistryResponseDTO(); + + serviceRegistryResponseDTO.setId(1L); + serviceRegistryResponseDTO.setServiceDefinition(getServiceDefinitionResponseDTOForTest()); + serviceRegistryResponseDTO.setProvider(getSystemResponseDTOForTest()); + serviceRegistryResponseDTO.setServiceUri("serviceUri"); + serviceRegistryResponseDTO.setEndOfValidity(null); + serviceRegistryResponseDTO.setSecure(ServiceSecurityType.CERTIFICATE); + serviceRegistryResponseDTO.setMetadata(null); + serviceRegistryResponseDTO.setVersion(1); + serviceRegistryResponseDTO.setInterfaces(List.of(getServiceInterfaceResponseDTOForTest())); + serviceRegistryResponseDTO.setCreatedAt(Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now())); + serviceRegistryResponseDTO.setUpdatedAt(Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now())); + + return serviceRegistryResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + public ServiceRegistryResponseDTO getServiceRegistryResponseDTOWithNullSystemAddressForTest() { + + final ServiceRegistryResponseDTO serviceRegistryResponseDTO = new ServiceRegistryResponseDTO(); + + serviceRegistryResponseDTO.setId(1L); + serviceRegistryResponseDTO.setServiceDefinition(getServiceDefinitionResponseDTOForTest()); + serviceRegistryResponseDTO.setProvider(getSystemResponseDTOWithNullAddressForTest()); + serviceRegistryResponseDTO.setServiceUri("serviceUri"); + serviceRegistryResponseDTO.setEndOfValidity(null); + serviceRegistryResponseDTO.setSecure(ServiceSecurityType.CERTIFICATE); + serviceRegistryResponseDTO.setMetadata(null); + serviceRegistryResponseDTO.setVersion(1); + serviceRegistryResponseDTO.setInterfaces(List.of(getServiceInterfaceResponseDTOForTest())); + serviceRegistryResponseDTO.setCreatedAt(Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now())); + serviceRegistryResponseDTO.setUpdatedAt(Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now())); + + return serviceRegistryResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + public ServiceRegistryResponseDTO getServiceRegistryResponseDTOWithEmptySystemAddressForTest() { + + final ServiceRegistryResponseDTO serviceRegistryResponseDTO = new ServiceRegistryResponseDTO(); + + serviceRegistryResponseDTO.setId(1L); + serviceRegistryResponseDTO.setServiceDefinition(getServiceDefinitionResponseDTOForTest()); + serviceRegistryResponseDTO.setProvider(getSystemResponseDTOWithEmptyAddressForTest()); + serviceRegistryResponseDTO.setServiceUri("serviceUri"); + serviceRegistryResponseDTO.setEndOfValidity(null); + serviceRegistryResponseDTO.setSecure(ServiceSecurityType.CERTIFICATE); + serviceRegistryResponseDTO.setMetadata(null); + serviceRegistryResponseDTO.setVersion(1); + serviceRegistryResponseDTO.setInterfaces(List.of(getServiceInterfaceResponseDTOForTest())); + serviceRegistryResponseDTO.setCreatedAt(Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now())); + serviceRegistryResponseDTO.setUpdatedAt(Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now())); + + return serviceRegistryResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + public ServiceDefinitionResponseDTO getServiceDefinitionResponseDTOForTest() { + + final ServiceDefinitionResponseDTO serviceDefinitionResponseDTO = new ServiceDefinitionResponseDTO(); + + serviceDefinitionResponseDTO.setId(1L); + serviceDefinitionResponseDTO.setServiceDefinition("serviceDefinition"); + serviceDefinitionResponseDTO.setCreatedAt(Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now())); + serviceDefinitionResponseDTO.setUpdatedAt(Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now())); + + return serviceDefinitionResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + private System getSystemForTest() { + + final System system = new System( + "testSystem", + "address", + 12345, + "authenticationInfo"); + + return system; + } + + //------------------------------------------------------------------------------------------------- + private System getSystemWithNullAddressForTest() { + + final System system = new System( + "testSystem", + null, + 12345, + "authenticationInfo"); + + return system; + } + + //------------------------------------------------------------------------------------------------- + private SystemResponseDTO getSystemResponseDTOWithNullAddressForTest() { + + final SystemResponseDTO systemResponseDTO = DTOConverter.convertSystemToSystemResponseDTO(getSystemWithNullAddressForTest()); + + return systemResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + private System getSystemWithEmptyAddressForTest() { + + final System system = new System( + "testSystem", + " ", + 12345, + "authenticationInfo"); + + return system; + } + + //------------------------------------------------------------------------------------------------- + private SystemResponseDTO getSystemResponseDTOWithEmptyAddressForTest() { + + final SystemResponseDTO systemResponseDTO = DTOConverter.convertSystemToSystemResponseDTO(getSystemWithEmptyAddressForTest()); + + return systemResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + private SystemResponseDTO getSystemResponseDTOForTest() { + + final SystemResponseDTO systemResponseDTO = DTOConverter.convertSystemToSystemResponseDTO(getSystemForTest()); + + return systemResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + private ServiceInterfaceResponseDTO getServiceInterfaceResponseDTOForTest() { + + final ServiceInterfaceResponseDTO serviceInterfaceResponseDTO = new ServiceInterfaceResponseDTO(); + serviceInterfaceResponseDTO.setId(1L); + serviceInterfaceResponseDTO.setInterfaceName("interfaceName"); + serviceInterfaceResponseDTO.setCreatedAt(Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now())); + serviceInterfaceResponseDTO.setUpdatedAt(Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now())); + + return serviceInterfaceResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + private List getResponseListForTest() { + + final List responseList = new ArrayList<>(); + for (int i = 0; i < TIME_TO_REPEAT_PING; i++) { + + if (i%2 == 0) { + final IcmpPingResponse pingResponse = getIcmpPingResponse(); + pingResponse.setSuccessFlag(false); + pingResponse.setTimeoutFlag(true); + pingResponse.setRtt(0); + pingResponse.setDuration(0); + + responseList.add(pingResponse); + }else { + responseList.add(getIcmpPingResponse()); + } + } + + return responseList; + } + + //------------------------------------------------------------------------------------------------- + private List get100LongResponseListWithIncementingResponseTimeAnd10PercentLossForTest() { + + final List responseList = new ArrayList<>(); + for (int i = 1; i < 91; i++) { + + final IcmpPingResponse pingResponse = getIcmpPingResponse(); + pingResponse.setSuccessFlag(true); + pingResponse.setTimeoutFlag(false); + pingResponse.setRtt(i); + pingResponse.setDuration(i); + + responseList.add(pingResponse); + } + + for (int i = 0; i < 10; i++) { + + final IcmpPingResponse pingResponse = getIcmpPingResponse(); + pingResponse.setSuccessFlag(false); + pingResponse.setTimeoutFlag(true); + + responseList.add(pingResponse); + } + + return responseList; + } + + //------------------------------------------------------------------------------------------------- + private List get100LongResponseListWith99PercentLossForTest() { + + final List responseList = new ArrayList<>(); + + final IcmpPingResponse pingResponse = getIcmpPingResponse(); + pingResponse.setSuccessFlag(true); + pingResponse.setTimeoutFlag(false); + pingResponse.setRtt(1); + pingResponse.setDuration(1); + + responseList.add(pingResponse); + + for (int i = 0; i < 100; i++) { + + final IcmpPingResponse pingResponseInLoop= getIcmpPingResponse(); + pingResponse.setSuccessFlag(false); + pingResponse.setTimeoutFlag(true); + + responseList.add(pingResponseInLoop); + } + + return responseList; + } + + //------------------------------------------------------------------------------------------------- + private List get100LongResponseListWith99Point9PercentLossForTest() { + + final List responseList = new ArrayList<>(); + + final IcmpPingResponse pingResponse = getIcmpPingResponse(); + pingResponse.setSuccessFlag(true); + pingResponse.setTimeoutFlag(false); + pingResponse.setRtt(1); + pingResponse.setDuration(1); + + responseList.add(pingResponse); + + for (int i = 0; i < 200; i++) { + + final IcmpPingResponse pingResponseInLoop= getIcmpPingResponse(); + pingResponse.setSuccessFlag(false); + pingResponse.setTimeoutFlag(true); + + responseList.add(pingResponseInLoop); + } + + return responseList; + } + //------------------------------------------------------------------------------------------------- + private List get100LongResponseListWithIncementingResponseTimeAnd0PercentLossForTest() { + + final List responseList = new ArrayList<>(); + for (int i = 1; i < 101; i++) { + + final IcmpPingResponse pingResponse = getIcmpPingResponse(); + pingResponse.setSuccessFlag(true); + pingResponse.setTimeoutFlag(false); + pingResponse.setRtt(i); + pingResponse.setDuration(i); + + responseList.add(pingResponse); + } + + return responseList; + } + //------------------------------------------------------------------------------------------------- + private List getEmptyResponseListForTest() { + + final List responseList = List.of(); + + return responseList; + } + + //------------------------------------------------------------------------------------------------- + private IcmpPingResponse getIcmpPingResponse() { + + final IcmpPingResponse pingResponse = new IcmpPingResponse(); + pingResponse.setSuccessFlag(true); + pingResponse.setTimeoutFlag(false); + pingResponse.setRtt(1); + pingResponse.setDuration(1L); + pingResponse.setTtl(64); + pingResponse.setSize(32); + pingResponse.setHost("localhost"); + + return pingResponse; + } + + //------------------------------------------------------------------------------------------------- + private QoSIntraMeasurement getQoSIntraMeasurementForTest() { + + final System system = getSystemForTest(); + final QoSIntraMeasurement measurement = new QoSIntraMeasurement( + system, + QoSMeasurementType.PING, + ZonedDateTime.now()); + + return measurement; + } + + //------------------------------------------------------------------------------------------------- + private QoSIntraPingMeasurement getQosIntraPingMeasurementForTest() { + + final QoSIntraMeasurement measurement = getQoSIntraMeasurementForTest(); + + final QoSIntraPingMeasurement pingMeasurement = new QoSIntraPingMeasurement(); + + pingMeasurement.setMeasurement(measurement); + pingMeasurement.setAvailable(true); + pingMeasurement.setMaxResponseTime(1); + pingMeasurement.setMinResponseTime(1); + pingMeasurement.setMeanResponseTimeWithoutTimeout(1); + pingMeasurement.setMeanResponseTimeWithTimeout(1); + pingMeasurement.setJitterWithoutTimeout(1); + pingMeasurement.setJitterWithTimeout(1); + pingMeasurement.setLostPerMeasurementPercent(0); + pingMeasurement.setCountStartedAt(ZonedDateTime.now()); + pingMeasurement.setLastAccessAt(ZonedDateTime.now()); + pingMeasurement.setSent(35); + pingMeasurement.setSentAll(35); + pingMeasurement.setReceived(35); + pingMeasurement.setReceivedAll(35); + + return pingMeasurement; + } + + //------------------------------------------------------------------------------------------------- + private QoSIntraPingMeasurementLog getOrCreateMeasurementLogForTest() { + + final QoSIntraPingMeasurementLog measurementLog = new QoSIntraPingMeasurementLog(); + measurementLog.setAvailable(true); + + return measurementLog; + } + +} diff --git a/qos-monitor/src/test/java/eu/arrowhead/core/qos/security/QosMonitorAccessControlFilterTest.java b/qos-monitor/src/test/java/eu/arrowhead/core/qos/security/QosMonitorAccessControlFilterTest.java new file mode 100644 index 000000000..cb69aae17 --- /dev/null +++ b/qos-monitor/src/test/java/eu/arrowhead/core/qos/security/QosMonitorAccessControlFilterTest.java @@ -0,0 +1,143 @@ +package eu.arrowhead.core.qos.security; + +import static org.junit.Assume.assumeTrue; +import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.x509; +import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.context.ApplicationContext; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; + +/** +* IMPORTANT: These tests may fail if the certificates are changed in the src/main/resources folder. +* +*/ +@RunWith(SpringRunner.class) +@SpringBootTest +@ContextConfiguration +@AutoConfigureMockMvc +public class QosMonitorAccessControlFilterTest { + + //================================================================================================= + // members + + private static final String QOS_MONITOR_ECHO_URI = CommonConstants.QOS_MONITOR_URI + CommonConstants.ECHO_URI; + + private static final String PING_MEASUREMENTS = "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/ping/measurements"; + private static final String QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI = CommonConstants.QOS_MONITOR_URI + CoreCommonConstants.MGMT_URI + PING_MEASUREMENTS; + + @Autowired + private ApplicationContext appContext; + + @Value(CommonConstants.$SERVER_SSL_ENABLED_WD) + private boolean secure; + + @Autowired + private WebApplicationContext wac; + + private MockMvc mockMvc; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Before + public void setup() { + assumeTrue(secure); + + final QosMonitorAccessControlFilter qoSFilter = appContext.getBean(QosMonitorAccessControlFilter.class); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac) + .apply(springSecurity()) + .addFilters(qoSFilter) + .build(); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testEchoCertificateSameCloud() throws Exception { + this.mockMvc.perform(get(QOS_MONITOR_ECHO_URI) + .secure(true) + .with(x509("certificates/provider.pem")) + .accept(MediaType.TEXT_PLAIN)) + .andExpect(status().isOk()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testEchoCertificateOtherCloud() throws Exception { + this.mockMvc.perform(get(QOS_MONITOR_ECHO_URI) + .secure(true) + .with(x509("certificates/other_cloud.pem")) + .accept(MediaType.TEXT_PLAIN)) + .andExpect(status().isUnauthorized()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testMgmtGetPingMeasurementsCertificateSysop() throws Exception { + this.mockMvc.perform(get(QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI) + .secure(true) + .with(x509("certificates/valid.pem")) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testMgmtGetPingMeasurementsCertificateNotSysop() throws Exception { + this.mockMvc.perform(get(QOS_MONITOR_PING_MEASUREMENTS_MGMT_URI) + .secure(true) + .with(x509("certificates/provider.pem")) + .accept(MediaType.TEXT_PLAIN)) + .andExpect(status().isUnauthorized()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testOPGetPingMeasurementsCertificateSysop() throws Exception { + + this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT) + .secure(true) + .with(x509("certificates/valid.pem")) + .accept(MediaType.TEXT_PLAIN)) + .andExpect(status().isUnauthorized()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testOPGetPingMeasurementsCertificateNotSysop() throws Exception { + + this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT) + .secure(true) + .with(x509("certificates/provider.pem")) + .accept(MediaType.TEXT_PLAIN)) + .andExpect(status().isUnauthorized()); + } + + //------------------------------------------------------------------------------------------------- + @Test + public void testOPGetPingMeasurementsCertificateOrchestrator() throws Exception { + + this.mockMvc.perform(get(CommonConstants.QOS_MONITOR_URI + CommonConstants.OP_QOS_MONITOR_PING_MEASUREMENT + "/1") + .secure(true) + .with(x509("certificates/orchestrator.pem")) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()); + } +} diff --git a/qos-monitor/src/test/resources/.placeholder b/qos-monitor/src/test/resources/.placeholder new file mode 100644 index 000000000..e69de29bb diff --git a/qos-monitor/src/test/resources/certificates/notvalid.pem b/qos-monitor/src/test/resources/certificates/notvalid.pem new file mode 100644 index 000000000..a70c46837 --- /dev/null +++ b/qos-monitor/src/test/resources/certificates/notvalid.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDMzCCAhugAwIBAgIEXNlw3zANBgkqhkiG9w0BAQsFADAXMRUwEwYDVQQDDAxh +cnJvd2hlYWQuZXUwHhcNMTkwNTEzMTMyNzU5WhcNMjkwNTEzMTMyNzU5WjAoMSYw +JAYDVQQDDB10ZXN0Y2xvdWQxLmFpdGlhLmFycm93aGVhZC5ldTCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBANTIWrd0mcvxx6LfPG6RvviN5VY1n9uphoYm +CoRA47scc0duc6kIWsIydEsKD9xEd2WdClbQXVazLSF+OWGocxBuyPaAjgu4DdVY +pJLgAaeSzbcjqS+A6bB3B6i8A9RxCWwtDJ5EJsUuIOa9yqcfkmdXVOHpNlwycPeH +FEOIUdUcd+RAL0Fw4h39a3HmTDf4nb2Px/3CWvZk89woxDXURJfyDl2fJyB3kLbp +4HWBht9YZNw2ZuIT1fO5rfm2XGEaPiUseI4KEwDyhW36HWOxv3oP9lMWjCaeWFg1 +A4q6sbjm+fsEsZJavgPWANINCTxKyy/IclwmxKimS6aDBHHyW6UCAwEAAaN2MHQw +DwYDVR0TBAgwBgEB/wIBAjBCBgNVHSMEOzA5gBSaipkeMUwesuYttprtxx4xyt07 +/qEbpBkwFzEVMBMGA1UEAwwMYXJyb3doZWFkLmV1ggRc1T6tMB0GA1UdDgQWBBT0 +jA9ICBgevPSr86oEvVJ8uDamJTANBgkqhkiG9w0BAQsFAAOCAQEAiy1OVJulFL2V +HOYlERD2MJCgIaVKoN6GGxGXQ7mBAjGE+am+dKvbGZ9l5ADRKxKgd1T0hklfTZJU +j7CHBp1JJ7cj7OkFyountQcdTJ3WVLDMxfRRictRwuEUaKMry4nmcU2WpDTJ+DSV +H6qW3VlXxJKnGe1M3u14wUx5k0iXr4S2oYkq/WZ9TUkLWKmzVPDlU3x6iSsyZj/5 +1a5o2qNceezzpGhcvoiHwQ0MFm9OLDYrh61Zb4M7jhn2AocHV4f3Y0P0IfdLlXq5 +MIgOK1ds2BekemekJ3VnW/TDj8fY6sxWl8aWFYJ1RhmVWTODiN9xu9XPyzAO5ryk +zG4AOQa5rQ== +-----END CERTIFICATE----- diff --git a/qos-monitor/src/test/resources/certificates/orchestrator.pem b/qos-monitor/src/test/resources/certificates/orchestrator.pem new file mode 100644 index 000000000..4792c5c6a --- /dev/null +++ b/qos-monitor/src/test/resources/certificates/orchestrator.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDNjCCAh6gAwIBAgIEXOu9NTANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB10 +ZXN0Y2xvdWQyLmFpdGlhLmFycm93aGVhZC5ldTAeFw0xOTA1MjcxMDM0MjlaFw0y +OTA1MjcxMDM0MjlaMDUxMzAxBgNVBAMMKm9yY2hlc3RyYXRvci50ZXN0Y2xvdWQy +LmFpdGlhLmFycm93aGVhZC5ldTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC +ggEBAK/alOuozKOwjr7UoXbtTTo1Lsf8y+3C3fEmUngB9I7k1rYq/1DvmMFf1Xdu +JXV98BL8AHIutsKpShSmNKtP8Kr8cAZyNby68J6/O78HUtJXoHgl0Eitws67m2No +NJh/ufXrPChDFThd44yZ7fouZgoiBThXN4DNixHrV/ANgdO+tv94H0sqFrFBzbis +xB55T9Kiy5arFuUq5QYpGEQqHiJUSavqk6T5DlYwasmet+tTksdYLn+cTpYcdmwW +8KVHU0whAECGbwoyW2o3GG/qpxopXJuGK3a9bT6jCgku1vQcAyYqbm0TWMJJnXzw +Q00IZx5mrfuBODbp1oruVDph1r8CAwEAAaNbMFkwDwYDVR0RBAgwBocEfwAAATAn +BgNVHSMEIDAegBQEME0II5M93mY9Flqn0cleI6aXT6EAggRc2WIZMB0GA1UdDgQW +BBRrbKDs28ZltCmzZyblUqx8itHUOzANBgkqhkiG9w0BAQsFAAOCAQEAVnFKZ8aw +TcFJEWFTrvnmbvgC7aICelOzSMcbRmyrLqAT0gpVB4sQqFqFNPmIhJo/ylHih+E0 +YZNqAUmso5ITX5xKcHb1j2LdBg29KZbXk0o5beK3eaDULKQpiyqyy4fT8MEEJ7Hu +AjCusxr5dQ7tiKZ9fhnXDa4XItKBp22j4B5LXppeuOUyASJ/B13erEPG9Dl7OVp1 +MXI0uHq4nj+mAqYpEZuY9vpW8gWuidfB3q9MDDwEtp8lWNnzGhhcQ2FitzmsepJz +qX4hnTYMr5zF1IJ5g3AuPxneAz0LL02jdh4HXYBXqm4SQEAb7y0ePCF9Zz+YfHf3 +JDHA7BSnLfNj/g== +-----END CERTIFICATE----- diff --git a/qos-monitor/src/test/resources/certificates/other_cloud.pem b/qos-monitor/src/test/resources/certificates/other_cloud.pem new file mode 100644 index 000000000..df59b780f --- /dev/null +++ b/qos-monitor/src/test/resources/certificates/other_cloud.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDJjCCAg6gAwIBAgIEXNlxczANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB10 +ZXN0Y2xvdWQxLmFpdGlhLmFycm93aGVhZC5ldTAeFw0xOTA1MTMxMzMwMjdaFw0y +OTA1MTMxMzMwMjdaMDYxNDAyBgNVBAMMK2F1dGhvcml6YXRpb24udGVzdGNsb3Vk +MS5haXRpYS5hcnJvd2hlYWQuZXUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK +AoIBAQC28nZZkdduX5SN7SLI8e6ZLSxDSWxVJo9D05jw5xK33lDLvlcAXRvWUf4o +liKwEdiFWd7HK8Qe0xOXUCw9FJjyG48i2FxqoBm6JZEbR93YQqCJcdRnc+F7Yutx +74yvJ+8W2j665QuyyU8lp6/lixKdllYyEhYoUTr88RB0cNEWJ6ZhVJCwRcqGTztm +RRW0AITYClOVqoNjrbeTmKjLihJ/HntpBwxLxBkU+BMWrxF7fSkgz5sJbIDn01T7 +e2vuVkQz55ik95KBm9UZr9lAYs5EI4tayb5QBiUmySoHnRlBo6VHreoUONptoc00 +aOg8oQX3y+AcXd6JHmAsYaxF+Np3AgMBAAGjSjBIMCcGA1UdIwQgMB6AFPSMD0gI +GB689KvzqgS9Uny4NqYloQCCBFzZcN8wHQYDVR0OBBYEFKuCJTxiQGnrChpQMplZ +LtqpXr5GMA0GCSqGSIb3DQEBCwUAA4IBAQBsF+ysFxscz5jZPRP9Y1xdpI1C2EJ4 +6CliDzRhpbjEGiRGbPR72HohJyRLZ4AiZPnD0n5kKJ7B75VyRH+bOM7jmEgKiqLV +uJNneY0jywWXGdUhtZMw40MGAi9KLSlISyyZ4ID/bHi6IjBFDiYR0e49AGqxvHlK +yL97ZJkC/u4WO16CLjcKtW94SpDP9Y4J27VEWNuSLSrEOJjexxWWxOoj+pcxGeip ++xfz1CE2nDSLyyomZwv/XwFDQZoRsPte0Cj9x+kA0P9Yiqs/nTfgxzMgpeNk7G5u +tYaehDT5o9+oLTA6cx+T4nuzN3ZvM59m4cOuHwJxCTgaK10c7e0+IvQ+ +-----END CERTIFICATE----- diff --git a/qos-monitor/src/test/resources/certificates/provider.p12 b/qos-monitor/src/test/resources/certificates/provider.p12 new file mode 100644 index 000000000..02d928fae Binary files /dev/null and b/qos-monitor/src/test/resources/certificates/provider.p12 differ diff --git a/qos-monitor/src/test/resources/certificates/provider.pem b/qos-monitor/src/test/resources/certificates/provider.pem new file mode 100644 index 000000000..5b9199f67 --- /dev/null +++ b/qos-monitor/src/test/resources/certificates/provider.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDLTCCAhWgAwIBAgIEXNlkcjANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB10 +ZXN0Y2xvdWQyLmFpdGlhLmFycm93aGVhZC5ldTAeFw0xOTA1MTMxMjM0NThaFw0y +OTA1MTMxMjM0NThaMD0xOzA5BgNVBAMMMmNsaWVudC1kZW1vLXByb3ZpZGVyLnRl +c3RjbG91ZDIuYWl0aWEuYXJyb3doZWFkLmV1MIIBIjANBgkqhkiG9w0BAQEFAAOC +AQ8AMIIBCgKCAQEA1aaeuv1I4bF5dxMIvUvLMxjRn309kdJewIIH08DfL17/LSss +D70ZaLz0yxNfbPPQpFK8LMK+HQHDiGZH5yp4qJDuEgfmUrqWibnBIBc/K3Ob45lQ +y0zdFVtFsVJYBFVymQwgxJT6th0hI3RGLbCJMzbmpDzT7g0IDsN+64tMyi08ZCPr +qk99uzYgioSSWNb9bhG2Z9646b3oiY5utQWRhP/2z/t6vVJHtRYeyaXPl6Z2M/5K +njpSvpSeZQhNrw+Is1DEE5DHiEjfQFWrLwDOqPKDrvmFyIlJ7P7OCMax6dIlSB7G +EQSSP+j4eIxDWgjm+Pv/c02UVDc0x3xX/UGtNwIDAQABo0owSDAnBgNVHSMEIDAe +gBQEME0II5M93mY9Flqn0cleI6aXT6EAggRc2WIZMB0GA1UdDgQWBBR1hYLJm0+k ++C7QJqQ6rCtDwdHT1DANBgkqhkiG9w0BAQsFAAOCAQEAFJYhz2/SP4GKp3RyOIXF +3KUeITfcEmFOI0gDkbG91T1RIt5R7zesWuiBuHkzj8Dqx5D5Hx4cu8wUV67Xyao1 +O13HaplbAQ0JY6+KPw6NjBUnCAybv0W1lgFvwtRA0HYkP55dkfGz3h8F7GV0hIpX +EX6lQiXxpwrdsdDYag1J/DCoYRG26Pw+pgraYYctIlBfO/E/gZiM7iYPcuj1TgUQ +ovIDOyZbnL/h0em4kLuPFFmtYr0k6gDljkNerROC5AIaMCAjhXMxgujtfeJuts6X +Sglgm11S0K86ZVwQ/pc+eCmXXj+3/tMV401g1ptKltdS8eC2pAeWV4D7HuJUNpcH +cw== +-----END CERTIFICATE----- diff --git a/qos-monitor/src/test/resources/certificates/valid.pem b/qos-monitor/src/test/resources/certificates/valid.pem new file mode 100644 index 000000000..56eae293d --- /dev/null +++ b/qos-monitor/src/test/resources/certificates/valid.pem @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDLzCCAhegAwIBAgIEXPYrATANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB10 +ZXN0Y2xvdWQyLmFpdGlhLmFycm93aGVhZC5ldTAeFw0xOTA2MDQwODI1MzdaFw0y +MDA2MDMwODI1MzdaMC4xLDAqBgNVBAMMI3N5c29wLnRlc3RjbG91ZDIuYWl0aWEu +YXJyb3doZWFkLmV1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoCoC +WTjB+UIi8WC8+mynAwDpC74ddxCFRt1ugnTSaW2HGJY57mZRmft/APhy7C+HyXyz +j77K6TCkr9jXxAykrkGhybdJ3ITNulolZImH2Vz8WHbmcvcKotdOvVexNou72LKi +RMrboIxIRJPtTta7RbhmVyIrTVElAVDWFjZHP7K98AhoGa3ADp0xbh0qK1BpuCnP +Km64DbY52zwr58mSaeyL7MgE+dWwWHx9r4X/WI7/2qQIio8DTvx36PHGKurtwpxa +V0o+gQ+Q1YcD1mfSHp3xtYQAnZXRLIjaDd7LGWMG7j3HbqukkjThyKrUCKfrKXQF +ItBUJ58PJJq8sTxoLwIDAQABo1swWTAPBgNVHREECDAGhwR/AAABMCcGA1UdIwQg +MB6AFAQwTQgjkz3eZj0WWqfRyV4jppdPoQCCBFzZYhkwHQYDVR0OBBYEFAVG6MVZ +FFyHQXW6qlQWA4EfXWSIMA0GCSqGSIb3DQEBCwUAA4IBAQBUEExzkf2bH4fF/tyP +r7DxO94aqQOySGJq/25DzfZQOpuK5Ud3MPpXSlxYw+MB5rRDJu0NzGUX+ha4mG3T +dXxd3X2QaDFR0SYUD4J0hTtmYp9TzgCXnU+J7t6sku/LYFJrCl5m4o124ShZXBgR +Dj/gDVd4C6InTPhpIPHaD6D97wKyObbC3V1dGiVs5Z5/+wUJdUFUmnfAb1rbX0nV +0TTKluWTtRT4cjBeIFs7MZiThMx8bgSE4mZIC1ry4PikjAap/oEIQVxbBTbl+5q8 +xhPbPn+JhZwQp39a1oPMEQog0wQhtKvZrYx//H1o3mzRo1ZFzL+R/LCKKElMPMXx +UHKC +-----END CERTIFICATE----- diff --git a/scripts/certificate_authority_privileges.sql b/scripts/certificate_authority_privileges.sql new file mode 100644 index 000000000..e39d0c9f7 --- /dev/null +++ b/scripts/certificate_authority_privileges.sql @@ -0,0 +1,9 @@ +USE `arrowhead`; + +REVOKE ALL, GRANT OPTION FROM 'certificate_authority'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'certificate_authority'@'localhost'; + +REVOKE ALL, GRANT OPTION FROM 'certificate_authority'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'certificate_authority'@'%'; + +FLUSH PRIVILEGES; diff --git a/scripts/certificate_generation/lib_certs.sh b/scripts/certificate_generation/lib_certs.sh new file mode 100644 index 000000000..a1ef62b2d --- /dev/null +++ b/scripts/certificate_generation/lib_certs.sh @@ -0,0 +1,364 @@ +# Created by Emanuel Palm (https://github.com/emanuelpalm) + +# Uses `keytool`, typically bundled with Java installations, to generate and +# sign keystores, certificates and truststores for Arrowhead roots, clouds, +# systems and system operators. + +# The environment variable PASSWORD is used to set the password of all +# created key stores. If it is not set, "123456" is used by default. The +# password can be changed for individual keystores and truststores later if +# desired. +if [[ -z "${PASSWORD}" ]]; then + export PASSWORD="123456" +fi + +# Creates a root certificate keystore and a corresponding PEM certificate. +# +# If the keystore already exists, the operation does nothing. If the PEM +# cerificate is missing, it will be created either from the already +# existing or new keystore. +# +# @param $1 Path to desired root certificate keystore. +# @param $2 Desired Common Name of root certificate. +create_root_keystore() { + local ROOT_KEYSTORE=$1 + local ROOT_KEY_ALIAS=$2 + local ROOT_CERT_FILE="${ROOT_KEYSTORE%.*}.crt" + + if [ ! -f "${ROOT_KEYSTORE}" ]; then + echo -e "\e[34mCreating \e[33m${ROOT_KEYSTORE}\e[34m ...\e[0m" + mkdir -p "$(dirname "${ROOT_KEYSTORE}")" + rm -f "${ROOT_CERT_FILE}" + + keytool -genkeypair -v \ + -keystore "${ROOT_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -keyalg "RSA" \ + -keysize "2048" \ + -validity "3650" \ + -alias "${ROOT_KEY_ALIAS}" \ + -keypass:env "PASSWORD" \ + -dname "CN=${ROOT_KEY_ALIAS}" \ + -ext "BasicConstraints=ca:true,pathlen:3" + fi + + if [ ! -f "${ROOT_CERT_FILE}" ]; then + echo -e "\e[34mCreating \e[33m${ROOT_CERT_FILE}\e[34m ...\e[0m" + + keytool -exportcert -v \ + -keystore "${ROOT_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -alias "${ROOT_KEY_ALIAS}" \ + -keypass:env "PASSWORD" \ + -file "${ROOT_CERT_FILE}" \ + -rfc + fi +} + +# Creates a cloud certificate keystore, containing a certificate signed by the +# specified root, and a corresponding PEM certificate. +# +# If the keystore already exists, the operation does nothing. If the PEM +# cerificate is missing, it will be created either from the already +# existing or new keystore. If the root keystore has changed since an +# existing cloud keystore was created, it is recreated. +# +# @param $1 Path to root certificate keystore. +# @param $2 Common Name of root certificate. +# @param $3 Path to desired cloud certificate keystore. +# @param $4 Desired Common Name of cloud certificate. +create_cloud_keystore() { + local ROOT_KEYSTORE=$1 + local ROOT_KEY_ALIAS=$2 + local ROOT_CERT_FILE="${ROOT_KEYSTORE%.*}.crt" + local CLOUD_KEYSTORE=$3 + local CLOUD_KEY_ALIAS=$4 + local CLOUD_CERT_FILE="${CLOUD_KEYSTORE%.*}.crt" + + if [ -f "${CLOUD_KEYSTORE}" ] && [ "${ROOT_KEYSTORE}" -nt "${CLOUD_KEYSTORE}" ]; then + rm -f "${CLOUD_KEYSTORE}" + fi + + if [ ! -f "${CLOUD_KEYSTORE}" ]; then + echo -e "\e[34mCreating \e[33m${CLOUD_KEYSTORE}\e[34m ...\e[0m" + mkdir -p "$(dirname "${CLOUD_KEYSTORE}")" + rm -f "${CLOUD_CERT_FILE}" + + keytool -genkeypair -v \ + -keystore "${CLOUD_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -keyalg "RSA" \ + -keysize "2048" \ + -validity "3650" \ + -alias "${CLOUD_KEY_ALIAS}" \ + -keypass:env "PASSWORD" \ + -dname "CN=${CLOUD_KEY_ALIAS}" \ + -ext "BasicConstraints=ca:true,pathlen:2" + + keytool -importcert -v \ + -keystore "${CLOUD_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -alias "${ROOT_KEY_ALIAS}" \ + -file "${ROOT_CERT_FILE}" \ + -trustcacerts \ + -noprompt + + keytool -certreq -v \ + -keystore "${CLOUD_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -alias "${CLOUD_KEY_ALIAS}" \ + -keypass:env "PASSWORD" | + keytool -gencert -v \ + -keystore "${ROOT_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -validity "3650" \ + -alias "${ROOT_KEY_ALIAS}" \ + -keypass:env "PASSWORD" \ + -ext "BasicConstraints=ca:true,pathlen:2" \ + -rfc | + keytool -importcert \ + -keystore "${CLOUD_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -alias "${CLOUD_KEY_ALIAS}" \ + -keypass:env "PASSWORD" \ + -trustcacerts \ + -noprompt + fi + + if [ ! -f "${CLOUD_CERT_FILE}" ]; then + echo -e "\e[34mCreating \e[33m${CLOUD_CERT_FILE}\e[34m ...\e[0m" + + keytool -exportcert -v \ + -keystore "${CLOUD_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -alias "${CLOUD_KEY_ALIAS}" \ + -keypass:env "PASSWORD" \ + -file "${CLOUD_CERT_FILE}" \ + -rfc + fi +} + +# Creates a system certificate keystore, containing a certificate signed by +# the specified cloud, and a corresponding PEM certificate and public key +# file. +# +# If the keystore already exists, the operation does nothing. If either the +# PEM cerificate or public key file is missing, those will be created either +# from the already existing or new keystore. If the cloud keystore has changed +# since an existing system keystore was created, it is recreated. +# +# @param $1 Path to root certificate keystore. +# @param $2 Common Name of root certificate. +# @param $3 Path to cloud certificate keystore. +# @param $4 Common Name of cloud certificate. +# @param $5 Path to desired system certificate keystore. +# @param $6 Desired Common Name of system certificate. +create_system_keystore() { + local ROOT_KEYSTORE=$1 + local ROOT_KEY_ALIAS=$2 + local ROOT_CERT_FILE="${ROOT_KEYSTORE%.*}.crt" + local CLOUD_KEYSTORE=$3 + local CLOUD_KEY_ALIAS=$4 + local CLOUD_CERT_FILE="${CLOUD_KEYSTORE%.*}.crt" + local SYSTEM_KEYSTORE=$5 + local SYSTEM_KEY_ALIAS=$6 + local SYSTEM_PUB_FILE="${SYSTEM_KEYSTORE%.*}.pub" + local SAN=$7 + + if [ -f "${SYSTEM_KEYSTORE}" ] && [ "${CLOUD_KEYSTORE}" -nt "${SYSTEM_KEYSTORE}" ]; then + rm -f "${SYSTEM_KEYSTORE}" + fi + + if [ ! -f "${SYSTEM_KEYSTORE}" ]; then + echo -e "\e[34mCreating \e[33m${SYSTEM_KEYSTORE}\e[34m ...\e[0m" + mkdir -p "$(dirname "${SYSTEM_KEYSTORE}")" + rm -f "${SYSTEM_PUB_FILE}" + + keytool -genkeypair -v \ + -keystore "${SYSTEM_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -keyalg "RSA" \ + -keysize "2048" \ + -validity "3650" \ + -alias "${SYSTEM_KEY_ALIAS}" \ + -keypass:env "PASSWORD" \ + -dname "CN=${SYSTEM_KEY_ALIAS}" \ + -ext "SubjectAlternativeName=${SAN}" + + keytool -importcert -v \ + -keystore "${SYSTEM_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -alias "${ROOT_KEY_ALIAS}" \ + -file "${ROOT_CERT_FILE}" \ + -trustcacerts \ + -noprompt + + keytool -importcert -v \ + -keystore "${SYSTEM_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -alias "${CLOUD_KEY_ALIAS}" \ + -file "${CLOUD_CERT_FILE}" \ + -trustcacerts \ + -noprompt + + keytool -certreq -v \ + -keystore "${SYSTEM_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -alias "${SYSTEM_KEY_ALIAS}" \ + -keypass:env "PASSWORD" | + keytool -gencert -v \ + -keystore "${CLOUD_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -validity "3650" \ + -alias "${CLOUD_KEY_ALIAS}" \ + -keypass:env "PASSWORD" \ + -ext "SubjectAlternativeName=${SAN}" \ + -rfc | + keytool -importcert \ + -keystore "${SYSTEM_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -alias "${SYSTEM_KEY_ALIAS}" \ + -keypass:env "PASSWORD" \ + -trustcacerts \ + -noprompt + fi + + if [ ! -f "${SYSTEM_PUB_FILE}" ]; then + echo -e "\e[34mCreating \e[33m${SYSTEM_PUB_FILE}\e[34m ...\e[0m" + + keytool -list \ + -keystore "${SYSTEM_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -alias "${SYSTEM_KEY_ALIAS}" \ + -rfc | + openssl x509 \ + -inform pem \ + -pubkey \ + -noout >"${SYSTEM_PUB_FILE}" + fi +} + +# Creates a system operator certificate keystore, containing a certificate +# signed by the specified cloud, a PEM certificate file, a CA (Certificate +# Authority) file, a public key file and a private key file. +# +# If the keystore already exists, the operation does nothing. If the PEM +# cerificate is missing, it will be created either from the already +# existing or new keystore. If the cloud keystore has changed since an +# existing system operator keystore was created, it is recreated. +# +# @param $1 Path to root certificate keystore. +# @param $2 Common Name of root certificate. +# @param $3 Path to cloud certificate keystore. +# @param $4 Common Name of cloud certificate. +# @param $5 Path to desired system operator certificate keystore. +# @param $6 Desired Common Name of system operator certificate. +create_sysop_keystore() { + local ROOT_KEYSTORE=$1 + local ROOT_CERT_FILE="${ROOT_KEYSTORE%.*}.crt" + local CLOUD_KEYSTORE=$3 + local CLOUD_CERT_FILE="${CLOUD_KEYSTORE%.*}.crt" + local SYSOP_KEYSTORE=$5 + local SYSOP_KEY_ALIAS=$6 + local SYSOP_PUB_FILE="${SYSOP_KEYSTORE%.*}.pub" + local SYSOP_CA_FILE="${SYSOP_KEYSTORE%.*}.ca" + local SYSOP_CERT_FILE="${SYSOP_KEYSTORE%.*}.crt" + local SYSOP_KEY_FILE="${SYSOP_KEYSTORE%.*}.key" + + local CREATE_KEYSTORE_OR_PUB_FILE=0 + + if [ -f "${SYSOP_KEYSTORE}" ] && [ "${CLOUD_KEYSTORE}" -nt "${SYSOP_KEYSTORE}" ]; then + rm -f "${SYSOP_KEYSTORE}" + fi + + if [ ! -f "${SYSOP_KEYSTORE}" ]; then + rm -f "${SYSOP_CA_FILE}" + rm -f "${SYSOP_CERT_FILE}" + rm -f "${SYSOP_KEY_FILE}" + CREATE_KEYSTORE_OR_PUB_FILE=1 + fi + + if [ ! -f "${SYSOP_PUB_FILE}" ]; then + CREATE_KEYSTORE_OR_PUB_FILE=1 + fi + + if [[ "${CREATE_KEYSTORE_OR_PUB_FILE}" == "1" ]]; then + create_system_keystore "$1" "$2" "$3" "$4" "$5" "$6" "dns:localost,ip:127.0.0.1" + fi + + if [ ! -f "${SYSOP_CA_FILE}" ]; then + echo -e "\e[34mCreating \e[33m${SYSOP_CA_FILE}\e[34m ...\e[0m" + + cat "${ROOT_CERT_FILE}" >"${SYSOP_CA_FILE}" + cat "${CLOUD_CERT_FILE}" >>"${SYSOP_CA_FILE}" + fi + + if [ ! -f "${SYSOP_CERT_FILE}" ]; then + echo -e "\e[34mCreating \e[33m${SYSOP_CERT_FILE}\e[34m ...\e[0m" + + keytool -exportcert -v \ + -keystore "${SYSOP_KEYSTORE}" \ + -storepass:env "PASSWORD" \ + -alias "${SYSOP_KEY_ALIAS}" \ + -keypass:env "PASSWORD" \ + -rfc >>"${SYSOP_CERT_FILE}" + fi + + if [ ! -f "${SYSOP_KEY_FILE}" ]; then + echo -e "\e[34mCreating \e[33m${SYSOP_KEY_FILE}\e[34m ...\e[0m" + + openssl pkcs12 \ + -in "${SYSOP_KEYSTORE}" \ + -passin env:PASSWORD \ + -out "${SYSOP_KEY_FILE}" \ + -nocerts \ + -nodes + fi +} + +# Creates truststore and populates it with identified certificates. +# +# If the truststore already exists, the operation does nothing. Unless, +# however, any of the identified certificate files are newer than the +# the truststore, in which case the truststore is recreated. +# +# $1 Path to desired truststore. +# $2,4,6... Paths to certificate file ".crt". +# $3,5,7... Common Names of certificates in ".crt" files. +create_truststore() { + local TRUSTSTORE=$1 + local ARGC=$# + local ARGV=("$@") + + if [ -f "${TRUSTSTORE}" ]; then + for ((j = 1; j < ARGC; j = j + 2)); do + local FILE="${ARGV[j]}" + if [ -f "${FILE}" ] && [ "${TRUSTSTORE}" -nt "${FILE}" ]; then + rm -f "${FILE}" + fi + done + fi + + if [ ! -f "${TRUSTSTORE}" ]; then + echo -e "\e[34mCreating \e[33m${TRUSTSTORE}\e[34m ...\e[0m" + mkdir -p "$(dirname "${TRUSTSTORE}")" + + for ((j = 1; j < ARGC; j = j + 2)); do + keytool -importcert -v \ + -keystore "${TRUSTSTORE}" \ + -storepass:env "PASSWORD" \ + -file "${ARGV[j]}" \ + -alias "${ARGV[j + 1]}" \ + -trustcacerts \ + -noprompt + done + fi +} + +# Makes sure that interrupts are not ignored while generating certificates. +exit_script() { + echo -e "\e[1;31mAborting ...\e[0m" + trap - SIGINT SIGTERM + kill -- -$$ +} +trap exit_script SIGINT SIGTERM \ No newline at end of file diff --git a/scripts/certificate_generation/mk_certs.sh b/scripts/certificate_generation/mk_certs.sh new file mode 100644 index 000000000..a6cc7c44f --- /dev/null +++ b/scripts/certificate_generation/mk_certs.sh @@ -0,0 +1,98 @@ +#!/bin/bash + +# Created by Emanuel Palm (https://github.com/emanuelpalm) + +cd "$(dirname "$0")" || exit +source "lib_certs.sh" +cd .. + +# ROOT + +create_root_keystore \ + "cloud-root/crypto/root.p12" "arrowhead.eu" + +# RELAY "CLOUD" + +create_cloud_keystore \ + "cloud-root/crypto/root.p12" "arrowhead.eu" \ + "cloud-relay/crypto/conet-demo-relay.p12" "conet-demo-relay.ltu.arrowhead.eu" + +create_system_keystore \ + "cloud-root/crypto/root.p12" "arrowhead.eu" \ + "cloud-relay/crypto/conet-demo-relay.p12" "conet-demo-relay.ltu.arrowhead.eu" \ + "cloud-relay/crypto/alpha.p12" "alpha.conet-demo-relay.ltu.arrowhead.eu" \ + "dns:alpha.relay,ip:172.23.1.11,dns:localhost,ip:127.0.0.1" + +create_truststore \ + "cloud-relay/crypto/truststore.p12" \ + "cloud-root/crypto/root.crt" "arrowhead.eu" + +# CONSUMER CLOUD + +create_cloud_keystore \ + "cloud-root/crypto/root.p12" "arrowhead.eu" \ + "cloud-data-consumer/crypto/conet-demo-consumer.p12" "conet-demo-consumer.ltu.arrowhead.eu" + +create_consumer_system_keystore() { + SYSTEM_NAME=$1 + + create_system_keystore \ + "cloud-root/crypto/root.p12" "arrowhead.eu" \ + "cloud-data-consumer/crypto/conet-demo-consumer.p12" "conet-demo-consumer.ltu.arrowhead.eu" \ + "cloud-data-consumer/crypto/${SYSTEM_NAME}.p12" "${SYSTEM_NAME}.conet-demo-consumer.ltu.arrowhead.eu" \ + "dns:core.consumer,ip:172.23.2.13,dns:localhost,ip:127.0.0.1" +} + +create_consumer_system_keystore "authorization" +create_consumer_system_keystore "contract_proxy" +create_consumer_system_keystore "data_consumer" +create_consumer_system_keystore "event_handler" +create_consumer_system_keystore "gatekeeper" +create_consumer_system_keystore "gateway" +create_consumer_system_keystore "orchestrator" +create_consumer_system_keystore "service_registry" + +create_sysop_keystore \ + "cloud-root/crypto/root.p12" "arrowhead.eu" \ + "cloud-data-consumer/crypto/conet-demo-consumer.p12" "conet-demo-consumer.ltu.arrowhead.eu" \ + "cloud-data-consumer/crypto/sysop.p12" "sysop.conet-demo-consumer.ltu.arrowhead.eu" + +create_truststore \ + "cloud-data-consumer/crypto/truststore.p12" \ + "cloud-data-consumer/crypto/conet-demo-consumer.crt" "conet-demo-consumer.ltu.arrowhead.eu" \ + "cloud-relay/crypto/conet-demo-relay.crt" "conet-demo-relay.ltu.arrowhead.eu" + +# PRODUCER CLOUD + +create_cloud_keystore \ + "cloud-root/crypto/root.p12" "arrowhead.eu" \ + "cloud-data-producer/crypto/conet-demo-producer.p12" "conet-demo-producer.ltu.arrowhead.eu" + +create_producer_system_keystore() { + SYSTEM_NAME=$1 + + create_system_keystore \ + "cloud-root/crypto/root.p12" "arrowhead.eu" \ + "cloud-data-producer/crypto/conet-demo-producer.p12" "conet-demo-producer.ltu.arrowhead.eu" \ + "cloud-data-producer/crypto/${SYSTEM_NAME}.p12" "${SYSTEM_NAME}.conet-demo-producer.ltu.arrowhead.eu" \ + "dns:core.producer,ip:172.23.3.13,dns:localhost,ip:127.0.0.1" +} + +create_producer_system_keystore "authorization" +create_producer_system_keystore "contract_proxy" +create_producer_system_keystore "data_consumer" +create_producer_system_keystore "event_handler" +create_producer_system_keystore "gatekeeper" +create_producer_system_keystore "gateway" +create_producer_system_keystore "orchestrator" +create_producer_system_keystore "service_registry" + +create_sysop_keystore \ + "cloud-root/crypto/root.p12" "arrowhead.eu" \ + "cloud-data-producer/crypto/conet-demo-producer.p12" "conet-demo-producer.ltu.arrowhead.eu" \ + "cloud-data-producer/crypto/sysop.p12" "sysop.conet-demo-producer.ltu.arrowhead.eu" + +create_truststore \ + "cloud-data-producer/crypto/truststore.p12" \ + "cloud-data-producer/crypto/conet-demo-producer.crt" "conet-demo-producer.ltu.arrowhead.eu" \ + "cloud-relay/crypto/conet-demo-relay.crt" "conet-demo-relay.ltu.arrowhead.eu" \ No newline at end of file diff --git a/scripts/certificate_generation/rm_certs.sh b/scripts/certificate_generation/rm_certs.sh new file mode 100644 index 000000000..0357c400e --- /dev/null +++ b/scripts/certificate_generation/rm_certs.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +# Created by Emanuel Palm (https://github.com/emanuelpalm) + +# With great power comes great responsibility. + +# Removes all keystores, certificates and truststores potentially created by +# `mk_certs.sh`. + +cd "$(dirname "$0")" || exit +cd .. +find cloud-* -regex ".*\.\(p12\|crt\|jks\|pub\|key\|ca\)" -exec rm -f {} \; \ No newline at end of file diff --git a/scripts/create_arrowhead_tables.sql b/scripts/create_arrowhead_tables.sql index df58ad803..2442873a5 100644 --- a/scripts/create_arrowhead_tables.sql +++ b/scripts/create_arrowhead_tables.sql @@ -66,6 +66,18 @@ CREATE TABLE IF NOT EXISTS `system_` ( UNIQUE KEY `triple` (`system_name`,`address`,`port`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `device` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `device_name` varchar(255) NOT NULL, + `address` varchar(255) NOT NULL, + `mac_address` varchar(255) NOT NULL, + `authentication_info` varchar(2047) DEFAULT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `double` (`device_name`,`mac_address`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + CREATE TABLE IF NOT EXISTS `service_definition` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `service_definition` varchar(255) NOT NULL, @@ -87,6 +99,39 @@ CREATE TABLE IF NOT EXISTS `service_interface` ( INSERT IGNORE INTO `service_interface` (interface_name) VALUES ('HTTP-SECURE-JSON'); INSERT IGNORE INTO `service_interface` (interface_name) VALUES ('HTTP-INSECURE-JSON'); +-- Device Registry + +CREATE TABLE IF NOT EXISTS `device_registry` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `device_id` bigint(20) NOT NULL, + `end_of_validity` timestamp NULL DEFAULT NULL, + `metadata` text, + `version` int(11) DEFAULT 1, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `device_registry_device` (`device_id`), + CONSTRAINT `device_registry_device` FOREIGN KEY (`device_id`) REFERENCES `device` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- System Registry + +CREATE TABLE IF NOT EXISTS `system_registry` ( + `id` bigint(20) NOT NULL AUTO_INCREMENT, + `system_id` bigint(20) NOT NULL, + `device_id` bigint(20) NOT NULL, + `end_of_validity` timestamp NULL DEFAULT NULL, + `metadata` text, + `version` int(11) DEFAULT 1, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + PRIMARY KEY (`id`), + UNIQUE KEY `system_registry_pair` (`system_id`,`device_id`), + KEY `system_registry_device` (`device_id`), + CONSTRAINT `system_registry_system` FOREIGN KEY (`system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE, + CONSTRAINT `system_registry_device` FOREIGN KEY (`device_id`) REFERENCES `device` (`id`) ON DELETE CASCADE +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + -- Service Registry CREATE TABLE IF NOT EXISTS `service_registry` ( @@ -101,10 +146,10 @@ CREATE TABLE IF NOT EXISTS `service_registry` ( `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), - UNIQUE KEY `pair` (`service_id`,`system_id`), - KEY `system` (`system_id`), - CONSTRAINT `service` FOREIGN KEY (`service_id`) REFERENCES `service_definition` (`id`) ON DELETE CASCADE, - CONSTRAINT `system` FOREIGN KEY (`system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE + UNIQUE KEY `service_registry_pair` (`service_id`,`system_id`), + KEY `service_registry_system` (`system_id`), + CONSTRAINT `service_registry_service` FOREIGN KEY (`service_id`) REFERENCES `service_definition` (`id`) ON DELETE CASCADE, + CONSTRAINT `service_registry_system` FOREIGN KEY (`system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `service_registry_interface_connection` ( @@ -333,4 +378,95 @@ CREATE TABLE IF NOT EXISTS `choreographer_next_action_step` ( CONSTRAINT `next_action_step` FOREIGN KEY (`action_step_id`) REFERENCES `choreographer_action_step` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8; +-- QoS Monitor + +CREATE TABLE IF NOT EXISTS `qos_intra_measurement` ( + `id` bigint(20) PRIMARY KEY AUTO_INCREMENT, + `system_id` bigint(20) NOT NULL, + `measurement_type` varchar(255) NOT NULL, + `last_measurement_at` timestamp NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + CONSTRAINT `fk_system` FOREIGN KEY (`system_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE, + UNIQUE KEY `unique_system_id_measurement_type` (`system_id`, `measurement_type`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +CREATE TABLE IF NOT EXISTS `qos_intra_ping_measurement` ( + `id` bigint(20) PRIMARY KEY AUTO_INCREMENT, + `measurement_id` bigint(20) NOT NULL, + `available` int(1) NOT NULL DEFAULT 0, + `last_access_at` timestamp NULL DEFAULT NULL, + `min_response_time` int(11) DEFAULT NULL, + `max_response_time` int(11) DEFAULT NULL, + `mean_response_time_with_timeout` int(11) NULL DEFAULT NULL, + `mean_response_time_without_timeout` int(11) NULL DEFAULT NULL, + `jitter_with_timeout` int(11) NULL DEFAULT NULL, + `jitter_without_timeout` int(11) NULL DEFAULT NULL, + `lost_per_measurement_percent` int(3) NOT NULL DEFAULT 0, + `sent` bigint(20) NOT NULL DEFAULT 0, + `received` bigint(20) NOT NULL DEFAULT 0, + `count_started_at` timestamp NULL, + `sent_all` bigint(20) NOT NULL DEFAULT 0, + `received_all` bigint(20) NOT NULL DEFAULT 0, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + CONSTRAINT `fk_measurement` FOREIGN KEY (`measurement_id`) REFERENCES `qos_intra_measurement` (`id`) ON DELETE CASCADE, + UNIQUE KEY `unique_measurement` (`measurement_id`) + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `qos_intra_ping_measurement_log` ( + `id` bigint(20) PRIMARY KEY AUTO_INCREMENT, + `measured_system_address` varchar(255) NOT NULL, + `available` int(1) NOT NULL DEFAULT 0, + `min_response_time` int(11) DEFAULT NULL, + `max_response_time` int(11) DEFAULT NULL, + `mean_response_time_with_timeout` int(11) NULL DEFAULT NULL, + `mean_response_time_without_timeout` int(11) NULL DEFAULT NULL, + `jitter_with_timeout` int(11) NULL DEFAULT NULL, + `jitter_without_timeout` int(11) NULL DEFAULT NULL, + `lost_per_measurement_percent` int(3) NOT NULL DEFAULT 0, + `sent` bigint(20) NOT NULL DEFAULT 0, + `received` bigint(20) NOT NULL DEFAULT 0, + `measured_at` timestamp NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +CREATE TABLE IF NOT EXISTS `qos_intra_ping_measurement_log_details` ( + `id` bigint(20) PRIMARY KEY AUTO_INCREMENT, + `measurement_log_id` bigint(20) NOT NULL, + `measurement_sequenece_number` int(3) NOT NULL, + `success_flag` int(1) NOT NULL DEFAULT 0, + `timeout_flag` int(1) NOT NULL DEFAULT 0, + `error_message` varchar(255) NULL DEFAULT NULL, + `throwable` varchar(255) NULL DEFAULT NULL, + `size_` int(11) NULL DEFAULT NULL, + `rtt` int(11) NULL DEFAULT NULL, + `ttl` int(3) NULL DEFAULT NULL, + `duration` int(5) NULL DEFAULT NULL, + `measured_at` timestamp NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + CONSTRAINT `fk_measurement_log` FOREIGN KEY (`measurement_log_id`) REFERENCES `qos_intra_ping_measurement_log` (`id`) ON DELETE CASCADE + +) ENGINE=InnoDB DEFAULT CHARSET=utf8; + +-- QoS Manager + +CREATE TABLE IF NOT EXISTS `qos_reservation` ( + `id` bigint(20) PRIMARY KEY AUTO_INCREMENT, + `reserved_provider_id` bigint(20) NOT NULL, + `reserved_service_id` bigint(20) NOT NULL, + `consumer_system_name` varchar(255) NOT NULL, + `consumer_address` varchar(255) NOT NULL, + `consumer_port` int(11) NOT NULL, + `reserved_to` timestamp NOT NULL, + `temporary_lock` int(1) NOT NULL DEFAULT 0, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, + CONSTRAINT `fk_reserved_provider` FOREIGN KEY (`reserved_provider_id`) REFERENCES `system_` (`id`) ON DELETE CASCADE, + CONSTRAINT `fk_reserved_service` FOREIGN KEY (`reserved_service_id`) REFERENCES `service_definition` (`id`) ON DELETE CASCADE, + UNIQUE KEY `unique_reserved_provider_and_service` (`reserved_provider_id`, `reserved_service_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/scripts/create_empty_arrowhead_db.sql b/scripts/create_empty_arrowhead_db.sql index 27a130088..82139460b 100644 --- a/scripts/create_empty_arrowhead_db.sql +++ b/scripts/create_empty_arrowhead_db.sql @@ -12,6 +12,21 @@ CREATE USER IF NOT EXISTS 'service_registry'@'localhost' IDENTIFIED BY 'ZzNNpxrb CREATE USER IF NOT EXISTS 'service_registry'@'%' IDENTIFIED BY 'ZzNNpxrbZGVvfJ8'; source service_registry_privileges.sql +-- System Registry +CREATE USER IF NOT EXISTS 'system_registry'@'localhost' IDENTIFIED BY 'Kh12Hhgaxzo7haf'; +CREATE USER IF NOT EXISTS 'system_registry'@'%' IDENTIFIED BY 'Kh12Hhgaxzo7haf'; +source system_registry_privileges.sql + +-- Device Registry +CREATE USER IF NOT EXISTS 'device_registry'@'localhost' IDENTIFIED BY 'iooHU87hNGUalht'; +CREATE USER IF NOT EXISTS 'device_registry'@'%' IDENTIFIED BY 'iooHU87hNGUalht'; +source device_registry_privileges.sql + +-- Onboarding controller +CREATE USER IF NOT EXISTS 'onboarding_controller'@'localhost' IDENTIFIED BY 'JKgh1as5f6oi7aV'; +CREATE USER IF NOT EXISTS 'onboarding_controller'@'%' IDENTIFIED BY 'JKgh1as5f6oi7aV'; +source onboarding_controller_privileges.sql + -- Authorization CREATE USER IF NOT EXISTS 'authorization'@'localhost' IDENTIFIED BY 'hqZFUkuHxhekio3'; CREATE USER IF NOT EXISTS 'authorization'@'%' IDENTIFIED BY 'hqZFUkuHxhekio3'; @@ -40,4 +55,14 @@ source gatekeeper_privileges.sql -- Gateway CREATE USER IF NOT EXISTS 'gateway'@'localhost' IDENTIFIED BY 'LfiSM9DpGfDEP5g'; CREATE USER IF NOT EXISTS 'gateway'@'%' IDENTIFIED BY 'LfiSM9DpGfDEP5g'; -source gateway_privileges.sql \ No newline at end of file +source gateway_privileges.sql + +-- Certificate Authority +CREATE USER IF NOT EXISTS 'certificate_authority'@'localhost' IDENTIFIED BY 'FsdG6Kgf9QpPfv2'; +CREATE USER IF NOT EXISTS 'certificate_authority'@'%' IDENTIFIED BY 'FsdG6Kgf9QpPfv2'; +source certificate_authority_privileges.sql + +-- QoS Monitor +CREATE USER IF NOT EXISTS 'qos_monitor'@'localhost' IDENTIFIED BY 'RLY3UEx6nx4kSXy'; +CREATE USER IF NOT EXISTS 'qos_monitor'@'%' IDENTIFIED BY 'RLY3UEx6nx4kSXy'; +source qos_monitor_privileges.sql diff --git a/scripts/device_registry_privileges.sql b/scripts/device_registry_privileges.sql new file mode 100644 index 000000000..eaa1e60ce --- /dev/null +++ b/scripts/device_registry_privileges.sql @@ -0,0 +1,33 @@ +USE `arrowhead`; + +REVOKE ALL, GRANT OPTION FROM 'device_registry'@'localhost'; + +GRANT ALL PRIVILEGES ON `arrowhead`.`device` TO 'device_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`device_registry` TO 'device_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'device_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'device_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'device_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry` TO 'device_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry_interface_connection` TO 'device_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'device_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'device_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'device_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'device_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'device_registry'@'localhost'; + +REVOKE ALL, GRANT OPTION FROM 'device_registry'@'%'; + +GRANT ALL PRIVILEGES ON `arrowhead`.`device` TO 'device_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`device_registry` TO 'device_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'device_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'device_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'device_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry` TO 'device_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry_interface_connection` TO 'device_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'device_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'device_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'device_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'device_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'device_registry'@'%'; + +FLUSH PRIVILEGES; \ No newline at end of file diff --git a/scripts/initSQL.sh b/scripts/initSQL.sh index 6c00fb65f..083190781 100644 --- a/scripts/initSQL.sh +++ b/scripts/initSQL.sh @@ -5,14 +5,19 @@ rm -rf sql mkdir sql cd sql wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/create_empty_arrowhead_db.sql -sed 's/source /& docker-entrypoint-initdb.d\/privileges\//g' create_empty_arrowhead_db.sql +sed -i 's/source /& docker-entrypoint-initdb.d\/privileges\//g' create_empty_arrowhead_db.sql mkdir privileges cd privileges +wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/create_arrowhead_tables.sql wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/service_registry_privileges.sql wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/authorization_privileges.sql wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/orchestrator_privileges.sql wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/event_handler_privileges.sql wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/choreographer_privileges.sql wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/gatekeeper_privileges.sql -wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/gateway_privileges.sql \ No newline at end of file +wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/gateway_privileges.sql +wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/certificate_authority_privileges.sql +wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/system_registry_privileges.sql +wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/device_registry_privileges.sql +wget https://raw.githubusercontent.com/arrowhead-f/core-java-spring/master/scripts/onboarding_controller_privileges.sql diff --git a/scripts/onboarding_controller_privileges.sql b/scripts/onboarding_controller_privileges.sql new file mode 100644 index 000000000..b619e2097 --- /dev/null +++ b/scripts/onboarding_controller_privileges.sql @@ -0,0 +1,11 @@ +USE `arrowhead`; + +REVOKE ALL, GRANT OPTION FROM 'onboarding_controller'@'localhost'; + +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'onboarding_controller'@'localhost'; + +REVOKE ALL, GRANT OPTION FROM 'onboarding_controller'@'%'; + +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'onboarding_controller'@'%'; + +FLUSH PRIVILEGES; \ No newline at end of file diff --git a/scripts/orchestrator_privileges.sql b/scripts/orchestrator_privileges.sql index 9595b3157..b1a4b7803 100644 --- a/scripts/orchestrator_privileges.sql +++ b/scripts/orchestrator_privileges.sql @@ -11,6 +11,7 @@ GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'orchestrator'@' GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'orchestrator'@'localhost'; GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'orchestrator'@'localhost'; GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'orchestrator'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`qos_reservation` TO 'orchestrator'@'localhost'; GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'orchestrator'@'localhost'; REVOKE ALL, GRANT OPTION FROM 'orchestrator'@'%'; @@ -24,6 +25,7 @@ GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gatekeeper_relay` TO 'orchestrator'@' GRANT ALL PRIVILEGES ON `arrowhead`.`cloud_gateway_relay` TO 'orchestrator'@'%'; GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'orchestrator'@'%'; GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'orchestrator'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`qos_reservation` TO 'orchestrator'@'%'; GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'orchestrator'@'%'; FLUSH PRIVILEGES; \ No newline at end of file diff --git a/scripts/qos_monitor_privileges.sql b/scripts/qos_monitor_privileges.sql new file mode 100644 index 000000000..74422bb57 --- /dev/null +++ b/scripts/qos_monitor_privileges.sql @@ -0,0 +1,19 @@ +USE `arrowhead`; + +REVOKE ALL, GRANT OPTION FROM 'qos_monitor'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_measurement` TO 'qos_monitor'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_ping_measurement` TO 'qos_monitor'@'localhost'; +GRANT SELECT ON `arrowhead`.`system_` TO 'qos_monitor'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'qos_monitor'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_ping_measurement_log` TO 'qos_monitor'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_ping_measurement_log_details` TO 'qos_monitor'@'localhost'; + +REVOKE ALL, GRANT OPTION FROM 'qos_monitor'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_measurement` TO 'qos_monitor'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_ping_measurement` TO 'qos_monitor'@'%'; +GRANT SELECT ON `arrowhead`.`system_` TO 'qos_monitor'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'qos_monitor'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_ping_measurement_log` TO 'qos_monitor'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`qos_intra_ping_measurement_log_details` TO 'qos_monitor'@'%'; + +FLUSH PRIVILEGES; \ No newline at end of file diff --git a/scripts/start_coresystems.bat b/scripts/start_coresystems.bat index 3e96b0ad8..2f86c4be2 100644 --- a/scripts/start_coresystems.bat +++ b/scripts/start_coresystems.bat @@ -36,6 +36,10 @@ cd ..\..\choreographer\target START "" /B "cmd /c javaw -jar arrowhead-choreographer-4.1.3.jar > sout_choreographer.log 2>&1" echo Choreographer started +cd ..\..\certificate-authority\target +START "" /B "cmd /c javaw -jar arrowhead-certificate-authority-4.1.3.jar > sout_ca.log 2>&1" +echo Certificate Authority started + cd %parent_path% ::Kill self diff --git a/scripts/start_coresystems.sh b/scripts/start_coresystems.sh index 4d3c7044b..24dbf6fde 100644 --- a/scripts/start_coresystems.sh +++ b/scripts/start_coresystems.sh @@ -35,3 +35,8 @@ echo Orchestrator started cd ../../choreographer/target nohup java -jar $(find . -maxdepth 1 -name arrowhead-choreographer-\*.jar | sort | tail -n1) &> sout_choreographer.log & echo Choreographer started + +cd ../../certificate-authority/target +nohup java -jar $(find . -maxdepth 1 -name arrowhead-certificate-authority-\*.jar | sort | tail -n1) &> sout_ca.log & +echo Certificate Authority started + diff --git a/scripts/start_coresystems_local.bat b/scripts/start_coresystems_local.bat index 179670d0b..e812085fa 100644 --- a/scripts/start_coresystems_local.bat +++ b/scripts/start_coresystems_local.bat @@ -26,6 +26,10 @@ cd ..\..\orchestrator\target START "" /B "cmd /c javaw -jar arrowhead-orchestrator-4.1.3.jar > sout_orch.log 2>&1" echo Orchestrator started +cd ..\..\certificate-authority\target +START "" /B "cmd /c javaw -jar arrowhead-certificate-authority-4.1.3.jar > sout_ca.log 2>&1" +echo Certificate Authority started + cd %parent_path% ::Kill self diff --git a/scripts/start_coresystems_local.sh b/scripts/start_coresystems_local.sh index 884b5cb5d..1d0f3e9a1 100644 --- a/scripts/start_coresystems_local.sh +++ b/scripts/start_coresystems_local.sh @@ -26,3 +26,7 @@ echo Authorization started cd ../../orchestrator/target nohup java -jar $(find . -maxdepth 1 -name arrowhead-orchestrator-\*.jar | sort | tail -n1) &> sout_orch.log & echo Orchestrator started + +cd ../../certificate-authority/target +nohup java -jar $(find . -maxdepth 1 -name arrowhead-certificate-authority-\*.jar | sort | tail -n1) &> sout_ca.log & +echo Certificate Authority started diff --git a/scripts/stop_coresystems.bat b/scripts/stop_coresystems.bat index dc6f3a234..31ab118f0 100644 --- a/scripts/stop_coresystems.bat +++ b/scripts/stop_coresystems.bat @@ -10,6 +10,7 @@ FOR /F "tokens=1" %%p in ('"jps -v | find "gatekeeper""') DO taskkill /pid %%p > FOR /F "tokens=1" %%p in ('"jps -v | find "eventhandler""') DO taskkill /pid %%p > NUL 2>&1 FOR /F "tokens=1" %%p in ('"jps -v | find "gateway""') DO taskkill /pid %%p > NUL 2>&1 FOR /F "tokens=1" %%p in ('"jps -v | find "authorization""') DO taskkill /pid %%p > NUL 2>&1 +FOR /F "tokens=1" %%p in ('"jps -v | find "certificate""') DO taskkill /pid %%p > NUL 2>&1 timeout /t %time_to_sleep% /nobreak > NUL FOR /F "tokens=1" %%p in ('"jps -v | find "serviceregistry""') DO taskkill /pid %%p > NUL 2>&1 @@ -27,6 +28,7 @@ IF "%STILL_THERE%"=="""" ( FOR /F "tokens=1" %%p in ('"jps -v | find "eventhandler""') DO taskkill /F /pid %%p FOR /F "tokens=1" %%p in ('"jps -v | find "gateway""') DO taskkill /F /pid %%p FOR /F "tokens=1" %%p in ('"jps -v | find "authorization""') DO taskkill /F /pid %%p + FOR /F "tokens=1" %%p in ('"jps -v | find "certificate""') DO taskkill /F /pid %%p FOR /F "tokens=1" %%p in ('"jps -v | find "serviceregistry""') DO taskkill /F /pid %%p echo Core systems forcefully killed ) diff --git a/scripts/stop_coresystems.sh b/scripts/stop_coresystems.sh index b19816282..1540cc284 100644 --- a/scripts/stop_coresystems.sh +++ b/scripts/stop_coresystems.sh @@ -7,6 +7,7 @@ pkill -f gatekeeper pkill -f authorization pkill -f eventhandler pkill -f gateway +pkill -f certificate-authority sleep 5s pkill -f serviceregistry sleep 2s @@ -19,8 +20,9 @@ then kill -KILL $(ps aux | grep 'authorization' | awk '{print $2}') kill -KILL $(ps aux | grep 'eventhandler' | awk '{print $2}') kill -KILL $(ps aux | grep 'gateway' | awk '{print $2}') + kill -KILL $(ps aux | grep 'certificate-authority' | awk '{print $2}') kill -KILL $(ps aux | grep 'serviceregistry' | awk '{print $2}') echo Core systems forcefully killed else echo Core systems killed -fi \ No newline at end of file +fi diff --git a/scripts/system_registry_privileges.sql b/scripts/system_registry_privileges.sql new file mode 100644 index 000000000..37ea8a6e0 --- /dev/null +++ b/scripts/system_registry_privileges.sql @@ -0,0 +1,33 @@ +USE `arrowhead`; + +REVOKE ALL, GRANT OPTION FROM 'system_registry'@'localhost'; + +GRANT ALL PRIVILEGES ON `arrowhead`.`device` TO 'system_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'system_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_registry` TO 'system_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'system_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'system_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry` TO 'system_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry_interface_connection` TO 'system_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'system_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'system_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'system_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'system_registry'@'localhost'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'system_registry'@'localhost'; + +REVOKE ALL, GRANT OPTION FROM 'system_registry'@'%'; + +GRANT ALL PRIVILEGES ON `arrowhead`.`device` TO 'system_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_` TO 'system_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`system_registry` TO 'system_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_definition` TO 'system_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_interface` TO 'system_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry` TO 'system_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`service_registry_interface_connection` TO 'system_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud` TO 'system_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_intra_cloud_interface_connection` TO 'system_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud` TO 'system_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`authorization_inter_cloud_interface_connection` TO 'system_registry'@'%'; +GRANT ALL PRIVILEGES ON `arrowhead`.`logs` TO 'system_registry'@'%'; + +FLUSH PRIVILEGES; \ No newline at end of file diff --git a/serviceregistry/.classpath b/serviceregistry/.classpath index cb0f276b7..014cf562e 100644 --- a/serviceregistry/.classpath +++ b/serviceregistry/.classpath @@ -45,5 +45,19 @@
+ + + + + + + + + + + + + + - \ No newline at end of file + diff --git a/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/ServiceRegistryApplicationInitListener.java b/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/ServiceRegistryApplicationInitListener.java index 69d8f2ccd..705581fe1 100644 --- a/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/ServiceRegistryApplicationInitListener.java +++ b/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/ServiceRegistryApplicationInitListener.java @@ -1,93 +1,129 @@ package eu.arrowhead.core.serviceregistry; -import java.util.Base64; -import java.util.List; -import java.util.Map; - -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; -import org.springframework.context.event.ContextRefreshedEvent; -import org.springframework.stereotype.Component; - import eu.arrowhead.common.ApplicationInitListener; import eu.arrowhead.common.CommonConstants; import eu.arrowhead.common.CoreDefaults; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.core.CoreSystem; +import eu.arrowhead.common.core.CoreSystemService; +import eu.arrowhead.common.database.entity.ServiceRegistry; import eu.arrowhead.common.database.entity.System; import eu.arrowhead.common.database.service.CommonDBService; +import eu.arrowhead.common.dto.shared.ServiceRegistryRequestDTO; +import eu.arrowhead.common.dto.shared.ServiceSecurityType; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; import eu.arrowhead.common.exception.ArrowheadException; import eu.arrowhead.common.exception.DataNotFoundException; import eu.arrowhead.core.serviceregistry.database.service.ServiceRegistryDBService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Component; + +import java.time.ZonedDateTime; +import java.util.Base64; +import java.util.List; +import java.util.Map; @Component public class ServiceRegistryApplicationInitListener extends ApplicationInitListener { - - //================================================================================================= - // members - - @Autowired - private CommonDBService commonDBService; - - @Autowired - private ServiceRegistryDBService serviceRegistryDBService; - - //================================================================================================= - // assistant methods - - //------------------------------------------------------------------------------------------------- - @Override - protected void customInit(final ContextRefreshedEvent event) { - logger.debug("customInit started..."); - if (!isOwnCloudRegistered()) { - registerOwnCloud(event.getApplicationContext()); - } - - try { - final String name = coreSystemRegistrationProperties.getCoreSystem().name().toLowerCase(); - final List oldSystems = serviceRegistryDBService.getSystemByName(name); - if (!oldSystems.isEmpty()) { - for (final System system : oldSystems) { - serviceRegistryDBService.removeSystemById(system.getId()); - } - } - - final String authInfo = sslProperties.isSslEnabled() ? Base64.getEncoder().encodeToString(publicKey.getEncoded()) : null; - serviceRegistryDBService.createSystem(name, coreSystemRegistrationProperties.getCoreSystemDomainName(), coreSystemRegistrationProperties.getCoreSystemDomainPort(), authInfo); - } catch (final ArrowheadException ex) { - logger.error("Can't registrate {} as a system.", coreSystemRegistrationProperties.getCoreSystem().name()); - logger.debug("Stacktrace", ex); - } - } - - //------------------------------------------------------------------------------------------------- - private boolean isOwnCloudRegistered() { - logger.debug("isOwnCloudRegistered started..."); - try { - commonDBService.getOwnCloud(sslProperties.isSslEnabled()); - return true; - } catch (final DataNotFoundException ex) { - return false; - } - } - - //------------------------------------------------------------------------------------------------- - private void registerOwnCloud(final ApplicationContext appContext) { - logger.debug("registerOwnCloud started..."); - - if (!standaloneMode) { - String name = CoreDefaults.DEFAULT_OWN_CLOUD_NAME; - String operator = CoreDefaults.DEFAULT_OWN_CLOUD_OPERATOR; - - if (sslProperties.isSslEnabled()) { - @SuppressWarnings("unchecked") - final Map context = appContext.getBean(CommonConstants.ARROWHEAD_CONTEXT, Map.class); - final String serverCN = (String) context.get(CommonConstants.SERVER_COMMON_NAME); - final String[] serverFields = serverCN.split("\\."); - name = serverFields[1]; - operator = serverFields[2]; + + //================================================================================================= + // members + + @Autowired + private CommonDBService commonDBService; + + @Autowired + private ServiceRegistryDBService serviceRegistryDBService; + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + @Override + protected void customInit(final ContextRefreshedEvent event) { + logger.debug("customInit started..."); + if (!isOwnCloudRegistered()) { + registerOwnCloud(event.getApplicationContext()); + } + + try { + final String name = coreSystemRegistrationProperties.getCoreSystem().name().toLowerCase(); + final List oldSystems = serviceRegistryDBService.getSystemByName(name); + if (!oldSystems.isEmpty()) { + for (final System system : oldSystems) { + removeServiceRegistryEntries(system); + serviceRegistryDBService.removeSystemById(system.getId()); + } + } + + final String authInfo = sslProperties.isSslEnabled() ? Base64.getEncoder().encodeToString(publicKey.getEncoded()) : null; + final SystemRequestDTO systemRequestDTO = new SystemRequestDTO(name, coreSystemRegistrationProperties.getCoreSystemDomainName(), + coreSystemRegistrationProperties.getCoreSystemDomainPort(), authInfo); + + final ServiceSecurityType securityType = sslProperties.isSslEnabled() ? ServiceSecurityType.CERTIFICATE : ServiceSecurityType.NOT_SECURE; + final String serviceInterface = sslProperties.isSslEnabled() ? CommonConstants.HTTP_SECURE_JSON : CommonConstants.HTTP_INSECURE_JSON; + + for (CoreSystemService service : CoreSystem.SERVICE_REGISTRY.getServices()) { + final ServiceRegistryRequestDTO registryRequest = new ServiceRegistryRequestDTO(); + registryRequest.setProviderSystem(systemRequestDTO); + registryRequest.setServiceDefinition(service.getServiceDefinition()); + registryRequest.setEndOfValidity(Utilities.convertZonedDateTimeToUTCString(ZonedDateTime.now().plusYears(1))); + registryRequest.setInterfaces(List.of(serviceInterface)); + registryRequest.setServiceUri(service.getServiceUri()); + registryRequest.setSecure(securityType.name()); + + serviceRegistryDBService.registerServiceResponse(registryRequest); + } + } catch (final ArrowheadException ex) { + logger.error("Can't registrate {} as a system.", coreSystemRegistrationProperties.getCoreSystem().name()); + logger.debug("Stacktrace", ex); + } + } + + //------------------------------------------------------------------------------------------------- + private void removeServiceRegistryEntries(final System system) { + for (CoreSystemService service : CoreSystem.SERVICE_REGISTRY.getServices()) { + try { + serviceRegistryDBService.removeServiceRegistry(service.getServiceDefinition(), system.getSystemName(), system.getAddress(), system.getPort()); + } catch (final Exception ex) { + // ignore } - - commonDBService.insertOwnCloud(operator, name, sslProperties.isSslEnabled(), null); - logger.info("{}.{} own cloud is registered in {} mode.", name, operator, getModeString()); - } - } + } + } + + //------------------------------------------------------------------------------------------------- + private boolean isOwnCloudRegistered() { + logger.debug("isOwnCloudRegistered started..."); + try { + commonDBService.getOwnCloud(sslProperties.isSslEnabled()); + return true; + } catch (final DataNotFoundException ex) { + return false; + } + } + + //------------------------------------------------------------------------------------------------- + private void registerOwnCloud(final ApplicationContext appContext) { + logger.debug("registerOwnCloud started..."); + + if (!standaloneMode) { + String name = CoreDefaults.DEFAULT_OWN_CLOUD_NAME; + String operator = CoreDefaults.DEFAULT_OWN_CLOUD_OPERATOR; + + if (sslProperties.isSslEnabled()) { + @SuppressWarnings("unchecked") final Map context = appContext.getBean(CommonConstants.ARROWHEAD_CONTEXT, Map.class); + final String serverCN = (String) context.get(CommonConstants.SERVER_COMMON_NAME); + final String[] serverFields = serverCN.split("\\."); + name = serverFields[1]; + operator = serverFields[2]; + } + + commonDBService.insertOwnCloud(operator, name, sslProperties.isSslEnabled(), null); + logger.info("{}.{} own cloud is registered in {} mode.", name, operator, getModeString()); + } + } } \ No newline at end of file diff --git a/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/ServiceRegistryController.java b/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/ServiceRegistryController.java index f01b54f9a..8c67a76b9 100644 --- a/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/ServiceRegistryController.java +++ b/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/ServiceRegistryController.java @@ -257,7 +257,7 @@ public String echoService() { }) @DeleteMapping(path = SYSTEMS_BY_ID_URI) public void removeSystem(@PathVariable(value = PATH_VARIABLE_ID) final long id) { - logger.debug("New System delete request recieved with id: {}", id); + logger.debug("New System delete request received with id: {}", id); if (id < 1) { throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, CommonConstants.SERVICE_REGISTRY_URI + SYSTEMS_BY_ID_URI); @@ -281,7 +281,7 @@ public void removeSystem(@PathVariable(value = PATH_VARIABLE_ID) final long id) @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_ITEM_PER_PAGE, required = false) final Integer size, @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_DIRECTION, defaultValue = CoreDefaults.DEFAULT_REQUEST_PARAM_DIRECTION_VALUE) final String direction, @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_SORT_FIELD, defaultValue = CoreCommonConstants.COMMON_FIELD_NAME_ID) final String sortField) { - logger.debug("New Service Definition get request recieved with page: {} and item_per page: {}", page, size); + logger.debug("New Service Definition get request received with page: {} and item_per page: {}", page, size); int validatedPage; int validatedSize; @@ -314,7 +314,7 @@ public void removeSystem(@PathVariable(value = PATH_VARIABLE_ID) final long id) }) @GetMapping(path = SERVICES_BY_ID_URI, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public ServiceDefinitionResponseDTO getServiceDefinitionById(@PathVariable(value = PATH_VARIABLE_ID) final long id) { - logger.debug("New Service Definition get request recieved with id: {}", id); + logger.debug("New Service Definition get request received with id: {}", id); if (id < 1) { throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, CommonConstants.SERVICE_REGISTRY_URI + SERVICES_BY_ID_URI); @@ -338,7 +338,7 @@ public void removeSystem(@PathVariable(value = PATH_VARIABLE_ID) final long id) @ResponseStatus(value = org.springframework.http.HttpStatus.CREATED) @ResponseBody public ServiceDefinitionResponseDTO addServiceDefinition(@RequestBody final ServiceDefinitionRequestDTO serviceDefinitionRequestDTO) { final String serviceDefinition = serviceDefinitionRequestDTO.getServiceDefinition(); - logger.debug("New Service Definition registration request recieved with definition: {}", serviceDefinition); + logger.debug("New Service Definition registration request received with definition: {}", serviceDefinition); if (Utilities.isEmpty(serviceDefinition)) { throw new BadPayloadException("Service definition is null or blank", HttpStatus.SC_BAD_REQUEST, CommonConstants.SERVICE_REGISTRY_URI + SERVICES_URI); @@ -368,7 +368,7 @@ public void removeSystem(@PathVariable(value = PATH_VARIABLE_ID) final long id) @ResponseBody public ServiceDefinitionResponseDTO putUpdateServiceDefinition(@PathVariable(value = PATH_VARIABLE_ID) final long id, @RequestBody final ServiceDefinitionRequestDTO serviceDefinitionRequestDTO) { final String serviceDefinition = serviceDefinitionRequestDTO.getServiceDefinition(); - logger.debug("New Service Definition update request recieved with id: {}, definition: {}", id, serviceDefinition); + logger.debug("New Service Definition update request received with id: {}, definition: {}", id, serviceDefinition); if (id < 1) { throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, CommonConstants.SERVICE_REGISTRY_URI + SERVICES_BY_ID_URI); @@ -401,7 +401,7 @@ public void removeSystem(@PathVariable(value = PATH_VARIABLE_ID) final long id) @PatchMapping(path = SERVICES_BY_ID_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = "application/json") @ResponseBody public ServiceDefinitionResponseDTO patchUpdateServiceDefinition(@PathVariable(value = PATH_VARIABLE_ID) final long id, @RequestBody final ServiceDefinitionRequestDTO serviceDefinitionRequestDTO) { - // Currently ServiceDefinition has only one updateable field, therefore PUT and PATCH do the same + // Currently ServiceDefinition has only one updatable field, therefore PUT and PATCH do the same return putUpdateServiceDefinition(id, serviceDefinitionRequestDTO); } @@ -415,7 +415,7 @@ public void removeSystem(@PathVariable(value = PATH_VARIABLE_ID) final long id) }) @DeleteMapping(path = SERVICES_BY_ID_URI) public void removeServiceDefinition(@PathVariable(value = PATH_VARIABLE_ID) final long id) { - logger.debug("New Service Definition delete request recieved with id: {}", id); + logger.debug("New Service Definition delete request received with id: {}", id); if (id < 1) { throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, CommonConstants.SERVICE_REGISTRY_URI + SERVICES_BY_ID_URI); @@ -439,7 +439,7 @@ public void removeServiceDefinition(@PathVariable(value = PATH_VARIABLE_ID) fina @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_ITEM_PER_PAGE, required = false) final Integer size, @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_DIRECTION, defaultValue = CoreDefaults.DEFAULT_REQUEST_PARAM_DIRECTION_VALUE) final String direction, @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_SORT_FIELD, defaultValue = CoreCommonConstants.COMMON_FIELD_NAME_ID) final String sortField) { - logger.debug("New Service Registry get request recieved with page: {} and item_per page: {}", page, size); + logger.debug("New Service Registry get request received with page: {} and item_per page: {}", page, size); int validatedPage; int validatedSize; @@ -473,7 +473,7 @@ public void removeServiceDefinition(@PathVariable(value = PATH_VARIABLE_ID) fina }) @GetMapping(path = SERVICE_REGISTRY_MGMT_BY_ID_URI) @ResponseBody public ServiceRegistryResponseDTO getServiceRegistryEntryById(@PathVariable(value = PATH_VARIABLE_ID) final long id) { - logger.debug("New Service Registry get request recieved with id: {}", id); + logger.debug("New Service Registry get request received with id: {}", id); if (id < 1) { throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, CommonConstants.SERVICE_REGISTRY_URI + SERVICE_REGISTRY_MGMT_BY_ID_URI); @@ -500,7 +500,7 @@ public void removeServiceDefinition(@PathVariable(value = PATH_VARIABLE_ID) fina @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_ITEM_PER_PAGE, required = false) final Integer size, @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_DIRECTION, defaultValue = CoreDefaults.DEFAULT_REQUEST_PARAM_DIRECTION_VALUE) final String direction, @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_SORT_FIELD, defaultValue = CoreCommonConstants.COMMON_FIELD_NAME_ID) final String sortField) { - logger.debug("New Service Registry get by Service Definition request recieved with page: {} and item_per page: {}", page, size); + logger.debug("New Service Registry get by Service Definition request received with page: {} and item_per page: {}", page, size); if (Utilities.isEmpty(serviceDefinition)) { throw new BadPayloadException("Service definition cannot be empty.", HttpStatus.SC_BAD_REQUEST, CommonConstants.SERVICE_REGISTRY_URI + SERVICE_REGISTRY_MGMT_BY_SERVICE_DEFINITION_URI); @@ -557,7 +557,7 @@ public void removeServiceDefinition(@PathVariable(value = PATH_VARIABLE_ID) fina }) @DeleteMapping(path = SERVICE_REGISTRY_MGMT_BY_ID_URI) public void removeServiceRegistryEntryById(@PathVariable(value = PATH_VARIABLE_ID) final long id) { - logger.debug("New Service Registry delete request recieved with id: {}", id); + logger.debug("New Service Registry delete request received with id: {}", id); if (id < 1) { throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, CommonConstants.SERVICE_REGISTRY_URI + SERVICE_REGISTRY_MGMT_BY_ID_URI); @@ -578,7 +578,7 @@ public void removeServiceRegistryEntryById(@PathVariable(value = PATH_VARIABLE_I @ResponseStatus(value = org.springframework.http.HttpStatus.CREATED) @PostMapping(path = CommonConstants.OP_SERVICE_REGISTRY_REGISTER_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) @ResponseBody public ServiceRegistryResponseDTO registerService(@RequestBody final ServiceRegistryRequestDTO request) { - logger.debug("New service registration request recieved"); + logger.debug("New service registration request received"); checkServiceRegistryRequest(request, false); final ServiceRegistryResponseDTO response = serviceRegistryDBService.registerServiceResponse(request); @@ -598,7 +598,7 @@ public void removeServiceRegistryEntryById(@PathVariable(value = PATH_VARIABLE_I @ResponseStatus(value = org.springframework.http.HttpStatus.CREATED) @PostMapping(path = CoreCommonConstants.MGMT_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public @ResponseBody ServiceRegistryResponseDTO addServiceRegistry(@RequestBody final ServiceRegistryRequestDTO request) { - logger.debug("New service registration request recieved"); + logger.debug("New service registration request received"); checkServiceRegistryRequest(request, CoreCommonConstants.MGMT_URI, true); final ServiceRegistryResponseDTO response = serviceRegistryDBService.registerServiceResponse(request); @@ -617,7 +617,7 @@ public void removeServiceRegistryEntryById(@PathVariable(value = PATH_VARIABLE_I }) @PutMapping(path = SERVICE_REGISTRY_MGMT_BY_ID_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public @ResponseBody ServiceRegistryResponseDTO updateServiceRegistry(@PathVariable(value = PATH_VARIABLE_ID) final long id, @RequestBody final ServiceRegistryRequestDTO request) { - logger.debug("New service registry update request recieved"); + logger.debug("New service registry update request received"); checkServiceRegistryUpdateRequest(id, request, CoreCommonConstants.MGMT_URI); final ServiceRegistryResponseDTO response = serviceRegistryDBService.updateServiceByIdResponse(id, request); @@ -637,7 +637,7 @@ public void removeServiceRegistryEntryById(@PathVariable(value = PATH_VARIABLE_I }) @PatchMapping(path = SERVICE_REGISTRY_MGMT_BY_ID_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public @ResponseBody ServiceRegistryResponseDTO mergeServiceRegistry(@PathVariable(value = PATH_VARIABLE_ID) final long id, @RequestBody final ServiceRegistryRequestDTO request) { - logger.debug("New service registry merge request recieved"); + logger.debug("New service registry merge request received"); checkServiceRegistryMergeRequest(id, request, CoreCommonConstants.MGMT_URI); final ServiceRegistryResponseDTO response = serviceRegistryDBService.mergeServiceByIdResponse(id, request); @@ -735,6 +735,29 @@ public void unregisterService(@RequestParam(CommonConstants.OP_SERVICE_REGISTRY_ logger.debug("Return system by name: {}, address: {}, port: {}", systemName, address, port); return result; } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return all service registry entries", response = ServiceRegistryListResponseDTO.class, tags = { CoreCommonConstants.SWAGGER_TAG_PRIVATE }) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_SERVICE_REGISTRY_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_SERVICE_REGISTRY_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = CoreCommonConstants.OP_SERVICE_REGISTRY_QUERY_ALL_URI) + @ResponseBody public ServiceRegistryListResponseDTO getServiceRegistryEntries() { + logger.debug("New Service Registry get request recieved"); + + final int page = 0; + final int size = Integer.MAX_VALUE; + final Direction direction = Direction.ASC; + final String sortField = CommonConstants.COMMON_FIELD_NAME_ID; + + final ServiceRegistryListResponseDTO serviceRegistryEntriesResponse = serviceRegistryDBService.getServiceRegistryEntriesResponse(page, size, direction, sortField); + logger.debug("Service Registry entries with page: {} and item_per page: {} successfully retrieved", page, size); + + return serviceRegistryEntriesResponse; + } //================================================================================================= // assistant methods @@ -805,7 +828,7 @@ private void checkSystemMergeRequest(final SystemRequestDTO request, final long } if (request.getPort() != null) { - final int validatedPort = request.getPort().intValue(); + final int validatedPort = request.getPort(); if (validatedPort < CommonConstants.SYSTEM_PORT_RANGE_MIN || validatedPort > CommonConstants.SYSTEM_PORT_RANGE_MAX) { throw new BadPayloadException("Port must be between " + CommonConstants.SYSTEM_PORT_RANGE_MIN + " and " + CommonConstants.SYSTEM_PORT_RANGE_MAX +".", HttpStatus.SC_BAD_REQUEST, CommonConstants.SERVICE_REGISTRY_URI + SYSTEMS_BY_ID_URI); @@ -862,7 +885,7 @@ private void checkSystemRequest(final SystemRequestDTO request, final String ori throw new BadPayloadException(SYSTEM_PORT_NULL_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); } - final int validatedPort = request.getPort().intValue(); + final int validatedPort = request.getPort(); if (validatedPort < CommonConstants.SYSTEM_PORT_RANGE_MIN || validatedPort > CommonConstants.SYSTEM_PORT_RANGE_MAX) { throw new BadPayloadException("Port must be between " + CommonConstants.SYSTEM_PORT_RANGE_MIN + " and " + CommonConstants.SYSTEM_PORT_RANGE_MAX + ".", HttpStatus.SC_BAD_REQUEST, origin); } @@ -981,7 +1004,7 @@ private void checkServiceRegistryMergeRequest(final long id, final ServiceRegist } if (request.getProviderSystem() != null && request.getProviderSystem().getPort() != null) { - final int validatedPort = request.getProviderSystem().getPort().intValue(); + final int validatedPort = request.getProviderSystem().getPort(); if (validatedPort < CommonConstants.SYSTEM_PORT_RANGE_MIN || validatedPort > CommonConstants.SYSTEM_PORT_RANGE_MAX) { throw new BadPayloadException("Port must be between " + CommonConstants.SYSTEM_PORT_RANGE_MIN + " and " + CommonConstants.SYSTEM_PORT_RANGE_MAX +".", HttpStatus.SC_BAD_REQUEST, origin); diff --git a/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/database/service/ServiceRegistryDBService.java b/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/database/service/ServiceRegistryDBService.java index df4c544c1..b64e0a58b 100644 --- a/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/database/service/ServiceRegistryDBService.java +++ b/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/database/service/ServiceRegistryDBService.java @@ -290,7 +290,7 @@ public ServiceDefinition getServiceDefinitionById(final long id) { if (find.isPresent()) { return find.get(); } else { - throw new InvalidParameterException("Service definition with id of '" + id + "' not exists"); + throw new InvalidParameterException("Service definition with id of '" + id + "' does not exist"); } } catch (final InvalidParameterException ex) { throw ex; @@ -388,7 +388,7 @@ public ServiceDefinition updateServiceDefinitionById(final long id, final String serviceDefinitionEntry.setServiceDefinition(validatedServiceDefinition); return serviceDefinitionRepository.saveAndFlush(serviceDefinitionEntry); } else { - throw new InvalidParameterException("Service definition with id of '" + id + "' not exists"); + throw new InvalidParameterException("Service definition with id of '" + id + "' does not exist"); } } catch (final InvalidParameterException ex) { throw ex; @@ -415,7 +415,7 @@ public void removeServiceDefinitionById(final long id) { try { if (!serviceDefinitionRepository.existsById(id)) { - throw new InvalidParameterException("Service Definition with id '" + id + "' not exists"); + throw new InvalidParameterException("Service Definition with id '" + id + "' does not exist"); } serviceDefinitionRepository.deleteById(id); @@ -437,7 +437,7 @@ public ServiceRegistry getServiceRegistryEntryById(final long id) { if (find.isPresent()) { return find.get(); } else { - throw new InvalidParameterException("Service Registry with id of '" + id + "' not exists"); + throw new InvalidParameterException("Service Registry with id of '" + id + "' does not exist"); } } catch (final InvalidParameterException ex) { throw ex; @@ -589,7 +589,7 @@ public ServiceRegistryResponseDTO updateServiceByIdResponse(final long id, final if (srEntryOptional.isPresent()) { srEntry = srEntryOptional.get(); } else { - throw new InvalidParameterException("Service Registry entry with id '" + id + "' not exists"); + throw new InvalidParameterException("Service Registry entry with id '" + id + "' does not exist"); } final String validatedServiceDefinition = request.getServiceDefinition().toLowerCase().trim(); @@ -630,7 +630,7 @@ public ServiceRegistryResponseDTO mergeServiceByIdResponse(final long id, final if (srEntryOptional.isPresent()) { srEntry = srEntryOptional.get(); } else { - throw new InvalidParameterException("Service Registry entry with id '" + id + "' not exists"); + throw new InvalidParameterException("Service Registry entry with id '" + id + "' does not exist"); } final String validatedServiceDefinition = !Utilities.isEmpty(request.getServiceDefinition()) ? request.getServiceDefinition().toLowerCase().trim() : @@ -858,7 +858,7 @@ public void removeServiceRegistryEntryById(final long id) { try { if (!serviceRegistryRepository.existsById(id)) { - throw new InvalidParameterException("Service Registry entry with id '" + id + "' not exists"); + throw new InvalidParameterException("Service Registry entry with id '" + id + "' does not exist"); } serviceRegistryRepository.deleteById(id); diff --git a/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/security/SRAccessControlFilter.java b/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/security/SRAccessControlFilter.java index d46a21ad5..d35734928 100644 --- a/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/security/SRAccessControlFilter.java +++ b/serviceregistry/src/main/java/eu/arrowhead/core/serviceregistry/security/SRAccessControlFilter.java @@ -1,11 +1,5 @@ package eu.arrowhead.core.serviceregistry.security; -import java.util.Map; - -import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; -import org.springframework.http.HttpStatus; -import org.springframework.stereotype.Component; - import eu.arrowhead.common.CommonConstants; import eu.arrowhead.common.CoreCommonConstants; import eu.arrowhead.common.Utilities; @@ -15,6 +9,11 @@ import eu.arrowhead.common.dto.shared.ServiceRegistryRequestDTO; import eu.arrowhead.common.exception.AuthException; import eu.arrowhead.common.security.CoreSystemAccessControlFilter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +import java.util.Map; @Component @ConditionalOnProperty(name = CommonConstants.SERVER_SSL_ENABLED, matchIfMissing = true) @@ -24,9 +23,10 @@ public class SRAccessControlFilter extends CoreSystemAccessControlFilter { // members private static final CoreSystem[] allowedCoreSystemsForQuery = { CoreSystem.ORCHESTRATOR, CoreSystem.GATEKEEPER, CoreSystem.CERTIFICATE_AUTHORITY, CoreSystem.EVENT_HANDLER, - CoreSystem.AUTHORIZATION }; + CoreSystem.AUTHORIZATION, CoreSystem.ONBOARDING_CONTROLLER, CoreSystem.DEVICE_REGISTRY, CoreSystem.SYSTEM_REGISTRY }; private static final CoreSystem[] allowedCoreSystemsForQueryBySystemId = { CoreSystem.ORCHESTRATOR }; private static final CoreSystem[] allowedCoreSystemsForQueryBySystemDTO = { CoreSystem.ORCHESTRATOR }; + private static final CoreSystem[] allowedCoreSystemsForQueryAll = { CoreSystem.QOS_MONITOR }; //================================================================================================= // assistant methods @@ -61,6 +61,9 @@ protected void checkClientAuthorized(final String clientCN, final String method, } else if (requestTarget.endsWith(CoreCommonConstants.OP_SERVICE_REGISTRY_QUERY_BY_SYSTEM_DTO_URI)) { // Only dedicated core systems can use this service checkIfClientIsAnAllowedCoreSystem(clientCN, cloudCN, allowedCoreSystemsForQueryBySystemDTO, requestTarget); + } else if (requestTarget.endsWith(CoreCommonConstants.OP_SERVICE_REGISTRY_QUERY_ALL_URI)) { + // Only dedicated core systems can use this service + checkIfClientIsAnAllowedCoreSystem(clientCN, cloudCN, allowedCoreSystemsForQueryAll, requestTarget); } } diff --git a/serviceregistry/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/serviceregistry/src/main/resources/META-INF/additional-spring-configuration-metadata.json index 8ccdfc698..2623b21e2 100644 --- a/serviceregistry/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/serviceregistry/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -1,28 +1,13 @@ {"properties": [ { - "name": "ping_scheduled", - "type": "java.lang.Boolean", - "description": "A description for 'ping_scheduled'" - }, - { - "name": "ping_timeout", - "type": "java.lang.Long", - "description": "A description for 'ping_timeout'" - }, - { - "name": "ping_interval", + "name": "ca.validity.negative-offest-millis", "type": "java.lang.Long", - "description": "A description for 'ping_interval'" + "description": "The negative offset in milliseconds from the current time for the beginning of the validity of the generated certificates" }, { - "name": "ttl_scheduled", - "type": "java.lang.Boolean", - "description": "A description for 'ttl_scheduled'" - }, - { - "name": "ttl_interval", + "name": "ca.validity.positive-offest-millis", "type": "java.lang.Long", - "description": "A description for 'ttl_interval'" + "description": "The offset in milliseconds from the current time for the end of the validity of the generated certificates" }, { "name": "disable.hostname.verifier", @@ -34,11 +19,6 @@ "type": "java.lang.Boolean", "description": "A description for 'log_all_request_and_response'" }, - { - "name": "use_strict_service_intf_name_verifier", - "type": "java.lang.Boolean", - "description": "A description for 'use_strict_service_intf_name_verifier'" - }, { "name": "core_system_name", "type": "java.lang.String", @@ -54,4 +34,4 @@ "type": "java.lang.Integer", "description": "A description for 'domain.port'" } -]} \ No newline at end of file +]} diff --git a/systemregistry/pom.xml b/systemregistry/pom.xml new file mode 100644 index 000000000..97610eee4 --- /dev/null +++ b/systemregistry/pom.xml @@ -0,0 +1,141 @@ + + 4.0.0 + + eu.arrowhead + core + ${revision} + + + arrowhead-systemregistry + jar + Arrowhead System Registry + SQL-based System Registry core service + + + + eu.arrowhead + arrowhead-core-common + ${revision} + + + com.h2database + h2 + test + + + + + + + maven-resources-plugin + ${mvn.resources.version} + + + copy-resources + + validate + + copy-resources + + + ${basedir}/target + + + src/main/resources + + application.properties + log4j2.xml + + + + + + + + + + jdeb + org.vafer + 1.8 + + + package + + jdeb + + + true + + [YYMMddHHmm].${git.commit.id.abbrev} + target/${project.artifactId}_${revision}.deb + true + ${basedir}/src/deb/control + + + file + ${project.build.directory}/${project.build.finalName}.jar + + perm + /usr/share/arrowhead/system_registry + 755 + + + + + link + /usr/share/arrowhead/system_registry/${project.artifactId}.jar + /usr/share/arrowhead/system_registry/${project.build.finalName}.jar + + + + file + ${project.build.directory}/log4j2.xml + + perm + /etc/arrowhead/systems/system_registry + 644 + + + + + file + ${project.build.directory}/application.properties + + perm + /etc/arrowhead/systems/system_registry + 644 + + + + + link + /usr/share/arrowhead/system_registry/application.properties + /etc/arrowhead/systems/system_registry/application.properties + + + + file + ${project.basedir}/src/deb/arrowhead-systemregistry.service + + perm + /etc/systemd/system + 644 + + + + + file + ${project.basedir}/../scripts/system_registry_privileges.sql + + perm + /usr/share/arrowhead/conf + + + + + + + + + + \ No newline at end of file diff --git a/systemregistry/src/deb/arrowhead-systemregistry.service b/systemregistry/src/deb/arrowhead-systemregistry.service new file mode 100644 index 000000000..2c255df69 --- /dev/null +++ b/systemregistry/src/deb/arrowhead-systemregistry.service @@ -0,0 +1,15 @@ +[Unit] +Description=arrowhead-systemregistry +After=network.target + +[Service] +WorkingDirectory=/etc/arrowhead/systems/system_registry +ExecStart=/usr/bin/java -Dlog4j.configurationFile=file:/etc/arrowhead/systems/system_registry/log4j2.xml -jar /usr/share/arrowhead/system_registry/arrowhead-systemregistry.jar +ExecStartPost=/bin/bash -c 'sleep 10' +TimeoutStopSec=5 +Type=simple +User=arrowhead +Group=arrowhead + +[Install] +WantedBy=default.target diff --git a/systemregistry/src/deb/control/config b/systemregistry/src/deb/control/config new file mode 100644 index 000000000..dafa23d7a --- /dev/null +++ b/systemregistry/src/deb/control/config @@ -0,0 +1,19 @@ +#!/bin/sh -e + +. /usr/share/debconf/confmodule + +if logname 2>/dev/null; then + USER=$(logname) + HOME=$(eval echo "~$USER") +else + USER="root" + HOME="/root" +fi + +# Get installation type +db_input high arrowhead-core-common/db_host || true +db_input high arrowhead-core-common/mysql_password_sysr || true + +# Run dialogs +db_go || true + diff --git a/systemregistry/src/deb/control/control b/systemregistry/src/deb/control/control new file mode 100644 index 000000000..d40708b5b --- /dev/null +++ b/systemregistry/src/deb/control/control @@ -0,0 +1,10 @@ +Package: arrowhead-system-registry +Version: [[version]] +Section: contrib/java +Priority: optional +Architecture: all +Maintainer: Mario Zsilak +Homepage: http://www.arrowhead.eu +Description: Arrowhead System Registry +Distribution: development +Depends: java-runtime-headless, openssl, virtual-mysql-server, arrowhead-core-common diff --git a/systemregistry/src/deb/control/postinst b/systemregistry/src/deb/control/postinst new file mode 100644 index 000000000..a9ee7abcb --- /dev/null +++ b/systemregistry/src/deb/control/postinst @@ -0,0 +1,103 @@ +#!/bin/sh +# postinst script for arrowhead-systemregistry +# +# see: dh_installdeb(1) + +set -e + +. /usr/share/debconf/confmodule + +SYSTEM_NAME="system_registry" +PKG_NAME="arrowhead-systemregistry" + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-remove' +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + +case "$1" in + configure) + dos2unix -q /etc/systemd/system/${PKG_NAME}.service + + . /usr/share/arrowhead/conf/ahconf.sh + + SYSTEM_DIR="${AH_SYSTEMS_DIR}/${SYSTEM_NAME}" + + db_get arrowhead-core-common/mysql_password_sysr; system_passwd=$RET || true + db_unregister arrowhead-core-common/mysql_password_sysr + + # Generate password (if required) + if [ -z "${system_passwd}" ]; then + system_passwd="$(openssl rand -base64 12)" + fi + + echo "Configuring MySQL database..." >&2 + ah_db_tables_and_user ${SYSTEM_NAME} ${SYSTEM_NAME}_privileges.sql ${system_passwd} + + if [ ! -d "${SYSTEM_DIR}" ]; then + mkdir -p ${SYSTEM_DIR} + fi + + domain_name=${AH_DOMAIN_NAME} + if [ -z ${domain_name} ]; then + domain_name=${OWN_IP} + fi + + ah_cert_signed_system ${SYSTEM_NAME} + + # modify log config and application.properties + + ah_transform_log_file ${SYSTEM_DIR} + + db_get arrowhead-core-common/sr_host; sr_host=$RET || true + + if [ -z ${sr_host} ]; then + sr_host=${OWN_IP} + fi + + db_get arrowhead-core-common/db_host; db_host=$RET || true + + mv ${SYSTEM_DIR}/application.properties ${SYSTEM_DIR}/application.properties.orig + cat ${SYSTEM_DIR}/application.properties.orig | \ + sed -r -e "\#^.*spring\.datasource\.url=#s#.*\$#spring.datasource.url=jdbc:mysql://"${db_host}":3306/arrowhead?serverTimezone=Europe/Budapest#" \ + -e "\#^.*spring\.datasource\.password=#s#.*\$#spring.datasource.password=${system_passwd}#" \ + -e "\#^.*domain\.name=#s#.*\$#domain.name=${domain_name}#" \ + -e "\#^.*sr_address=#s#.*\$#sr_address=${sr_host}#" \ + -e "\#^.*server\.ssl\.key-store=#s#.*\$#server.ssl.key-store=file:${SYSTEM_DIR}/${SYSTEM_NAME}.p12#" \ + -e "\#^.*server\.ssl\.key-store-password=#s#.*\$#server.ssl.key-store-password=${AH_PASS_CERT}#" \ + -e "\#^.*server\.ssl\.key-password=#s#.*\$#server.ssl.key-password=${AH_PASS_CERT}#" \ + -e "\#^.*server\.ssl\.trust-store=#s#.*\$#server.ssl.trust-store=file:${AH_CONF_DIR}/truststore.p12#" \ + -e "\#^.*server\.ssl\.trust-store-password=#s#.*\$#server.ssl.trust-store-password=${AH_PASS_CERT}#" > ${SYSTEM_DIR}/application.properties + + rm ${SYSTEM_DIR}/application.properties.orig + chown arrowhead:arrowhead ${SYSTEM_DIR}/application.properties + chmod 640 ${SYSTEM_DIR}/application.properties + + echo "Starting ${PKG_NAME}..." >&2 + systemctl daemon-reload + systemctl enable ${PKG_NAME}.service + systemctl start ${PKG_NAME}.service + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/systemregistry/src/deb/control/postrm b/systemregistry/src/deb/control/postrm new file mode 100644 index 000000000..d314adc04 --- /dev/null +++ b/systemregistry/src/deb/control/postrm @@ -0,0 +1,56 @@ +#!/bin/sh +# postrm script for arrowhead-systemregistry +# +# see: dh_installdeb(1) + +set -e + +. /usr/share/debconf/confmodule + +SYSTEM_NAME="system_registry" + +# summary of how this script can be called: +# * `remove' +# * `purge' +# * `upgrade' +# * `failed-upgrade' +# * `abort-install' +# * `abort-install' +# * `abort-upgrade' +# * `disappear' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + purge) + AH_CONF_DIR="/etc/arrowhead" + AH_SYSTEMS_DIR="${AH_CONF_DIR}/systems" + SYSTEM_DIR="${AH_SYSTEMS_DIR}/${SYSTEM_NAME}" + + rm -f \ + /var/log/arrowhead/${SYSTEM_NAME}*.log \ + ${SYSTEM_DIR}/log4j2.xml \ + ${SYSTEM_DIR}/application.properties \ + ${SYSTEM_DIR}/${SYSTEM_NAME}.p12 + rmdir ${SYSTEM_DIR} 2>/dev/null || true + rmdir ${AH_SYSTEMS_DIR}/sysop 2>/dev/null || true + db_purge + ;; + + remove|upgrade|failed-upgrade|abort-install|abort-upgrade|disappear) + ;; + + *) + echo "postrm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/systemregistry/src/deb/control/preinst b/systemregistry/src/deb/control/preinst new file mode 100644 index 000000000..49a147da0 --- /dev/null +++ b/systemregistry/src/deb/control/preinst @@ -0,0 +1,35 @@ +#!/bin/sh +# preinst script for arrowhead-serviceregistry +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `install' +# * `install' +# * `upgrade' +# * `abort-upgrade' +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + install|upgrade) + ;; + + abort-upgrade) + ;; + + *) + echo "preinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/systemregistry/src/deb/control/prerm b/systemregistry/src/deb/control/prerm new file mode 100644 index 000000000..569aa72d8 --- /dev/null +++ b/systemregistry/src/deb/control/prerm @@ -0,0 +1,45 @@ +#!/bin/sh +# prerm script for arrowhead-systemregistry +# +# see: dh_installdeb(1) + +set -e + +PKG_NAME="arrowhead-systemregistry" + +# summary of how this script can be called: +# * `remove' +# * `upgrade' +# * `failed-upgrade' +# * `remove' `in-favour' +# * `deconfigure' `in-favour' +# `removing' +# +# for details, see https://www.debian.org/doc/debian-policy/ or +# the debian-policy package + + +case "$1" in + remove) + systemctl stop ${PKG_NAME}.service + systemctl disable ${PKG_NAME}.service + ;; + + upgrade|deconfigure) + ;; + + failed-upgrade) + ;; + + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryApplicationInitListener.java b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryApplicationInitListener.java new file mode 100644 index 000000000..934f21fa2 --- /dev/null +++ b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryApplicationInitListener.java @@ -0,0 +1,22 @@ +package eu.arrowhead.core.systemregistry; + +import eu.arrowhead.common.ApplicationInitListener; +import org.springframework.context.event.ContextRefreshedEvent; +import org.springframework.stereotype.Component; + +import java.util.Base64; + +@Component +public class SystemRegistryApplicationInitListener extends ApplicationInitListener { + + //================================================================================================= + // members + + //------------------------------------------------------------------------------------------------- + @Override + protected void customInit(final ContextRefreshedEvent event) { + if (sslProperties.isSslEnabled()) { + logger.debug("AuthInfo: {}", Base64.getEncoder().encodeToString(publicKey.getEncoded())); + } + } +} \ No newline at end of file diff --git a/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryController.java b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryController.java new file mode 100644 index 000000000..6e722b274 --- /dev/null +++ b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryController.java @@ -0,0 +1,213 @@ +package eu.arrowhead.core.systemregistry; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.Defaults; +import eu.arrowhead.common.dto.shared.CertificateType; +import eu.arrowhead.common.dto.shared.SystemQueryFormDTO; +import eu.arrowhead.common.dto.shared.SystemQueryResultDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryRequestDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.core.systemregistry.database.service.SystemRegistryDBService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +@Api(tags = {CoreCommonConstants.SWAGGER_TAG_ALL}) +@CrossOrigin(maxAge = Defaults.CORS_MAX_AGE, allowCredentials = Defaults.CORS_ALLOW_CREDENTIALS, + allowedHeaders = {HttpHeaders.ORIGIN, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT, HttpHeaders.AUTHORIZATION} +) +@RestController +@RequestMapping(CommonConstants.SYSTEM_REGISTRY_URI) +public class SystemRegistryController { + + //================================================================================================= + // members + + private static final String PATH_VARIABLE_ID = "id"; + private static final String SYSTEM_REGISTRY_REGISTER_DESCRIPTION = "Registers a system"; + private static final String SYSTEM_REGISTRY_REGISTER_201_MESSAGE = "System registered"; + private static final String SYSTEM_REGISTRY_REGISTER_400_MESSAGE = "Could not register system"; + private static final String SYSTEM_REGISTRY_UNREGISTER_DESCRIPTION = "Remove a registered system"; + private static final String SYSTEM_REGISTRY_UNREGISTER_200_MESSAGE = "Registered system removed"; + private static final String SYSTEM_REGISTRY_UNREGISTER_400_MESSAGE = "Could not remove system"; + private static final String SYSTEM_REGISTRY_QUERY_DESCRIPTION = "Return System Registry data that fits the specification"; + private static final String SYSTEM_REGISTRY_QUERY_200_MESSAGE = "System Registry data returned"; + private static final String SYSTEM_REGISTRY_QUERY_400_MESSAGE = "Could not query System Registry"; + private static final String SYSTEM_REGISTRY_QUERY_BY_SYSTEM_ID_DESCRIPTION = "Return system by requested id"; + private static final String SYSTEM_REGISTRY_QUERY_BY_SYSTEM_ID_200_MESSAGE = "System data by id returned"; + private static final String SYSTEM_REGISTRY_QUERY_BY_SYSTEM_ID_400_MESSAGE = "Could not query System Registry by Consumer system id"; + private static final String SYSTEM_REGISTRY_QUERY_BY_SYSTEM_DTO_DESCRIPTION = "Return System by requested dto"; + private static final String SYSTEM_REGISTRY_QUERY_BY_SYSTEM_DTO_200_MESSAGE = "Consumer System data by requestDTO returned"; + private static final String SYSTEM_REGISTRY_QUERY_BY_SYSTEM_DTO_400_MESSAGE = "Could not query System Registry by Consumer system requestDTO"; + + private final Logger logger = LogManager.getLogger(SystemRegistryController.class); + + private final SystemRegistryDBService systemRegistryDBService; + private final Validation validation; + + @Autowired + public SystemRegistryController(final SystemRegistryDBService systemRegistryDBService) { + this.systemRegistryDBService = systemRegistryDBService; + this.validation = new Validation(); + } + + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return an echo message with the purpose of testing the core system availability", response = String.class, tags = {CoreCommonConstants.SWAGGER_TAG_CLIENT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = CoreCommonConstants.SWAGGER_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = CommonConstants.ECHO_URI) + public String echoSystem() { + return "Got it!"; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = SYSTEM_REGISTRY_REGISTER_DESCRIPTION, response = SystemRegistryResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_CLIENT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_CREATED, message = SYSTEM_REGISTRY_REGISTER_201_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = SYSTEM_REGISTRY_REGISTER_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @ResponseStatus(value = org.springframework.http.HttpStatus.CREATED) + @PostMapping(path = CommonConstants.OP_SYSTEM_REGISTRY_REGISTER_URI, + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public SystemRegistryResponseDTO registerSystem(@RequestBody final SystemRegistryRequestDTO request) { + logger.debug("New system registration request received"); + validation.checkSystemRegistryRequest(request, getOrigin(CommonConstants.OP_SYSTEM_REGISTRY_REGISTER_URI),false); + + final SystemRegistryResponseDTO response = systemRegistryDBService.registerSystemRegistry(request); + logger.debug("{} successfully registers its system {}", request.getSystem().getSystemName(), request.getSystem()); + + return response; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = SYSTEM_REGISTRY_UNREGISTER_DESCRIPTION, tags = {CoreCommonConstants.SWAGGER_TAG_CLIENT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = SYSTEM_REGISTRY_UNREGISTER_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = SYSTEM_REGISTRY_UNREGISTER_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @DeleteMapping(path = CommonConstants.OP_SYSTEM_REGISTRY_UNREGISTER_URI) + public void unregisterSystem(@RequestParam(CommonConstants.OP_SYSTEM_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_SYSTEM_NAME) final String systemName, + @RequestParam(CommonConstants.OP_SYSTEM_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_ADDRESS) final String address, + @RequestParam(CommonConstants.OP_SYSTEM_REGISTRY_UNREGISTER_REQUEST_PARAM_PROVIDER_PORT) final int port) { + logger.debug("System removal request received"); + validation.checkUnregisterSystemParameters(systemName, address, port, getOrigin(CommonConstants.OP_SYSTEM_REGISTRY_UNREGISTER_URI)); + + systemRegistryDBService.removeSystemRegistryByNameAndAddressAndPort(systemName, address, port); + logger.debug("{} successfully removed", systemName); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = SYSTEM_REGISTRY_QUERY_DESCRIPTION, response = SystemQueryResultDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_CLIENT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = SYSTEM_REGISTRY_QUERY_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = SYSTEM_REGISTRY_QUERY_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(path = CommonConstants.OP_SYSTEM_REGISTRY_QUERY_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public SystemQueryResultDTO queryRegistry(@RequestBody final SystemQueryFormDTO form) { + logger.debug("System query request received"); + + validation.checkSystemNameRequirements(form.getSystemNameRequirements(), getOrigin(CommonConstants.OP_SYSTEM_REGISTRY_QUERY_URI)); + + final SystemQueryResultDTO result = systemRegistryDBService.queryRegistry(form); + logger.debug("Return {} providers for system {}", result.getSystemQueryData().size(), form.getSystemNameRequirements()); + + return result; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = SYSTEM_REGISTRY_QUERY_BY_SYSTEM_ID_DESCRIPTION, response = SystemResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_PRIVATE}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = SYSTEM_REGISTRY_QUERY_BY_SYSTEM_ID_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = SYSTEM_REGISTRY_QUERY_BY_SYSTEM_ID_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = CoreCommonConstants.OP_SYSTEM_REGISTRY_QUERY_BY_SYSTEM_ID_URI, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public SystemResponseDTO queryRegistryBySystemId(@PathVariable(value = PATH_VARIABLE_ID) final long systemId) { + logger.debug("System query by system id request received"); + + final SystemResponseDTO result = systemRegistryDBService.getSystemById(systemId); + + logger.debug("Return system by id: {}", systemId); + return result; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = SYSTEM_REGISTRY_QUERY_BY_SYSTEM_DTO_DESCRIPTION, response = SystemResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_PRIVATE}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = SYSTEM_REGISTRY_QUERY_BY_SYSTEM_DTO_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = SYSTEM_REGISTRY_QUERY_BY_SYSTEM_DTO_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(path = CoreCommonConstants.OP_SYSTEM_REGISTRY_QUERY_BY_SYSTEM_DTO_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public SystemResponseDTO queryRegistryBySystemDTO(@RequestBody final SystemRequestDTO request) { + logger.debug("System query by systemRequestDTO request received"); + + validation.checkSystemRequest(request, CommonConstants.SYSTEM_REGISTRY_URI + CoreCommonConstants.OP_SYSTEM_REGISTRY_QUERY_BY_SYSTEM_ID_URI, false); + + final String systemName = request.getSystemName(); + final String address = request.getAddress(); + final int port = request.getPort(); + + final SystemResponseDTO result = systemRegistryDBService.getSystemDtoByNameAndAddressAndPort(systemName, address, port); + + logger.debug("Return system by name: {}, address: {}, port: {}", systemName, address, port); + return result; + } + + //================================================================================================= + // assistant methods + + + //================================================================================================= + // assistant methods + private String getBaseOrigin() { + return CommonConstants.SYSTEM_REGISTRY_URI; + } + + private String getOrigin(final String postfix) { + Assert.notNull(postfix, "Internal error: Origin postfix not provided"); + return getBaseOrigin() + postfix; + } + +} \ No newline at end of file diff --git a/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryMain.java b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryMain.java new file mode 100644 index 000000000..40c635956 --- /dev/null +++ b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryMain.java @@ -0,0 +1,28 @@ +package eu.arrowhead.core.systemregistry; + + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.database.repository.RefreshableRepositoryImpl; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@SpringBootApplication(scanBasePackages = CommonConstants.BASE_PACKAGE) +@EntityScan(CoreCommonConstants.DATABASE_ENTITY_PACKAGE) +@EnableJpaRepositories(basePackages = CoreCommonConstants.DATABASE_REPOSITORY_PACKAGE, repositoryBaseClass = RefreshableRepositoryImpl.class) +@EnableSwagger2 +public class SystemRegistryMain +{ + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public static void main(final String[] args) { + SpringApplication.run(SystemRegistryMain.class, args); + } +} diff --git a/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryManagementController.java b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryManagementController.java new file mode 100644 index 000000000..7042fcb8b --- /dev/null +++ b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryManagementController.java @@ -0,0 +1,514 @@ +package eu.arrowhead.core.systemregistry; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.CoreDefaults; +import eu.arrowhead.common.CoreUtilities; +import eu.arrowhead.common.Defaults; +import eu.arrowhead.common.dto.internal.DeviceListResponseDTO; +import eu.arrowhead.common.dto.internal.SystemListResponseDTO; +import eu.arrowhead.common.dto.internal.SystemRegistryListResponseDTO; +import eu.arrowhead.common.dto.shared.DeviceRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryRequestDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.core.systemregistry.database.service.SystemRegistryDBService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +@Api(tags = {CoreCommonConstants.SWAGGER_TAG_ALL}) +@CrossOrigin(maxAge = Defaults.CORS_MAX_AGE, allowCredentials = Defaults.CORS_ALLOW_CREDENTIALS, + allowedHeaders = {HttpHeaders.ORIGIN, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT, HttpHeaders.AUTHORIZATION} +) +@RestController +@RequestMapping(CommonConstants.SYSTEM_REGISTRY_URI + CoreCommonConstants.MGMT_URI) +public class SystemRegistryManagementController { + + //================================================================================================= + // members + + private static final String GET_SYSTEM_BY_ID_HTTP_200_MESSAGE = "System by requested id returned"; + private static final String GET_SYSTEM_BY_ID_HTTP_400_MESSAGE = "No Such System by requested id"; + private static final String PATH_VARIABLE_ID = "id"; + private static final String SYSTEM_BY_ID_URI = "/system/{" + PATH_VARIABLE_ID + "}"; + private static final String SYSTEMS_URI = "/systems"; + private static final String SYSTEMS_BY_ID_URI = "/systems/{" + PATH_VARIABLE_ID + "}"; + private static final String GET_SYSTEMS_HTTP_200_MESSAGE = "Systems returned"; + private static final String GET_SYSTEMS_HTTP_400_MESSAGE = " Invalid parameters"; + private static final String POST_SYSTEM_HTTP_201_MESSAGE = "System created"; + private static final String POST_SYSTEM_HTTP_400_MESSAGE = "Could not create system"; + private static final String PUT_SYSTEM_HTTP_200_MESSAGE = "System updated"; + private static final String PUT_SYSTEM_HTTP_400_MESSAGE = "Could not update system"; + private static final String PATCH_SYSTEM_HTTP_200_MESSAGE = "System updated"; + private static final String PATCH_SYSTEM_HTTP_400_MESSAGE = "Could not update system"; + private static final String DELETE_SYSTEM_HTTP_200_MESSAGE = "System deleted"; + private static final String DELETE_SYSTEM_HTTP_400_MESSAGE = "Could not delete system"; + + private static final String GET_DEVICE_BY_ID_HTTP_200_MESSAGE = "Device by requested id returned"; + private static final String GET_DEVICE_BY_ID_HTTP_400_MESSAGE = "No Such Device by requested id"; + private static final String DEVICE_BY_ID_URI = "/device/{" + PATH_VARIABLE_ID + "}"; + private static final String DEVICES_URI = "/devices"; + private static final String POST_DEVICE_HTTP_201_MESSAGE = "Device created"; + private static final String POST_DEVICE_HTTP_400_MESSAGE = "Could not create device"; + private static final String PUT_DEVICE_HTTP_200_MESSAGE = "Device updated"; + private static final String PUT_DEVICE_HTTP_400_MESSAGE = "Could not update device"; + + private static final String DELETE_SYSTEMS_HTTP_200_MESSAGE = "System definition removed"; + private static final String DELETE_SYSTEMS_HTTP_400_MESSAGE = "Could not remove system definition"; + + private static final String SYSTEM_REGISTRY_UPDATE_DESCRIPTION = "Update a system"; + private static final String SYSTEM_REGISTRY_UPDATE_200_MESSAGE = "System updated"; + private static final String SYSTEM_REGISTRY_UPDATE_400_MESSAGE = "Could not update system"; + private static final String SYSTEM_REGISTRY_MERGE_DESCRIPTION = "Merge/Patch a system"; + private static final String SYSTEM_REGISTRY_MERGE_200_MESSAGE = "System merged"; + private static final String SYSTEM_REGISTRY_MERGE_400_MESSAGE = "Could not merge system"; + + private static final String SYSTEM_REGISTRY_MGMT_BY_ID_URI = "/{" + PATH_VARIABLE_ID + "}"; + private static final String PATH_VARIABLE_SYSTEM_NAME = "systemName"; + private static final String SYSTEM_REGISTRY_MGMT_BY_SYSTEM_NAME_URI = "/systemname" + "/{" + PATH_VARIABLE_SYSTEM_NAME + "}"; + private static final String GET_SYSTEM_REGISTRY_HTTP_200_MESSAGE = "System Registry entries returned"; + private static final String GET_SYSTEM_REGISTRY_HTTP_400_MESSAGE = "Could not retrieve system registry entries"; + private static final String DELETE_SYSTEM_REGISTRY_HTTP_200_MESSAGE = "System Registry entry removed"; + private static final String DELETE_SYSTEM_REGISTRY_HTTP_400_MESSAGE = "Could not remove system registry entry"; + + private final Logger logger = LogManager.getLogger(SystemRegistryManagementController.class); + + private final SystemRegistryDBService systemRegistryDBService; + private final Validation validation; + + @Autowired + public SystemRegistryManagementController(final SystemRegistryDBService systemRegistryDBService) { + this.systemRegistryDBService = systemRegistryDBService; + this.validation = new Validation(); + } + + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return system by id", response = SystemResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_SYSTEM_BY_ID_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_SYSTEM_BY_ID_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(SYSTEM_BY_ID_URI) + @ResponseBody + public SystemResponseDTO getSystemById(@PathVariable(value = PATH_VARIABLE_ID) final long systemId) { + logger.debug("getSystemById started ..."); + + validation.checkId(systemId, getOrigin(SYSTEM_BY_ID_URI)); + + return systemRegistryDBService.getSystemById(systemId); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return systems by request parameters", response = SystemListResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_SYSTEMS_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_SYSTEMS_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(SYSTEMS_URI) + @ResponseBody + public SystemListResponseDTO getSystems( + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_PAGE, required = false) final Integer page, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_ITEM_PER_PAGE, required = false) final Integer size, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_DIRECTION, defaultValue = CoreDefaults.DEFAULT_REQUEST_PARAM_DIRECTION_VALUE) final String direction, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_SORT_FIELD, defaultValue = CoreCommonConstants.COMMON_FIELD_NAME_ID) final String sortField) { + logger.debug("getSystems started ..."); + + final CoreUtilities.ValidatedPageParams pageParameters = CoreUtilities + .validatePageParameters(page, size, direction, CommonConstants.SYSTEM_REGISTRY_URI + DEVICES_URI); + return systemRegistryDBService.getSystemEntries(pageParameters, sortField); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return created system", response = SystemResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_CREATED, message = POST_SYSTEM_HTTP_201_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = POST_SYSTEM_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(path = SYSTEMS_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(org.springframework.http.HttpStatus.CREATED) + @ResponseBody + public SystemResponseDTO addSystem(@RequestBody final SystemRequestDTO request) { + return callCreateSystem(request); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return updated system", response = SystemResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_CREATED, message = PUT_SYSTEM_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = PUT_SYSTEM_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PutMapping(path = SYSTEMS_BY_ID_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public SystemResponseDTO updateSystem(@PathVariable(value = PATH_VARIABLE_ID) final long systemId, @RequestBody final SystemRequestDTO request) { + return callUpdateSystem(request, systemId); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return system updated by fields", response = SystemResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_CREATED, message = PATCH_SYSTEM_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = PATCH_SYSTEM_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PatchMapping(path = SYSTEMS_BY_ID_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public SystemResponseDTO mergeSystem(@PathVariable(value = PATH_VARIABLE_ID) final long systemId, @RequestBody final SystemRequestDTO request) { + return callMergeSystem(request, systemId); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Remove system", tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = DELETE_SYSTEM_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DELETE_SYSTEM_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @DeleteMapping(path = SYSTEMS_BY_ID_URI) + public void removeSystem(@PathVariable(value = PATH_VARIABLE_ID) final long systemId) { + logger.debug("New System delete request received with id: {}", systemId); + + validation.checkId(systemId, getOrigin(SYSTEM_BY_ID_URI)); + + systemRegistryDBService.removeSystemById(systemId); + logger.debug("System with id: '{}' successfully deleted", systemId); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return device by id", response = DeviceResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_DEVICE_BY_ID_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_DEVICE_BY_ID_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(SYSTEMS_BY_ID_URI) + @ResponseBody + public DeviceResponseDTO getDeviceById(@PathVariable(value = PATH_VARIABLE_ID) final long deviceId) { + logger.debug("getDeviceById started ..."); + + validation.checkId(deviceId, getOrigin(SYSTEM_BY_ID_URI)); + + return systemRegistryDBService.getDeviceById(deviceId); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return requested device by the given parameters", response = DeviceListResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_SYSTEMS_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_SYSTEMS_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = DEVICES_URI, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public DeviceListResponseDTO getDeviceListByRequestParameters( + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_PAGE, required = false) final Integer page, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_ITEM_PER_PAGE, required = false) final Integer size, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_DIRECTION, defaultValue = CoreDefaults.DEFAULT_REQUEST_PARAM_DIRECTION_VALUE) final String direction, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_SORT_FIELD, defaultValue = CoreCommonConstants.COMMON_FIELD_NAME_ID) final String sortField) { + logger.debug("New DeviceList get request received with page: {} and item_per page: {}", page, size); + + final CoreUtilities.ValidatedPageParams pageParameters = CoreUtilities + .validatePageParameters(page, size, direction, CommonConstants.SYSTEM_REGISTRY_URI + DEVICES_URI); + final DeviceListResponseDTO deviceListResponseDTO = systemRegistryDBService.getDeviceEntries(pageParameters, sortField); + logger.debug("DeviceList with page: {} and item_per page: {} successfully retrieved", page, size); + + return deviceListResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return created device", response = DeviceResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_CREATED, message = POST_DEVICE_HTTP_201_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = POST_DEVICE_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PostMapping(path = DEVICES_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseStatus(value = org.springframework.http.HttpStatus.CREATED) + @ResponseBody + public DeviceResponseDTO addDevice(@RequestBody final DeviceRequestDTO dto) { + logger.debug("New device registration request received with name: {}", dto.getDeviceName()); + + validation.validateDevice(dto, DEVICES_URI); + + final DeviceResponseDTO responseDTO = systemRegistryDBService + .createDeviceDto(dto.getDeviceName(), dto.getAddress(), dto.getMacAddress(), dto.getAuthenticationInfo()); + logger.debug("{} successfully registered.", responseDTO); + + return responseDTO; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return updated device", response = DeviceResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = PUT_DEVICE_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = PUT_DEVICE_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PutMapping(path = DEVICE_BY_ID_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public DeviceResponseDTO putUpdateDevice(@PathVariable(value = PATH_VARIABLE_ID) final long id, + @RequestBody final DeviceRequestDTO dto) { + logger.debug("New device update request received with id: {}, definition: {}", id, dto); + + validation.checkId(id, getOrigin(DEVICE_BY_ID_URI)); + validation.validateDevice(dto, getOrigin(DEVICE_BY_ID_URI)); + + final DeviceResponseDTO deviceResponseDTO = systemRegistryDBService + .updateDeviceByIdResponse(id, dto.getDeviceName(), dto.getAddress(), dto.getMacAddress(), dto.getAuthenticationInfo()); + logger.debug("Device with id: '{}' successfully updated with definition '{}'.", id, deviceResponseDTO); + + return deviceResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Remove device", tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = DELETE_SYSTEMS_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DELETE_SYSTEMS_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @DeleteMapping(path = DEVICE_BY_ID_URI) + public void removeDevice(@PathVariable(value = PATH_VARIABLE_ID) final long id) { + logger.debug("New System Definition delete request received with id: {}", id); + + validation.checkId(id, getOrigin(DEVICE_BY_ID_URI)); + + systemRegistryDBService.removeDeviceById(id); + logger.debug("Device with id: '{}' successfully deleted", id); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return requested system registry entries by the given parameters", response = SystemRegistryListResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_SYSTEM_REGISTRY_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_SYSTEM_REGISTRY_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = CoreCommonConstants.MGMT_URI) + @ResponseBody + public SystemRegistryListResponseDTO getSystemRegistryEntries( + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_PAGE, required = false) final Integer page, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_ITEM_PER_PAGE, required = false) final Integer size, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_DIRECTION, defaultValue = CoreDefaults.DEFAULT_REQUEST_PARAM_DIRECTION_VALUE) final String direction, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_SORT_FIELD, defaultValue = CoreCommonConstants.COMMON_FIELD_NAME_ID) final String sortField) { + logger.debug("New System Registry get request received with page: {} and item_per page: {}", page, size); + + final CoreUtilities.ValidatedPageParams params = CoreUtilities + .validatePageParameters(page, size, direction, CommonConstants.SYSTEM_REGISTRY_URI + CoreCommonConstants.MGMT_URI); + final SystemRegistryListResponseDTO systemRegistryEntriesResponse = systemRegistryDBService + .getSystemRegistryEntries(params, sortField); + logger.debug("System Registry entries with page: {} and item_per page: {} successfully retrieved", page, size); + + return systemRegistryEntriesResponse; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return requested system registry entry", response = SystemRegistryResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_SYSTEM_REGISTRY_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_SYSTEM_REGISTRY_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = SYSTEM_REGISTRY_MGMT_BY_ID_URI) + @ResponseBody + public SystemRegistryResponseDTO getSystemRegistryEntryById(@PathVariable(value = PATH_VARIABLE_ID) final long id) { + logger.debug("New System Registry get request received with id: {}", id); + + validation.checkId(id, getOrigin(SYSTEM_REGISTRY_MGMT_BY_ID_URI)); + + final SystemRegistryResponseDTO systemRegistryEntryByIdResponse = systemRegistryDBService.getSystemRegistryById(id); + logger.debug("System Registry entry with id: {} successfully retrieved", id); + + return systemRegistryEntryByIdResponse; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Return requested system registry entries by system definition based on the given parameters", response = SystemRegistryListResponseDTO.class, + tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = GET_SYSTEM_REGISTRY_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = GET_SYSTEM_REGISTRY_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @GetMapping(path = SYSTEM_REGISTRY_MGMT_BY_SYSTEM_NAME_URI) + @ResponseBody + public SystemRegistryListResponseDTO getSystemRegistryEntriesBySystemName( + @PathVariable(value = PATH_VARIABLE_SYSTEM_NAME) final String systemName, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_PAGE, required = false) final Integer page, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_ITEM_PER_PAGE, required = false) final Integer size, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_DIRECTION, defaultValue = CoreDefaults.DEFAULT_REQUEST_PARAM_DIRECTION_VALUE) final String direction, + @RequestParam(name = CoreCommonConstants.REQUEST_PARAM_SORT_FIELD, defaultValue = CoreCommonConstants.COMMON_FIELD_NAME_ID) final String sortField) { + logger.debug("New System Registry get by System Definition request received with page: {} and item_per page: {}", page, size); + + final String origin = CommonConstants.SYSTEM_REGISTRY_URI + SYSTEM_REGISTRY_MGMT_BY_SYSTEM_NAME_URI; + validation.checkSystemName(systemName, origin); + + final CoreUtilities.ValidatedPageParams pageParameters = CoreUtilities.validatePageParameters(page, size, direction, origin); + final SystemRegistryListResponseDTO systemRegistryEntries = systemRegistryDBService + .getSystemRegistryEntriesBySystemName(systemName, pageParameters, sortField); + logger.debug("System Registry entries with page: {} and item_per page: {} successfully retrieved", page, size); + + return systemRegistryEntries; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = "Remove the specified system registry entry", tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = DELETE_SYSTEM_REGISTRY_HTTP_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = DELETE_SYSTEM_REGISTRY_HTTP_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @DeleteMapping(path = SYSTEM_REGISTRY_MGMT_BY_ID_URI) + public void removeSystemRegistryEntryById(@PathVariable(value = PATH_VARIABLE_ID) final long id) { + logger.debug("New System Registry delete request received with id: {}", id); + + validation.checkId(id, SYSTEM_REGISTRY_MGMT_BY_ID_URI); + + systemRegistryDBService.removeSystemRegistryEntryById(id); + logger.debug("System Registry with id: '{}' successfully deleted", id); + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = SYSTEM_REGISTRY_UPDATE_DESCRIPTION, response = SystemRegistryResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = SYSTEM_REGISTRY_UPDATE_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = SYSTEM_REGISTRY_UPDATE_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PutMapping(path = SYSTEM_REGISTRY_MGMT_BY_ID_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody + SystemRegistryResponseDTO updateSystemRegistry(@PathVariable(value = PATH_VARIABLE_ID) final long id, @RequestBody final SystemRegistryRequestDTO request) { + logger.debug("New system registry update request received"); + validation.checkSystemRegistryUpdateRequest(id, request, SYSTEM_REGISTRY_MGMT_BY_ID_URI); + + final SystemRegistryResponseDTO response = systemRegistryDBService.updateSystemRegistryById(id, request); + logger.debug("System Registry entry {} is successfully updated with system {} and system {}", id, request.getSystem().getSystemName(), + request.getSystem()); + + return response; + } + + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = SYSTEM_REGISTRY_MERGE_DESCRIPTION, response = SystemRegistryResponseDTO.class, tags = {CoreCommonConstants.SWAGGER_TAG_MGMT}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_OK, message = SYSTEM_REGISTRY_MERGE_200_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = SYSTEM_REGISTRY_MERGE_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @PatchMapping(path = SYSTEM_REGISTRY_MGMT_BY_ID_URI, consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public @ResponseBody + SystemRegistryResponseDTO mergeSystemRegistry(@PathVariable(value = PATH_VARIABLE_ID) final long id, @RequestBody final SystemRegistryRequestDTO request) { + logger.debug("New system registry merge request received"); + validation.checkSystemRegistryMergeRequest(id, request, CoreCommonConstants.MGMT_URI); + + final SystemRegistryResponseDTO response = systemRegistryDBService.mergeSystemRegistryById(id, request); + logger.debug("System Registry entry {} is successfully merged witch system {} and system {}", id, response.getSystem(), request.getSystem()); + + return response; + } + + //================================================================================================= + // assistant methods + + //------------------------------------------------------------------------------------------------- + private SystemResponseDTO callCreateSystem(final SystemRequestDTO request) { + logger.debug("callCreateSystem started..."); + + validation.checkSystemRequest(request, getOrigin(SYSTEMS_URI), true); + + final String systemName = request.getSystemName(); + final String address = request.getAddress(); + final int port = request.getPort(); + final String authenticationInfo = request.getAuthenticationInfo(); + + return systemRegistryDBService.createSystemDto(systemName, address, port, authenticationInfo); + } + + //------------------------------------------------------------------------------------------------- + private SystemResponseDTO callUpdateSystem(final SystemRequestDTO request, final long systemId) { + logger.debug("callUpdateSystem started..."); + + validation.checkSystemPutRequest(request, systemId, getOrigin(SYSTEMS_URI)); + + final String validatedSystemName = request.getSystemName().toLowerCase(); + final String validatedAddress = request.getAddress().toLowerCase(); + final int validatedPort = request.getPort(); + final String validatedAuthenticationInfo = request.getAuthenticationInfo(); + + return systemRegistryDBService.updateSystemDto(systemId, validatedSystemName, validatedAddress, validatedPort, validatedAuthenticationInfo); + } + + //------------------------------------------------------------------------------------------------- + private SystemResponseDTO callMergeSystem(final SystemRequestDTO request, final long systemId) { + logger.debug("callMergeSystem started..."); + + validation.checkSystemMergeRequest(request, systemId, getOrigin(SYSTEMS_URI)); + + final String validatedSystemName = request.getSystemName() != null ? request.getSystemName().toLowerCase() : ""; + final String validatedAddress = request.getAddress() != null ? request.getAddress().toLowerCase() : ""; + final Integer validatedPort = request.getPort(); + final String validatedAuthenticationInfo = request.getAuthenticationInfo(); + + return systemRegistryDBService.mergeSystemResponse(systemId, validatedSystemName, validatedAddress, validatedPort, validatedAuthenticationInfo); + } + + //================================================================================================= + // assistant methods + private String getBaseOrigin() { + return CommonConstants.SYSTEM_REGISTRY_URI + CoreCommonConstants.MGMT_URI; + } + + private String getOrigin(final String postfix) { + Assert.notNull(postfix, "Internal error: Origin postfix not provided"); + return getBaseOrigin() + postfix; + } +} \ No newline at end of file diff --git a/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryOnboardingController.java b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryOnboardingController.java new file mode 100644 index 000000000..5b3bc5ca3 --- /dev/null +++ b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/SystemRegistryOnboardingController.java @@ -0,0 +1,126 @@ +package eu.arrowhead.core.systemregistry; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.Defaults; +import eu.arrowhead.common.dto.shared.SystemRegistryOnboardingWithCsrRequestDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryOnboardingWithCsrResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryOnboardingWithNameRequestDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryOnboardingWithNameResponseDTO; +import eu.arrowhead.core.systemregistry.database.service.SystemRegistryDBService; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpHeaders; +import org.springframework.http.MediaType; +import org.springframework.util.Assert; +import org.springframework.web.bind.annotation.CrossOrigin; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import javax.servlet.http.HttpServletRequest; + +@Api(tags = {CoreCommonConstants.SWAGGER_TAG_ALL}) +@CrossOrigin(maxAge = Defaults.CORS_MAX_AGE, allowCredentials = Defaults.CORS_ALLOW_CREDENTIALS, + allowedHeaders = {HttpHeaders.ORIGIN, HttpHeaders.CONTENT_TYPE, HttpHeaders.ACCEPT, HttpHeaders.AUTHORIZATION} +) +@RestController +@RequestMapping(CommonConstants.SYSTEM_REGISTRY_URI + CommonConstants.ONBOARDING_URI) +public class SystemRegistryOnboardingController { + + //================================================================================================= + // members + + private static final String SYSTEM_REGISTRY_REGISTER_DESCRIPTION = "Registers a system"; + private static final String SYSTEM_REGISTRY_REGISTER_201_MESSAGE = "System registered"; + private static final String SYSTEM_REGISTRY_REGISTER_400_MESSAGE = "Could not register system"; + + private final Logger logger = LogManager.getLogger(SystemRegistryOnboardingController.class); + + private final SystemRegistryDBService systemRegistryDBService; + private final Validation validation; + + @Autowired + public SystemRegistryOnboardingController(final SystemRegistryDBService systemRegistryDBService) { + this.systemRegistryDBService = systemRegistryDBService; + this.validation = new Validation(); + } + + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = SYSTEM_REGISTRY_REGISTER_DESCRIPTION, response = SystemRegistryOnboardingWithNameResponseDTO.class, tags = + {CoreCommonConstants.SWAGGER_TAG_CLIENT, CoreCommonConstants.SWAGGER_TAG_ONBOARDING}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_CREATED, message = SYSTEM_REGISTRY_REGISTER_201_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = SYSTEM_REGISTRY_REGISTER_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @ResponseStatus(value = org.springframework.http.HttpStatus.CREATED) + @PostMapping(path = CommonConstants.OP_SYSTEM_REGISTRY_ONBOARDING_WITH_NAME_URI, + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public SystemRegistryOnboardingWithNameResponseDTO onboardDevice(final HttpServletRequest httpServletRequest, + @RequestBody final SystemRegistryOnboardingWithNameRequestDTO request) { + logger.debug("New onboarding with name and system registration request received"); + validation.checkOnboardingRequest(request, getOrigin(CommonConstants.OP_SYSTEM_REGISTRY_ONBOARDING_WITH_NAME_URI)); + + final String host = httpServletRequest.getRemoteHost(); + final String address = httpServletRequest.getRemoteAddr(); + final var response = systemRegistryDBService.onboardAndRegisterSystemRegistry(request, host, address); + logger.debug("{} successfully registers its system {}", request.getSystem().getSystemName(), request.getSystem()); + + return response; + } + + //------------------------------------------------------------------------------------------------- + @ApiOperation(value = SYSTEM_REGISTRY_REGISTER_DESCRIPTION, response = SystemRegistryOnboardingWithCsrResponseDTO.class, tags = + {CoreCommonConstants.SWAGGER_TAG_CLIENT, CoreCommonConstants.SWAGGER_TAG_ONBOARDING}) + @ApiResponses(value = { + @ApiResponse(code = HttpStatus.SC_CREATED, message = SYSTEM_REGISTRY_REGISTER_201_MESSAGE), + @ApiResponse(code = HttpStatus.SC_BAD_REQUEST, message = SYSTEM_REGISTRY_REGISTER_400_MESSAGE), + @ApiResponse(code = HttpStatus.SC_UNAUTHORIZED, message = CoreCommonConstants.SWAGGER_HTTP_401_MESSAGE), + @ApiResponse(code = HttpStatus.SC_INTERNAL_SERVER_ERROR, message = CoreCommonConstants.SWAGGER_HTTP_500_MESSAGE) + }) + @ResponseStatus(value = org.springframework.http.HttpStatus.CREATED) + @PostMapping(path = CommonConstants.OP_SYSTEM_REGISTRY_ONBOARDING_WITH_CSR_URI, + consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + @ResponseBody + public SystemRegistryOnboardingWithCsrResponseDTO onboardDevice(@RequestBody final SystemRegistryOnboardingWithCsrRequestDTO request) { + logger.debug("New onboarding with csr and system registration request received"); + validation.checkOnboardingRequest(request, getOrigin(CommonConstants.OP_SYSTEM_REGISTRY_ONBOARDING_WITH_CSR_URI)); + + final var response = systemRegistryDBService.onboardAndRegisterSystemRegistry(request); + logger.debug("{} successfully registers its system {}", request.getSystem().getSystemName(), request.getSystem()); + + return response; + } + + //================================================================================================= + // assistant methods + + + //================================================================================================= + // assistant methods + private String getBaseOrigin() { + return CommonConstants.SYSTEM_REGISTRY_URI + CommonConstants.ONBOARDING_URI; + } + + private String getOrigin(final String postfix) { + Assert.notNull(postfix, "Internal error: Origin postfix not provided"); + return getBaseOrigin() + postfix; + } + +} \ No newline at end of file diff --git a/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/Validation.java b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/Validation.java new file mode 100644 index 000000000..775ed7e7a --- /dev/null +++ b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/Validation.java @@ -0,0 +1,318 @@ +package eu.arrowhead.core.systemregistry; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.core.CoreSystem; +import eu.arrowhead.common.dto.shared.DeviceRequestDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryOnboardingWithCsrRequestDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryOnboardingWithNameRequestDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryRequestDTO; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; +import eu.arrowhead.common.exception.BadPayloadException; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.RequestBody; + +import java.time.format.DateTimeParseException; +import java.util.Objects; + +public class Validation { + + private static final String ID_NOT_VALID_ERROR_MESSAGE = "Id must be greater than 0. "; + private static final String SYSTEM_NAME_NULL_ERROR_MESSAGE = " System name must have value "; + private static final String SYSTEM_ADDRESS_NULL_ERROR_MESSAGE = " System address must have value "; + private static final String SYSTEM_PORT_NULL_ERROR_MESSAGE = " System port must have value "; + + private static final String DEVICE_NAME_NULL_ERROR_MESSAGE = " Device name must have value "; + private static final String DEVICE_ADDRESS_NULL_ERROR_MESSAGE = " Device address must have value "; + private static final String DEVICE_MAC_ADDRESS_NULL_ERROR_MESSAGE = " Device MAC address must have value "; + + private final Logger logger = LogManager.getLogger(); + + public Validation() { super(); } + + //------------------------------------------------------------------------------------------------- + void checkSystemNameRequirements(final String systemNameRequirements, final String origin) { + + if (Utilities.isEmpty(systemNameRequirements)) { + throw new BadPayloadException("System definition requirement is null or blank", HttpStatus.SC_BAD_REQUEST, origin); + } + + } + + //------------------------------------------------------------------------------------------------- + void checkId(final long systemId, final String origin) { + if (systemId < 1) { + throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + } + + //------------------------------------------------------------------------------------------------- + void checkSystemMergeRequest(final SystemRequestDTO request, final long systemId, final String origin) { + logger.debug("checkSystemPatchRequest started..."); + + if (systemId <= 0) { + throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + boolean needChange = false; + if (!Utilities.isEmpty(request.getAddress())) { + needChange = true; + } + + + if (!Utilities.isEmpty(request.getSystemName())) { + needChange = true; + for (final CoreSystem coreSysteam : CoreSystem.values()) { + if (coreSysteam.name().equalsIgnoreCase(request.getSystemName().trim())) { + throw new BadPayloadException("System name '" + request.getSystemName() + "' is a reserved arrowhead core system name.", + HttpStatus.SC_BAD_REQUEST, origin); + } + } + } + + if (request.getPort() != null) { + final int validatedPort = request.getPort(); + if (validatedPort < CommonConstants.SYSTEM_PORT_RANGE_MIN || validatedPort > CommonConstants.SYSTEM_PORT_RANGE_MAX) { + throw new BadPayloadException( + "Port must be between " + CommonConstants.SYSTEM_PORT_RANGE_MIN + " and " + CommonConstants.SYSTEM_PORT_RANGE_MAX + ".", + HttpStatus.SC_BAD_REQUEST, + origin); + } + + needChange = true; + } + + if (request.getAuthenticationInfo() != null) { + needChange = true; + } + + if (!needChange) { + throw new BadPayloadException("Patch request is empty.", HttpStatus.SC_BAD_REQUEST, origin); + } + } + + //------------------------------------------------------------------------------------------------- + void checkOnboardingRequest(final SystemRegistryOnboardingWithNameRequestDTO request, final String origin) { + logger.debug("checkOnboardingRequest started..."); + if (request == null) { + throw new BadPayloadException("Request is null.", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (request.getCertificateCreationRequest() == null) { + throw new BadPayloadException("Certificate creation request is null.", HttpStatus.SC_BAD_REQUEST, origin); + } + + checkSystemRegistryRequest(request, origin, true); + } + + //------------------------------------------------------------------------------------------------- + void checkOnboardingRequest(final SystemRegistryOnboardingWithCsrRequestDTO request, final String origin) { + logger.debug("checkOnboardingRequest started..."); + if (request == null) { + throw new BadPayloadException("Request is null.", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (request.getCertificateSigningRequest() == null) { + throw new BadPayloadException("Certificate signing request is null.", HttpStatus.SC_BAD_REQUEST, origin); + } + + checkSystemRegistryRequest(request, origin, true); + } + + //------------------------------------------------------------------------------------------------- + void checkSystemPutRequest(final SystemRequestDTO request, final long systemId, final String origin) { + logger.debug("checkSystemPutRequest started..."); + + if (systemId <= 0) { + throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + checkSystemRequest(request, origin, true); + } + + //------------------------------------------------------------------------------------------------- + void checkSystemRequest(final SystemRequestDTO request, final String origin, final boolean checkReservedCoreSystemNames) { + logger.debug("checkSystemRequest started..."); + + if (request == null) { + throw new BadPayloadException("System is null.", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(request.getSystemName())) { + throw new BadPayloadException(SYSTEM_NAME_NULL_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (checkReservedCoreSystemNames) { + for (final CoreSystem coreSysteam : CoreSystem.values()) { + if (coreSysteam.name().equalsIgnoreCase(request.getSystemName().trim())) { + throw new BadPayloadException("System name '" + request.getSystemName() + "' is a reserved arrowhead core system name.", + HttpStatus.SC_BAD_REQUEST, origin); + } + } + } + + if (Utilities.isEmpty(request.getAddress())) { + throw new BadPayloadException(SYSTEM_ADDRESS_NULL_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (request.getPort() == null) { + throw new BadPayloadException(SYSTEM_PORT_NULL_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + final int validatedPort = request.getPort(); + if (validatedPort <= CommonConstants.SYSTEM_PORT_RANGE_MIN || validatedPort > CommonConstants.SYSTEM_PORT_RANGE_MAX) { + throw new BadPayloadException( + "Port must be between " + CommonConstants.SYSTEM_PORT_RANGE_MIN + " and " + CommonConstants.SYSTEM_PORT_RANGE_MAX + ".", + HttpStatus.SC_BAD_REQUEST, origin); + } + } + + //------------------------------------------------------------------------------------------------- + void checkDeviceRequest(final DeviceRequestDTO request, final String origin) { + logger.debug("checkDeviceRequest started..."); + + if (request == null) { + throw new BadPayloadException("Device is null.", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(request.getDeviceName())) { + throw new BadPayloadException(DEVICE_NAME_NULL_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(request.getAddress())) { + throw new BadPayloadException(DEVICE_ADDRESS_NULL_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + if (Utilities.isEmpty(request.getMacAddress())) { + throw new BadPayloadException(DEVICE_MAC_ADDRESS_NULL_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + if (!Utilities.isValidMacAddress(request.getMacAddress())) { + throw new BadPayloadException("Unrecognized format of MAC Address", HttpStatus.SC_BAD_REQUEST, origin); + } + } + + //------------------------------------------------------------------------------------------------- + void checkSystemRegistryRequest(final SystemRegistryRequestDTO request, final String origin, final boolean checkReservedCoreSystemNames) { + logger.debug("checkSystemRegistryRequest started..."); + + checkSystemRequest(request.getSystem(), origin, checkReservedCoreSystemNames); + checkDeviceRequest(request.getProvider(), origin); + + if (!Utilities.isEmpty(request.getEndOfValidity())) { + try { + Utilities.parseUTCStringToLocalZonedDateTime(request.getEndOfValidity().trim()); + } catch (final DateTimeParseException ex) { + throw new BadPayloadException( + "End of validity is specified in the wrong format. Please provide UTC time using " + Utilities.getDatetimePattern() + " pattern.", + HttpStatus.SC_BAD_REQUEST, origin); + } + } + } + + //------------------------------------------------------------------------------------------------- + void checkSystemName(final String systemName, final String origin) { + if (Utilities.isEmpty(systemName)) { + throw new BadPayloadException("Name of the system is blank", HttpStatus.SC_BAD_REQUEST, origin); + } + } + + + //------------------------------------------------------------------------------------------------- + void checkUnregisterSystemParameters(final String systemName, final String address, final int port, final String origin) { + // parameters can't be null, but can be empty + logger.debug("checkUnregisterSystemParameters started..."); + + checkSystemName(systemName, origin); + + if (Utilities.isEmpty(address)) { + throw new BadPayloadException("Address of the system is blank", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (port < CommonConstants.SYSTEM_PORT_RANGE_MIN || port > CommonConstants.SYSTEM_PORT_RANGE_MAX) { + throw new BadPayloadException( + "Port must be between " + CommonConstants.SYSTEM_PORT_RANGE_MIN + " and " + CommonConstants.SYSTEM_PORT_RANGE_MAX + ".", + HttpStatus.SC_BAD_REQUEST, origin); + } + } + + //------------------------------------------------------------------------------------------------- + void checkSystemRegistryUpdateRequest(final long id, final SystemRegistryRequestDTO request, final String origin) { + logger.debug("checkSystemRegistryUpdateRequest started..."); + + if (id <= 0) { + throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + checkSystemRegistryRequest(request, origin, true); + + } + + //------------------------------------------------------------------------------------------------- + void validateDevice(@RequestBody final DeviceRequestDTO deviceRequestDto, final String origin) { + if (Utilities.isEmpty(deviceRequestDto.getDeviceName())) { + throw new BadPayloadException("Device name is null or blank", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(deviceRequestDto.getAddress())) { + throw new BadPayloadException("Device address is null or blank", HttpStatus.SC_BAD_REQUEST, origin); + } + + if (Utilities.isEmpty(deviceRequestDto.getMacAddress())) { + throw new BadPayloadException("Device MAC address is null or blank", HttpStatus.SC_BAD_REQUEST, origin); + } + } + + //------------------------------------------------------------------------------------------------- + @SuppressWarnings("squid:S3776") + void checkSystemRegistryMergeRequest(final long id, final SystemRegistryRequestDTO request, final String origin) { + logger.debug("checkSystemRegistryMergeRequest started..."); + + if (id <= 0) { + throw new BadPayloadException(ID_NOT_VALID_ERROR_MESSAGE, HttpStatus.SC_BAD_REQUEST, origin); + } + + boolean needChange = false; + + if (Objects.nonNull(request.getSystem())) { + final SystemRequestDTO system = request.getSystem(); + + if (!Utilities.isEmpty(system.getSystemName())) { + needChange = true; + } else if (!Utilities.isEmpty(system.getAddress())) { + needChange = true; + } else if (Objects.nonNull(system.getPort())) { + final int validatedPort = system.getPort(); + if (validatedPort < CommonConstants.SYSTEM_PORT_RANGE_MIN || validatedPort > CommonConstants.SYSTEM_PORT_RANGE_MAX) { + throw new BadPayloadException( + "Port must be between " + CommonConstants.SYSTEM_PORT_RANGE_MIN + " and " + CommonConstants.SYSTEM_PORT_RANGE_MAX + ".", + HttpStatus.SC_BAD_REQUEST, + origin); + } + + needChange = true; + } else if (Objects.nonNull(system.getAuthenticationInfo())) { + needChange = true; + } + } + + + if (request.getEndOfValidity() != null) { + needChange = true; + } + + if (request.getMetadata() != null) { + needChange = true; + } + + if (request.getVersion() != null && request.getVersion() > 0) { + needChange = true; + } + + if (!needChange) { + throw new BadPayloadException("Patch request is empty.", HttpStatus.SC_BAD_REQUEST, origin); + } + } +} diff --git a/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/database/service/SystemRegistryDBService.java b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/database/service/SystemRegistryDBService.java new file mode 100644 index 000000000..7de3553a4 --- /dev/null +++ b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/database/service/SystemRegistryDBService.java @@ -0,0 +1,1148 @@ +package eu.arrowhead.core.systemregistry.database.service; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.CoreUtilities; +import eu.arrowhead.common.SecurityUtilities; +import eu.arrowhead.common.Utilities; +import eu.arrowhead.common.database.entity.Device; +import eu.arrowhead.common.database.entity.System; +import eu.arrowhead.common.database.entity.SystemRegistry; +import eu.arrowhead.common.database.repository.DeviceRepository; +import eu.arrowhead.common.database.repository.SystemRegistryRepository; +import eu.arrowhead.common.database.repository.SystemRepository; +import eu.arrowhead.common.drivers.CertificateAuthorityDriver; +import eu.arrowhead.common.dto.internal.CertificateSigningRequestDTO; +import eu.arrowhead.common.dto.internal.DTOConverter; +import eu.arrowhead.common.dto.internal.DeviceListResponseDTO; +import eu.arrowhead.common.dto.internal.SystemListResponseDTO; +import eu.arrowhead.common.dto.internal.SystemRegistryListResponseDTO; +import eu.arrowhead.common.dto.shared.CertificateCreationRequestDTO; +import eu.arrowhead.common.dto.shared.CertificateCreationResponseDTO; +import eu.arrowhead.common.dto.shared.CertificateType; +import eu.arrowhead.common.dto.shared.DeviceRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceResponseDTO; +import eu.arrowhead.common.dto.shared.SystemQueryFormDTO; +import eu.arrowhead.common.dto.shared.SystemQueryResultDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryOnboardingWithCsrRequestDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryOnboardingWithCsrResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryOnboardingWithNameRequestDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryOnboardingWithNameResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryRequestDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.common.exception.ArrowheadException; +import eu.arrowhead.common.exception.BadPayloadException; +import eu.arrowhead.common.exception.InvalidParameterException; +import org.apache.http.HttpStatus; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.util.Assert; + +import java.io.IOException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.security.KeyPair; +import java.time.ZonedDateTime; +import java.time.format.DateTimeParseException; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +@Service +public class SystemRegistryDBService { + + //================================================================================================= + // members + + private static final String COULD_NOT_DELETE_SYSTEM_ERROR_MESSAGE = "Could not delete System, with given parameters"; + private static final String COULD_NOT_DELETE_DEVICE_ERROR_MESSAGE = "Could not delete Device, with given parameters"; + private static final String PORT_RANGE_ERROR_MESSAGE = "Port must be between " + CommonConstants.SYSTEM_PORT_RANGE_MIN + " and " + CommonConstants.SYSTEM_PORT_RANGE_MAX + "."; + + private final Logger logger = LogManager.getLogger(SystemRegistryDBService.class); + + private final SystemRegistryRepository systemRegistryRepository; + private final SystemRepository systemRepository; + private final DeviceRepository deviceRepository; + private final SecurityUtilities securityUtilities; + private final CertificateAuthorityDriver caDriver; + + @Value(CoreCommonConstants.$SYSTEM_REGISTRY_PING_TIMEOUT_WD) + private int pingTimeout; + + @Autowired + public SystemRegistryDBService(final SystemRegistryRepository systemRegistryRepository, + final SystemRepository systemRepository, + final DeviceRepository deviceRepository, + final SecurityUtilities securityUtilities, + final CertificateAuthorityDriver caDriver) { + this.systemRegistryRepository = systemRegistryRepository; + this.systemRepository = systemRepository; + this.deviceRepository = deviceRepository; + this.securityUtilities = securityUtilities; + this.caDriver = caDriver; + } + + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public SystemResponseDTO getSystemById(final long systemId) { + logger.debug("getSystemById started..."); + + try { + final Optional systemOption = systemRepository.findById(systemId); + if (systemOption.isEmpty()) { + throw new InvalidParameterException("System with id " + systemId + " not found."); + } + + return DTOConverter.convertSystemToSystemResponseDTO(systemOption.get()); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + + //------------------------------------------------------------------------------------------------- + public SystemListResponseDTO getSystemEntries(final CoreUtilities.ValidatedPageParams pageParams, final String sortField) { + logger.debug("getSystemEntries started..."); + + final int validatedPage = pageParams.getValidatedPage(); + final int validatedSize = pageParams.getValidatedSize(); + final Sort.Direction validatedDirection = pageParams.getValidatedDirection(); + final String validatedSortField = Utilities.isEmpty(sortField) ? CoreCommonConstants.COMMON_FIELD_NAME_ID : sortField.trim(); + + if (!System.SORTABLE_FIELDS_BY.contains(validatedSortField)) { + throw new InvalidParameterException("Sortable field with reference '" + validatedSortField + "' is not available"); + } + + try { + return DTOConverter.convertSystemEntryListToSystemListResponseDTO( + systemRepository.findAll(PageRequest.of(validatedPage, validatedSize, validatedDirection, validatedSortField))); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public SystemResponseDTO createSystemDto(final String systemName, final String address, final int port, final String authenticationInfo) { + logger.debug("createSystemResponse started..."); + + return DTOConverter.convertSystemToSystemResponseDTO(createSystem(systemName, address, port, authenticationInfo)); + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public SystemResponseDTO updateSystemDto(final long systemId, final String systemName, final String address, final int port, + final String authenticationInfo) { + logger.debug("updateSystemResponse started..."); + + return DTOConverter.convertSystemToSystemResponseDTO(updateSystem(systemId, systemName, address, port, authenticationInfo)); + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public System updateSystem(final long systemId, final String systemName, final String address, final int port, final String authenticationInfo) { + logger.debug("updateSystem started..."); + + final long validatedSystemId = validateId(systemId); + final int validatedPort = validateSystemPort(port); + final String validatedSystemName = validateParamString(systemName); + if (validatedSystemName.contains(".")) { + throw new InvalidParameterException("System name can't contain dot (.)"); + } + final String validatedAddress = validateParamString(address); + + try { + final Optional systemOptional = systemRepository.findById(validatedSystemId); + if (systemOptional.isEmpty()) { + throw new InvalidParameterException("No system with id : " + validatedSystemId); + } + + final System system = systemOptional.get(); + + if (checkSystemIfUniqueValidationNeeded(system, validatedSystemName, validatedAddress, validatedPort)) { + checkConstraintsOfSystemTable(validatedSystemName, validatedAddress, validatedPort); + } + + system.setSystemName(validatedSystemName); + system.setAddress(validatedAddress); + system.setPort(validatedPort); + system.setAuthenticationInfo(authenticationInfo); + + return systemRepository.saveAndFlush(system); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public void removeSystemById(final long id) { + logger.debug("removeSystemById started..."); + + try { + if (!systemRepository.existsById(id)) { + throw new InvalidParameterException(COULD_NOT_DELETE_SYSTEM_ERROR_MESSAGE); + } + + systemRepository.deleteById(id); + systemRepository.flush(); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public SystemResponseDTO mergeSystemResponse(final long systemId, final String systemName, final String address, final Integer port, + final String authenticationInfo) { + logger.debug("mergeSystemResponse started..."); + + return DTOConverter.convertSystemToSystemResponseDTO(mergeSystem(systemId, systemName, address, port, authenticationInfo)); + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public System mergeSystem(final long systemId, final String systemName, final String address, final Integer port, final String authenticationInfo) { + logger.debug("mergeSystem started..."); + + final long validatedSystemId = validateId(systemId); + final Integer validatedPort = validateAllowNullSystemPort(port); + final String validatedSystemName = validateAllowNullParamString(systemName); + if (validatedSystemName != null && validatedSystemName.contains(".")) { + throw new InvalidParameterException("System name can't contain dot (.)"); + } + final String validatedAddress = validateAllowNullParamString(address); + + try { + final Optional systemOptional = systemRepository.findById(validatedSystemId); + if (systemOptional.isEmpty()) { + throw new InvalidParameterException("No system with id : " + validatedSystemId); + } + + final System system = systemOptional.get(); + + if (checkSystemIfUniqueValidationNeeded(system, validatedSystemName, validatedAddress, validatedPort)) { + checkConstraintsOfSystemTable(validatedSystemName != null ? validatedSystemName : system.getSystemName(), + validatedAddress != null ? validatedAddress : system.getAddress(), + validatedPort != null ? validatedPort : system.getPort()); + } + + if (Utilities.notEmpty(validatedSystemName)) { + system.setSystemName(validatedSystemName); + } + + if (Utilities.notEmpty(validatedAddress)) { + system.setAddress(validatedAddress); + } + + if (validatedPort != null) { + system.setPort(validatedPort); + } + + if (Utilities.notEmpty(authenticationInfo)) { + system.setAuthenticationInfo(authenticationInfo); + } + + return systemRepository.saveAndFlush(system); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + + //------------------------------------------------------------------------------------------------- + public DeviceResponseDTO getDeviceById(long deviceId) { + logger.debug("getDeviceById started..."); + + try { + final Optional deviceOptional = deviceRepository.findById(deviceId); + if (deviceOptional.isEmpty()) { + throw new InvalidParameterException("Device with id " + deviceId + " not found."); + } + + return DTOConverter.convertDeviceToDeviceResponseDTO(deviceOptional.get()); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + public DeviceListResponseDTO getDeviceEntries(final CoreUtilities.ValidatedPageParams pageParams, final String sortField) { + logger.debug("getDeviceList started..."); + + final String validatedSortField = Utilities.isEmpty(sortField) ? CoreCommonConstants.COMMON_FIELD_NAME_ID : sortField.trim(); + + if (!System.SORTABLE_FIELDS_BY.contains(validatedSortField)) { + throw new InvalidParameterException("Sortable field with reference '" + validatedSortField + "' is not available"); + } + + try { + final Page devices = deviceRepository.findAll(PageRequest.of(pageParams.getValidatedPage(), pageParams.getValidatedSize(), + pageParams.getValidatedDirection(), validatedSortField)); + return DTOConverter.convertDeviceEntryListToDeviceListResponseDTO(devices); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceResponseDTO createDeviceDto(final String name, final String address, final String macAddress, final String authenticationInfo) { + return DTOConverter.convertDeviceToDeviceResponseDTO(createDevice(name, address, macAddress, authenticationInfo)); + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public DeviceResponseDTO updateDeviceByIdResponse(final long id, final String name, final String address, final String macAddress, + final String authenticationInfo) { + + logger.debug("updateDeviceByIdResponse started..."); + + try { + + final long validatedId = validateId(id); + final Device newDevice = validateNonNullDeviceParameters(name, address, macAddress, authenticationInfo); + + final Optional optionalDevice = deviceRepository.findById(validatedId); + final Device device = optionalDevice.orElseThrow(() -> new InvalidParameterException("No device with id : " + id)); + + device.setDeviceName(newDevice.getDeviceName()); + device.setAddress(newDevice.getAddress()); + device.setMacAddress(newDevice.getMacAddress()); + device.setAuthenticationInfo(newDevice.getAuthenticationInfo()); + + return DTOConverter.convertDeviceToDeviceResponseDTO(deviceRepository.saveAndFlush(device)); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public void removeDeviceById(final long id) { + logger.debug("removeDeviceById started..."); + + try { + if (!deviceRepository.existsById(id)) { + throw new InvalidParameterException(COULD_NOT_DELETE_DEVICE_ERROR_MESSAGE); + } + + deviceRepository.deleteById(id); + deviceRepository.flush(); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public SystemRegistryListResponseDTO getSystemRegistryEntries(final CoreUtilities.ValidatedPageParams params, final String sortField) { + logger.debug("getSystemRegistryEntries started..."); + final String validatedSortField = sortField == null ? CoreCommonConstants.COMMON_FIELD_NAME_ID : sortField.trim(); + + if (!SystemRegistry.SORTABLE_FIELDS_BY.contains(validatedSortField)) { + throw new InvalidParameterException("Sortable field with reference '" + validatedSortField + "' is not available"); + } + + try { + final PageRequest pageRequest = PageRequest.of(params.getValidatedPage(), + params.getValidatedSize(), + params.getValidatedDirection(), + validatedSortField); + final Page systemRegistryPage = systemRegistryRepository.findAll(pageRequest); + return DTOConverter.convertSystemRegistryListToSystemRegistryListResponseDTO(systemRegistryPage); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public SystemRegistryResponseDTO getSystemRegistryById(final long id) { + logger.debug("getSystemRegistryById started..."); + + return DTOConverter.convertSystemRegistryToSystemRegistryResponseDTO(getSystemRegistryEntryById(id)); + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public void removeSystemRegistryEntryById(final long id) { + logger.debug("removeSystemRegistryEntryById started..."); + + try { + if (!systemRegistryRepository.existsById(id)) { + throw new InvalidParameterException("System Registry entry with id '" + id + "' does not exist"); + } + + systemRegistryRepository.deleteById(id); + systemRegistryRepository.flush(); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public SystemRegistryResponseDTO registerSystemRegistry(final SystemRegistryRequestDTO request) { + logger.debug("registerSystemRegistry started..."); + checkSystemRegistryRequest(request); + + try { + + final ZonedDateTime endOfValidity = getZonedDateTime(request); + final String metadataStr = Utilities.map2Text(request.getMetadata()); + final int version = (request.getVersion() != null) ? request.getVersion() : 1; + final System systemDb = findOrCreateSystem(request.getSystem()); + final Device deviceDb = findOrCreateDevice(request.getProvider()); + + final SystemRegistry srEntry = createSystemRegistry(systemDb, deviceDb, endOfValidity, metadataStr, version); + return DTOConverter.convertSystemRegistryToSystemRegistryResponseDTO(srEntry); + } catch (final DateTimeParseException ex) { + logger.debug(ex.getMessage(), ex); + throw new InvalidParameterException( + "End of validity is specified in the wrong format. Please provide UTC time using " + Utilities.getDatetimePattern() + " pattern.", ex); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public SystemRegistryResponseDTO updateSystemRegistryById(final long id, final SystemRegistryRequestDTO request) { + logger.debug("updateSystemRegistryById started..."); + + Assert.isTrue(0 < id, "id is not greater than zero"); + checkSystemRegistryRequest(request); + + try { + final SystemRegistry srEntry; + final SystemRegistry updateSrEntry; + + final Optional srEntryOptional = systemRegistryRepository.findById(id); + srEntry = srEntryOptional.orElseThrow(() -> new InvalidParameterException("System Registry entry with id '" + id + "' does not exist")); + + final System systemDb = findOrCreateSystem(request.getSystem()); + final Device deviceDb = findOrCreateDevice(request.getProvider()); + final ZonedDateTime endOfValidity = getZonedDateTime(request); + final String metadataStr = Utilities.map2Text(request.getMetadata()); + final int version = (request.getVersion() != null) ? request.getVersion() : 1; + + updateSrEntry = updateSystemRegistry(srEntry, systemDb, deviceDb, endOfValidity, metadataStr, version); + + return DTOConverter.convertSystemRegistryToSystemRegistryResponseDTO(updateSrEntry); + } catch (final DateTimeParseException ex) { + logger.debug(ex.getMessage(), ex); + throw new InvalidParameterException( + "End of validity is specified in the wrong format. Please provide UTC time using " + Utilities.getDatetimePattern() + " pattern.", ex); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public SystemRegistryResponseDTO mergeSystemRegistryById(final long id, final SystemRegistryRequestDTO request) { + + logger.debug("mergeSystemRegistryById started..."); + Assert.notNull(request, "request is null."); + Assert.isTrue(0 < id, "id is not greater than zero"); + + try { + final SystemRegistry srEntry; + final SystemRegistry updateSrEntry; + + final Optional srEntryOptional = systemRegistryRepository.findById(id); + srEntry = srEntryOptional.orElseThrow(() -> new InvalidParameterException("System Registry entry with id '" + id + "' does not exist")); + + final System systemDb = mergeSystem(request.getSystem(), srEntry.getSystem()); + final Device deviceDb = mergeDevice(request.getProvider(), srEntry.getDevice()); + + final ZonedDateTime endOfValidity = Utilities.notEmpty(request.getEndOfValidity()) ? + Utilities.parseUTCStringToLocalZonedDateTime(request.getEndOfValidity().trim()) : + srEntry.getEndOfValidity(); + + final String validatedMetadataStr = Objects.nonNull(request.getMetadata()) ? + Utilities.map2Text(request.getMetadata()) : + srEntry.getMetadata(); + + final int validatedVersion = (request.getVersion() != null) ? request.getVersion() : srEntry.getVersion(); + + updateSrEntry = updateSystemRegistry(srEntry, systemDb, deviceDb, endOfValidity, validatedMetadataStr, validatedVersion); + + return DTOConverter.convertSystemRegistryToSystemRegistryResponseDTO(updateSrEntry); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final DateTimeParseException ex) { + logger.debug(ex.getMessage(), ex); + throw new InvalidParameterException( + "End of validity is specified in the wrong format. Please provide UTC time using " + Utilities.getDatetimePattern() + " pattern.", ex); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public SystemRegistryListResponseDTO getSystemRegistryEntriesBySystemName(final String systemName, final CoreUtilities.ValidatedPageParams pageParameters, + final String sortField) { + logger.debug("getSystemRegistryEntriesBySystemName is started..."); + + if (!System.SORTABLE_FIELDS_BY.contains(sortField)) { + throw new InvalidParameterException("Sortable field with reference '" + sortField + "' is not available"); + } + + final List systemList = systemRepository.findBySystemName(systemName); + final PageRequest pageRequest = PageRequest.of(pageParameters.getValidatedPage(), pageParameters.getValidatedSize(), + pageParameters.getValidatedDirection(), sortField); + + final Page systemRegistries = systemRegistryRepository.findAllBySystemIsIn(systemList, pageRequest); + return DTOConverter.convertSystemRegistryListToSystemRegistryListResponseDTO(systemRegistries); + } + + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public void removeSystemRegistryByNameAndAddressAndPort(final String systemName, final String address, final int port) { + logger.debug("removeSystemRegistryByNameAndAddressAndPort is started..."); + final System system = getSystemByNameAndAddressAndPort(systemName, address, port); + + final List entries = systemRegistryRepository.findBySystem(system); + if (entries.isEmpty()) { + throw new InvalidParameterException("System Registry entry for System with name '" + systemName + + "', address '" + address + + "' and port '" + port + "' does not exist"); + } + + systemRegistryRepository.deleteInBatch(entries); + systemRegistryRepository.flush(); + } + + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public SystemQueryResultDTO queryRegistry(final SystemQueryFormDTO form) { + logger.debug("queryRegistry is started..."); + Assert.notNull(form, "Form is null."); + + try { + final List systems; + final List devices; + final List registryList; + final int unfilteredHits; + + if (Utilities.notEmpty(form.getSystemNameRequirements())) { + final String systemName = Utilities.lowerCaseTrim(form.getSystemNameRequirements()); + systems = systemRepository.findBySystemName(systemName); + + if (systems.isEmpty()) { + // no system found + logger.debug("System not found: {}", systemName); + return DTOConverter.convertSystemRegistryListToSystemQueryResultDTO(Collections.emptyList()); + } + } else { + throw new InvalidParameterException("System Name must not be null"); + } + + registryList = systemRegistryRepository.findAllBySystemIsIn(systems); + unfilteredHits = registryList.size(); + + if (Utilities.notEmpty(form.getDeviceNameRequirements())) { + final String deviceName = Utilities.lowerCaseTrim(form.getDeviceNameRequirements()); + devices = deviceRepository.findByDeviceName(deviceName); + + if (devices.isEmpty()) { + // no device found + logger.debug("Device not found: {}", deviceName); + return DTOConverter.convertSystemRegistryListToSystemQueryResultDTO(Collections.emptyList()); + } + + registryList.removeIf(e -> !devices.contains(e.getDevice())); + } + + // filter on version + if (Objects.nonNull(form.getVersionRequirement())) { + registryList.removeIf(e -> Objects.equals(form.getVersionRequirement(), e.getVersion())); + } else if (Objects.nonNull(form.getMinVersionRequirement()) || Objects.nonNull(form.getMaxVersionRequirement())) { + final int minVersion = form.getMinVersionRequirement() == null ? 1 : form.getMinVersionRequirement(); + final int maxVersion = form.getMaxVersionRequirement() == null ? Integer.MAX_VALUE : form.getMaxVersionRequirement(); + + registryList.removeIf(e -> (e.getVersion() < minVersion) || (e.getVersion() > maxVersion)); + } + + // filter on metadata + if (form.getMetadataRequirements() != null && !form.getMetadataRequirements().isEmpty()) { + final Map requiredMetadata = normalizeMetadata(form.getMetadataRequirements()); + registryList.removeIf(e -> + { + final Map metadata = Utilities.text2Map(e.getMetadata()); + if (Objects.isNull(metadata)) { + // we have requirements but no metadata -> remove + return true; + } + + return !metadata.entrySet().containsAll(requiredMetadata.entrySet()); + }); + } + + // filter on ping + if (form.getPingProviders()) { + filterOnPing(registryList, pingTimeout); + } + + logger.debug("Potential system providers after filtering: {}", registryList.size()); + return DTOConverter.convertListOfSystemRegistryEntriesToSystemQueryResultDTO(registryList, unfilteredHits); + } catch (final IllegalStateException e) { + throw new InvalidParameterException("Invalid keys in the metadata requirements (whitespace only differences)"); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public SystemResponseDTO getSystemDtoByNameAndAddressAndPort(final String systemName, final String address, final int port) { + final System system = getSystemByNameAndAddressAndPort(systemName, address, port); + return DTOConverter.convertSystemToSystemResponseDTO(system); + } + + //------------------------------------------------------------------------------------------------- + @Transactional(rollbackFor = ArrowheadException.class) + public System createSystem(final String systemName, final String address, final int port, final String authenticationInfo) { + logger.debug("createSystem started..."); + + final System system = validateNonNullSystemParameters(systemName, address, port, authenticationInfo); + + try { + return systemRepository.saveAndFlush(system); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + public SystemRegistryOnboardingWithNameResponseDTO onboardAndRegisterSystemRegistry(final SystemRegistryOnboardingWithNameRequestDTO request, + final String host, final String address) { + logger.debug("onboardAndRegisterSystemRegistry started..."); + + final CertificateCreationRequestDTO creationRequestDTO = request.getCertificateCreationRequest(); + final KeyPair keyPair = securityUtilities.extractOrGenerateKeyPair(creationRequestDTO); + final String certificateSigningRequest; + + try { + certificateSigningRequest = securityUtilities + .createCertificateSigningRequest(creationRequestDTO.getCommonName(), keyPair, CertificateType.AH_SYSTEM, host, address); + } catch (Exception e) { + logger.error(e.getMessage(), e); + throw new ArrowheadException("Unable to create certificate signing request: " + e.getMessage()); + } + + final var signingResponse = signCertificate(certificateSigningRequest); + signingResponse.setKeyPairDTO(securityUtilities.encodeKeyPair(keyPair)); + + final var retValue = new SystemRegistryOnboardingWithNameResponseDTO(); + retValue.setCertificateResponse(signingResponse); + retValue.load(registerSystemRegistry(request)); + return retValue; + } + + public SystemRegistryOnboardingWithCsrResponseDTO onboardAndRegisterSystemRegistry(final SystemRegistryOnboardingWithCsrRequestDTO request) { + + logger.debug("onboardAndRegisterDeviceRegistry started..."); + final var signingResponse = signCertificate(request.getCertificateSigningRequest()); + securityUtilities.extractAndSetPublicKey(signingResponse); + + final var retValue = new SystemRegistryOnboardingWithCsrResponseDTO(); + retValue.setCertificateResponse(signingResponse); + retValue.load(registerSystemRegistry(request)); + return retValue; + } + + //================================================================================================= + // assistant methods + //------------------------------------------------------------------------------------------------- + private System getSystemByNameAndAddressAndPort(final String systemName, final String address, final int port) { + final String dbSystemName = Utilities.lowerCaseTrim(systemName); + final String dbAddress = Utilities.lowerCaseTrim(address); + final Optional optionalSystem = systemRepository.findBySystemNameAndAddressAndPort(dbSystemName, dbAddress, port); + return optionalSystem.orElseThrow(() -> new InvalidParameterException( + "System entry with name '" + dbSystemName + "', address '" + dbAddress + "' and port '" + port + "' does not exist")); + } + + //------------------------------------------------------------------------------------------------- + @SuppressWarnings("squid:S1126") + private boolean checkSystemIfUniqueValidationNeeded(final System system, final String validatedSystemName, final String validatedAddress, + final Integer validatedPort) { + logger.debug("checkSystemIfUniqueValidationNeeded started..."); + + final String actualSystemName = system.getSystemName(); + final String actualAddress = system.getAddress(); + final int actualPort = system.getPort(); + + if (validatedSystemName != null && !actualSystemName.equalsIgnoreCase(validatedSystemName)) { + return true; + } else if (validatedAddress != null && !actualAddress.equalsIgnoreCase(validatedAddress)) { + return true; + } else { + return validatedPort != null && actualPort != validatedPort; + } + } + + //------------------------------------------------------------------------------------------------- + // This method may CHANGE the content of providedServices + private void filterOnPing(final List systems, final int timeout) { + if (systems == null || systems.isEmpty() || timeout <= 0) { + return; + } + + systems.removeIf(sr -> !pingService(sr.getSystem().getAddress(), sr.getSystem().getPort(), timeout)); + } + + //------------------------------------------------------------------------------------------------- + private boolean pingService(final String address, final int port, final int timeout) { + final InetSocketAddress host = new InetSocketAddress(address, port); + try (final Socket socket = new Socket()) { + socket.connect(host, timeout); + return true; + } catch (final IOException ex) { + return false; + } + } + + //------------------------------------------------------------------------------------------------- + private Map normalizeMetadata(final Map metadata) throws IllegalStateException { + logger.debug("normalizeMetadata started..."); + if (metadata == null) { + return Map.of(); + } + + final Map map = new HashMap<>(); + + metadata.forEach((k, v) -> + { + if (Objects.nonNull(v)) { + map.put(k.trim(), v.trim()); + } + }); + + return map; + } + + //------------------------------------------------------------------------------------------------- + private void checkConstraintsOfSystemTable(final String validatedSystemName, final String validatedAddress, final int validatedPort) { + logger.debug("checkConstraintsOfSystemTable started..."); + + try { + final Optional find = systemRepository + .findBySystemNameAndAddressAndPort(validatedSystemName.toLowerCase().trim(), validatedAddress.toLowerCase().trim(), validatedPort); + if (find.isPresent()) { + throw new InvalidParameterException( + "System with name: " + validatedSystemName + ", address: " + validatedAddress + ", port: " + validatedPort + " already exists."); + } + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + private void checkConstraintsOfDeviceTable(final String validatedDeviceName, final String validatedMacAddress) { + logger.debug("checkConstraintsOfDeviceTable started..."); + + try { + final Optional find = deviceRepository.findByDeviceNameAndMacAddress(validatedDeviceName, validatedMacAddress); + if (find.isPresent()) { + throw new InvalidParameterException( + "Device with name: " + validatedDeviceName + ", MAC address: " + validatedMacAddress + " already exists."); + } + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + private System validateNonNullSystemParameters(final String systemName, final String address, final int port, final String authenticationInfo) { + logger.debug("validateNonNullSystemParameters started..."); + + validateNonNullParameters(systemName, address); + + if (port <= CommonConstants.SYSTEM_PORT_RANGE_MIN || port > CommonConstants.SYSTEM_PORT_RANGE_MAX) { + throw new InvalidParameterException(PORT_RANGE_ERROR_MESSAGE); + } + + final String validatedSystemName = Utilities.lowerCaseTrim(systemName); + final String validatedAddress = Utilities.lowerCaseTrim(address); + + checkConstraintsOfSystemTable(validatedSystemName, validatedAddress, port); + + return new System(validatedSystemName, validatedAddress, port, authenticationInfo); + } + + //------------------------------------------------------------------------------------------------- + private Device validateNonNullDeviceParameters(final String deviceName, final String address, final String macAddress, final String authenticationInfo) { + logger.debug("validateNonNullDeviceParameters started..."); + + validateNonNullParameters(deviceName, address); + + if (Utilities.isEmpty(macAddress)) { + throw new InvalidParameterException("MAC address is null or empty"); + } + + final String validatedDeviceName = Utilities.lowerCaseTrim(deviceName); + final String validatedAddress = Utilities.lowerCaseTrim(address); + final String validatedMacAddress = Utilities.lowerCaseTrim(macAddress); + + if (!Utilities.isValidMacAddress(validatedMacAddress)) { + throw new BadPayloadException("Unrecognized format of MAC Address", HttpStatus.SC_BAD_REQUEST); + } + + checkConstraintsOfDeviceTable(validatedDeviceName, validatedMacAddress); + + return new Device(validatedDeviceName, validatedAddress, validatedMacAddress, authenticationInfo); + } + + //------------------------------------------------------------------------------------------------- + private void validateNonNullParameters(final String name, final String address) { + logger.debug("validateNonNullParameters started..."); + + if (Utilities.isEmpty(name)) { + throw new InvalidParameterException("Name is null or empty"); + } + + if (Utilities.isEmpty(address)) { + throw new InvalidParameterException("Address is null or empty"); + } + + if (name.contains(".")) { + throw new InvalidParameterException("Name can't contain dot (.)"); + } + } + + //------------------------------------------------------------------------------------------------- + private String validateParamString(final String param) { + logger.debug("validateSystemParamString started..."); + + if (Utilities.isEmpty(param)) { + throw new InvalidParameterException("parameter null or empty"); + } + + return Utilities.lowerCaseTrim(param); + } + + //------------------------------------------------------------------------------------------------- + private int validateSystemPort(final int port) { + logger.debug("validateSystemPort started..."); + + if (port < CommonConstants.SYSTEM_PORT_RANGE_MIN || port > CommonConstants.SYSTEM_PORT_RANGE_MAX) { + throw new InvalidParameterException(PORT_RANGE_ERROR_MESSAGE); + } + + return port; + } + + //------------------------------------------------------------------------------------------------- + private long validateId(final long id) { + logger.debug("validateId started..."); + + if (id < 1) { + throw new IllegalArgumentException("Id must be greater than zero"); + } + + return id; + } + + //------------------------------------------------------------------------------------------------- + private Integer validateAllowNullSystemPort(final Integer port) { + logger.debug("validateAllowNullSystemPort started..."); + + if (port != null && (port < CommonConstants.SYSTEM_PORT_RANGE_MIN || port > CommonConstants.SYSTEM_PORT_RANGE_MAX)) { + throw new IllegalArgumentException(PORT_RANGE_ERROR_MESSAGE); + } + + return port; + } + + //------------------------------------------------------------------------------------------------- + private String validateAllowNullParamString(final String param) { + logger.debug("validateAllowNullParamString started..."); + + if (Utilities.isEmpty(param)) { + return null; + } + + return Utilities.lowerCaseTrim(param); + } + + + //------------------------------------------------------------------------------------------------- + private SystemRegistry getSystemRegistryEntryById(final long id) { + logger.debug("getSystemRegistryEntryById started..."); + try { + final Optional systemRegistry = systemRegistryRepository.findById(id); + return systemRegistry.orElseThrow(() -> new InvalidParameterException("System Registry with id of '" + id + "' does not exist")); + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + private System findOrCreateSystem(SystemRequestDTO requestSystemDto) { + return findOrCreateSystem(requestSystemDto.getSystemName(), + requestSystemDto.getAddress(), + requestSystemDto.getPort(), + requestSystemDto.getAuthenticationInfo()); + } + + //------------------------------------------------------------------------------------------------- + private System findOrCreateSystem(final String name, final String address, final int port, final String authenticationInfo) { + + final String validatedName = Utilities.lowerCaseTrim(name); + final String validatedAddress = Utilities.lowerCaseTrim(address); + + final Optional optSystem = systemRepository.findBySystemNameAndAddressAndPort(validatedName, validatedAddress, port); + System provider; + + if (optSystem.isPresent()) { + provider = optSystem.get(); + if (!Objects.equals(authenticationInfo, provider.getAuthenticationInfo()) || + !Objects.equals(validatedAddress, provider.getAddress())) { // authentication info or system has changed + provider.setAuthenticationInfo(authenticationInfo); + provider.setAddress(validatedAddress); + provider = systemRepository.saveAndFlush(provider); + } + } else { + provider = createSystem(validatedName, validatedAddress, port, authenticationInfo); + } + return provider; + } + + //------------------------------------------------------------------------------------------------- + private Device findOrCreateDevice(DeviceRequestDTO requestDeviceDto) { + return findOrCreateDevice(requestDeviceDto.getDeviceName(), + requestDeviceDto.getAddress(), + requestDeviceDto.getMacAddress(), + requestDeviceDto.getAuthenticationInfo()); + } + + //------------------------------------------------------------------------------------------------- + private Device findOrCreateDevice(String deviceName, String address, String macAddress, String authenticationInfo) { + + final String validateName = Utilities.lowerCaseTrim(deviceName); + final String validateAddress = Utilities.lowerCaseTrim(address); + final String validatedMacAddress = Utilities.lowerCaseTrim(macAddress); + + if (!Utilities.isValidMacAddress(validatedMacAddress)) { + throw new BadPayloadException("Unrecognized format of MAC Address", HttpStatus.SC_BAD_REQUEST); + } + + final Optional optProvider = deviceRepository.findByDeviceNameAndMacAddress(validateName, validatedMacAddress); + Device provider; + + if (optProvider.isPresent()) { + provider = optProvider.get(); + if (!Objects.equals(authenticationInfo, provider.getAuthenticationInfo()) || + !Objects.equals(validateAddress, provider.getAddress())) { // authentication info or provider has changed + provider.setAuthenticationInfo(authenticationInfo); + provider.setAddress(validateAddress); + provider = deviceRepository.saveAndFlush(provider); + } + } else { + provider = createDevice(validateName, validateAddress, validatedMacAddress, authenticationInfo); + } + return provider; + } + + //------------------------------------------------------------------------------------------------- + private Device createDevice(final String name, final String address, final String macAddress, final String authenticationInfo) { + final Device device = new Device(name, address, macAddress, authenticationInfo); + return deviceRepository.saveAndFlush(device); + } + + //------------------------------------------------------------------------------------------------- + private void checkSystemRegistryRequest(final SystemRegistryRequestDTO request) { + logger.debug("checkSystemRegistryRequest started..."); + Assert.notNull(request, "Request is null."); + + Assert.notNull(request.getSystem(), "System is not specified."); + Assert.isTrue(Utilities.notEmpty(request.getSystem().getSystemName()), "System name is not specified."); + Assert.isTrue(Utilities.notEmpty(request.getSystem().getAddress()), "System address is not specified."); + Assert.notNull(request.getSystem().getPort(), "System port is not specified."); + + Assert.notNull(request.getProvider(), "Provider Device is not specified."); + Assert.isTrue(Utilities.notEmpty(request.getProvider().getDeviceName()), "Provider Device name is not specified."); + Assert.isTrue(Utilities.notEmpty(request.getProvider().getAddress()), "Provider Device address is not specified."); + Assert.isTrue(Utilities.notEmpty(request.getProvider().getMacAddress()), "Provider Device MAC is not specified."); + } + + //------------------------------------------------------------------------------------------------- + private void checkConstraintsOfSystemRegistryTable(final System systemDb, final Device deviceDb) { + logger.debug("checkConstraintOfSystemRegistryTable started..."); + + try { + final Optional find = systemRegistryRepository.findBySystemAndDevice(systemDb, deviceDb); + if (find.isPresent()) { + throw new InvalidParameterException("System Registry entry with provider: (" + deviceDb.getDeviceName() + ", " + deviceDb.getMacAddress() + + ") and system : " + systemDb.getSystemName() + " already exists."); + } + } catch (final InvalidParameterException ex) { + throw ex; + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + private Device mergeDevice(final DeviceRequestDTO request, final Device device) { + final String name = Utilities.firstNotNullIfExists(request.getDeviceName(), device.getDeviceName()); + final String address = Utilities.firstNotNullIfExists(request.getAddress(), device.getAddress()); + final String macAddress = Utilities.firstNotNullIfExists(request.getDeviceName(), device.getDeviceName()); + final String authenticationInfo = Utilities.firstNotNullIfExists(request.getAuthenticationInfo(), device.getAuthenticationInfo()); + return findOrCreateDevice(name, address, macAddress, authenticationInfo); + } + + //------------------------------------------------------------------------------------------------- + private System mergeSystem(final SystemRequestDTO request, final System system) { + final String name = Utilities.firstNotNullIfExists(request.getSystemName(), system.getSystemName()); + final String address = Utilities.firstNotNullIfExists(request.getAddress(), system.getAddress()); + final int port = request.getPort() > 0 ? request.getPort() : system.getPort(); + final String authenticationInfo = Utilities.firstNotNullIfExists(request.getAuthenticationInfo(), system.getAuthenticationInfo()); + return findOrCreateSystem(name, address, port, authenticationInfo); + } + + //------------------------------------------------------------------------------------------------- + private SystemRegistry createSystemRegistry(final System systemDb, final Device deviceDb, final ZonedDateTime endOfValidity, final String metadataStr, + final int version) { + logger.debug("createSystemRegistry started..."); + + checkConstraintsOfSystemRegistryTable(systemDb, deviceDb); + + try { + return systemRegistryRepository.saveAndFlush(new SystemRegistry(systemDb, deviceDb, endOfValidity, metadataStr, version)); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + + //------------------------------------------------------------------------------------------------- + private boolean checkSystemRegistryIfUniqueValidationNeeded(final SystemRegistry srEntry, final System system, final Device device) { + logger.debug("checkSystemRegistryIfUniqueValidationNeeded started..."); + + return srEntry.getSystem().getId() != system.getId() || srEntry.getDevice().getId() != device.getId(); + + } + + //------------------------------------------------------------------------------------------------- + private SystemRegistry updateSystemRegistry(final SystemRegistry srEntry, final System system, final Device device, + final ZonedDateTime endOfValidity, final String metadataStr, final int version) { + logger.debug("updateSystemRegistry started..."); + Assert.notNull(srEntry, "SystemRegistry Entry is not specified."); + Assert.notNull(system, "System is not specified."); + Assert.notNull(device, "Device is not specified."); + + if (checkSystemRegistryIfUniqueValidationNeeded(srEntry, system, device)) { + checkConstraintsOfSystemRegistryTable(system, device); + } + + return setModifiedValuesOfSystemRegistryEntryFields(srEntry, system, device, endOfValidity, metadataStr, version); + } + + //------------------------------------------------------------------------------------------------- + private ZonedDateTime getZonedDateTime(SystemRegistryRequestDTO request) { + return Utilities.isEmpty(request.getEndOfValidity()) ? null : Utilities.parseUTCStringToLocalZonedDateTime(request.getEndOfValidity().trim()); + } + + //------------------------------------------------------------------------------------------------- + private CertificateCreationResponseDTO signCertificate(final String signingRequest) { + logger.debug("Contact CertificateAuthority ..."); + final var csrDTO = new CertificateSigningRequestDTO(signingRequest); + final var signingResponse = caDriver.signCertificate(csrDTO); + + logger.debug("Processing response from Certificate Authority ..."); + final CertificateCreationResponseDTO certificateResponseDTO = new CertificateCreationResponseDTO(); + certificateResponseDTO.setCertificate(signingResponse.getCertificateChain().get(0)); + certificateResponseDTO.setCertificateFormat(CoreCommonConstants.CERTIFICATE_FORMAT); + certificateResponseDTO.setCertificateType(CertificateType.AH_DEVICE); + return certificateResponseDTO; + } + + //------------------------------------------------------------------------------------------------- + private SystemRegistry setModifiedValuesOfSystemRegistryEntryFields(final SystemRegistry srEntry, final System system, final Device device, + final ZonedDateTime endOfValidity, final String metadataStr, final int version) { + + logger.debug("setModifiedValuesOfSystemRegistryEntryFields started..."); + + try { + srEntry.setSystem(system); + srEntry.setDevice(device); + srEntry.setEndOfValidity(endOfValidity); + srEntry.setMetadata(metadataStr); + srEntry.setVersion(version); + + return systemRegistryRepository.saveAndFlush(srEntry); + } catch (final Exception ex) { + logger.debug(ex.getMessage(), ex); + throw new ArrowheadException(CoreCommonConstants.DATABASE_OPERATION_EXCEPTION_MSG); + } + } + +} diff --git a/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/security/SystemRegistryAccessControlFilter.java b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/security/SystemRegistryAccessControlFilter.java new file mode 100644 index 000000000..ecc1a7af8 --- /dev/null +++ b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/security/SystemRegistryAccessControlFilter.java @@ -0,0 +1,44 @@ +package eu.arrowhead.core.systemregistry.security; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.SecurityUtilities; +import eu.arrowhead.common.dto.shared.CertificateType; +import eu.arrowhead.common.security.CoreSystemAccessControlFilter; +import org.bouncycastle.crypto.tls.CertChainType; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.stereotype.Component; + +import java.util.Map; + +@Component +@ConditionalOnProperty(name = CommonConstants.SERVER_SSL_ENABLED, matchIfMissing = true) +public class SystemRegistryAccessControlFilter extends CoreSystemAccessControlFilter { + + //================================================================================================= + // assistant methods + private final SecurityUtilities securityUtilities; + + @Autowired + public SystemRegistryAccessControlFilter(final SecurityUtilities securityUtilities) {this.securityUtilities = securityUtilities;} + + //------------------------------------------------------------------------------------------------- + @Override + protected void checkClientAuthorized(final String clientCN, final String method, final String requestTarget, final String requestJSON, final Map queryParams) { + + if (requestTarget.contains(CommonConstants.ONBOARDING_URI) || requestTarget.contains(CommonConstants.OP_SYSTEM_REGISTRY_UNREGISTER_URI)) { + // certificates will be verified individually on each method + securityUtilities.authenticateCertificate(clientCN, requestTarget, CertificateType.AH_DEVICE); + return; + } + + super.checkClientAuthorized(clientCN, method, requestTarget, requestJSON, queryParams); + final String cloudCN = getServerCloudCN(); + + if (requestTarget.contains(CoreCommonConstants.MGMT_URI)) { + // Only the local System Operator can use these methods + checkIfLocalSystemOperator(clientCN, cloudCN, requestTarget); + } + } +} \ No newline at end of file diff --git a/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/security/SystemRegistrySecurityConfig.java b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/security/SystemRegistrySecurityConfig.java new file mode 100644 index 000000000..e54cc7a62 --- /dev/null +++ b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/security/SystemRegistrySecurityConfig.java @@ -0,0 +1,11 @@ +package eu.arrowhead.core.systemregistry.security; + +import eu.arrowhead.common.security.DefaultSecurityConfig; +import org.springframework.context.annotation.Configuration; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; + +@Configuration +@EnableWebSecurity +public class SystemRegistrySecurityConfig extends DefaultSecurityConfig { + +} \ No newline at end of file diff --git a/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/swagger/SystemRegistrySwaggerConfig.java b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/swagger/SystemRegistrySwaggerConfig.java new file mode 100644 index 000000000..4fed8dab9 --- /dev/null +++ b/systemregistry/src/main/java/eu/arrowhead/core/systemregistry/swagger/SystemRegistrySwaggerConfig.java @@ -0,0 +1,27 @@ +package eu.arrowhead.core.systemregistry.swagger; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.swagger.DefaultSwaggerConfig; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import springfox.documentation.spring.web.plugins.Docket; +import springfox.documentation.swagger2.annotations.EnableSwagger2; + +@EnableSwagger2 +@Configuration +public class SystemRegistrySwaggerConfig extends DefaultSwaggerConfig { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + public SystemRegistrySwaggerConfig() { + super(CommonConstants.CORE_SYSTEM_SYSTEM_REGISTRY); + } + + //------------------------------------------------------------------------------------------------- + @Bean + public Docket customizeSwagger() { + return configureSwaggerForCoreSystem(this.getClass().getPackageName()); + } +} \ No newline at end of file diff --git a/systemregistry/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/systemregistry/src/main/resources/META-INF/additional-spring-configuration-metadata.json new file mode 100644 index 000000000..f88420b7a --- /dev/null +++ b/systemregistry/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -0,0 +1,42 @@ +{"properties": [ + { + "name": "ping_scheduled", + "type": "java.lang.Boolean", + "description": "A description for 'ping_scheduled'" + }, + { + "name": "ping_timeout", + "type": "java.lang.Long", + "description": "A description for 'ping_timeout'" + }, + { + "name": "ping_interval", + "type": "java.lang.Long", + "description": "A description for 'ping_interval'" + }, + { + "name": "disable.hostname.verifier", + "type": "java.lang.Boolean", + "description": "A description for 'disable.hostname.verifier'" + }, + { + "name": "log_all_request_and_response", + "type": "java.lang.Boolean", + "description": "A description for 'log_all_request_and_response'" + }, + { + "name": "core_system_name", + "type": "java.lang.String", + "description": "A description for 'core_system_name'" + }, + { + "name": "domain.name", + "type": "java.lang.String", + "description": "A description for 'domain.name'" + }, + { + "name": "domain.port", + "type": "java.lang.Integer", + "description": "A description for 'domain.port'" + } +]} \ No newline at end of file diff --git a/systemregistry/src/main/resources/application.properties b/systemregistry/src/main/resources/application.properties new file mode 100644 index 000000000..cd205c351 --- /dev/null +++ b/systemregistry/src/main/resources/application.properties @@ -0,0 +1,59 @@ +############################################ +### APPLICATION PARAMETERS ### +############################################ + +# Database connection (mandatory) +# Change the server timezone if necessary +spring.datasource.url=jdbc:mysql://127.0.0.1:3306/arrowhead?serverTimezone=Europe/Budapest +spring.datasource.username=system_registry +spring.datasource.password=Kh12Hhgaxzo7haf +spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver + +spring.jpa.database-platform=org.hibernate.dialect.MySQL5InnoDBDialect +# use true only for debugging +spring.jpa.show-sql=false +spring.jpa.properties.hibernate.format_sql=true +spring.jpa.hibernate.ddl-auto=none + +# System Registry web-server parameters +server.address=0.0.0.0 +server.port=8437 +domain.name=127.0.0.1 +domain.port=8437 + +############################################ +### CUSTOM PARAMETERS ### +############################################ + +# Name of the core system +core_system_name=SYSTEM_REGISTRY + +# Show all request/response in debug log +log_all_request_and_response=false + +# Service Registry web-server parameters (to register the Authorization services) +sr_address=127.0.0.1 +sr_port=8443 + +############################################ +### SECURE MODE ### +############################################ + +# configure secure mode + +# Set this to false to disable https mode +server.ssl.enabled=true + +server.ssl.key-store-type=PKCS12 +server.ssl.key-store=classpath:certificates/system_registry.p12 +server.ssl.key-store-password=123456 +server.ssl.key-alias=system_registry +server.ssl.key-password=123456 +server.ssl.client-auth=need +server.ssl.trust-store-type=PKCS12 +server.ssl.trust-store=classpath:certificates/truststore.p12 +server.ssl.trust-store-password=123456 + +#If true, http client does not check whether the hostname is match one of the server's SAN in its certificate +#Just for testing, DO NOT USE this feature in production environment +disable.hostname.verifier=false diff --git a/systemregistry/src/main/resources/certificates/system_registry.p12 b/systemregistry/src/main/resources/certificates/system_registry.p12 new file mode 100644 index 000000000..1e913c7ae Binary files /dev/null and b/systemregistry/src/main/resources/certificates/system_registry.p12 differ diff --git a/systemregistry/src/main/resources/certificates/truststore.p12 b/systemregistry/src/main/resources/certificates/truststore.p12 new file mode 100644 index 000000000..57c1c5f43 Binary files /dev/null and b/systemregistry/src/main/resources/certificates/truststore.p12 differ diff --git a/systemregistry/src/main/resources/log4j2.xml b/systemregistry/src/main/resources/log4j2.xml new file mode 100644 index 000000000..de3e42cf3 --- /dev/null +++ b/systemregistry/src/main/resources/log4j2.xml @@ -0,0 +1,46 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex + + INFO + DEBUG + . + + + + + + + + ${LOG_PATTERN} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/systemregistry/src/main/resources/swagger/swagger-ui.html b/systemregistry/src/main/resources/swagger/swagger-ui.html new file mode 100644 index 000000000..0a9a6eaa1 --- /dev/null +++ b/systemregistry/src/main/resources/swagger/swagger-ui.html @@ -0,0 +1,75 @@ + + + + + + System Registry + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + diff --git a/systemregistry/src/test/java/eu/arrowhead/common/database/service/DatabaseTestContext.java b/systemregistry/src/test/java/eu/arrowhead/common/database/service/DatabaseTestContext.java new file mode 100644 index 000000000..e8c11b927 --- /dev/null +++ b/systemregistry/src/test/java/eu/arrowhead/common/database/service/DatabaseTestContext.java @@ -0,0 +1,14 @@ +package eu.arrowhead.common.database.service; + +import eu.arrowhead.common.CoreCommonConstants; +import eu.arrowhead.common.database.repository.RefreshableRepositoryImpl; +import org.springframework.boot.SpringBootConfiguration; +import org.springframework.boot.autoconfigure.domain.EntityScan; +import org.springframework.data.jpa.repository.config.EnableJpaRepositories; + +@SpringBootConfiguration +@EntityScan(basePackages = CoreCommonConstants.DATABASE_ENTITY_PACKAGE) +@EnableJpaRepositories(basePackages = CoreCommonConstants.DATABASE_REPOSITORY_PACKAGE, repositoryBaseClass = RefreshableRepositoryImpl.class) +public class DatabaseTestContext { + public DatabaseTestContext() { super(); } +} diff --git a/systemregistry/src/test/java/eu/arrowhead/common/database/service/SystemRepositoryTest.java b/systemregistry/src/test/java/eu/arrowhead/common/database/service/SystemRepositoryTest.java new file mode 100644 index 000000000..3a60f6ef9 --- /dev/null +++ b/systemregistry/src/test/java/eu/arrowhead/common/database/service/SystemRepositoryTest.java @@ -0,0 +1,71 @@ +package eu.arrowhead.common.database.service; + +import eu.arrowhead.common.database.entity.System; +import eu.arrowhead.common.database.repository.SystemRepository; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; +import org.springframework.test.context.TestPropertySource; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.List; +import java.util.Optional; + +@RunWith(SpringRunner.class) +@DataJpaTest +@TestPropertySource(properties = { + "spring.jpa.hibernate.ddl-auto=create" +}) +@Sql(scripts = "classpath:/sql/systems.sql") +public class SystemRepositoryTest { + + @Autowired + private SystemRepository systemRepository; + + @Test + public void injectedComponentsAreNotNull() { + Assert.assertNotNull(systemRepository); + } + + @Test + public void findBySystemNameAndAddressAndPort() { + final Optional system1 = systemRepository.findBySystemNameAndAddressAndPort("system1", "192.168.1.1", 1); + Assert.assertTrue(system1.isPresent()); + } + + @Test + public void findBySystemNameAndAddressAndPort_nonExistentName() { + final Optional system1 = systemRepository.findBySystemNameAndAddressAndPort("system", "192.168.1.1", 1); + Assert.assertFalse(system1.isPresent()); + } + + @Test + public void findBySystemNameAndAddressAndPort_nonExistentAddress() { + final Optional system1 = systemRepository.findBySystemNameAndAddressAndPort("system1", "192.168.1.10", 1); + Assert.assertFalse(system1.isPresent()); + } + + @Test + public void findBySystemNameAndAddressAndPort_nonExistentPort() { + final Optional system1 = systemRepository.findBySystemNameAndAddressAndPort("system1", "192.168.1.1", 10); + Assert.assertFalse(system1.isPresent()); + } + + @Test + public void findBySystemName() { + final List systems2 = systemRepository.findBySystemName("system2"); + Assert.assertEquals(2, systems2.size()); + + final List systems3 = systemRepository.findBySystemName("system3"); + Assert.assertEquals(3, systems3.size()); + } + + @Test + public void findBySystemName_nonExistent() { + final List systems2 = systemRepository.findBySystemName("system"); + Assert.assertEquals(0, systems2.size()); + } +} \ No newline at end of file diff --git a/systemregistry/src/test/java/eu/arrowhead/core/systemregistry/StandaloneModeInSystemRegistryTests.java b/systemregistry/src/test/java/eu/arrowhead/core/systemregistry/StandaloneModeInSystemRegistryTests.java new file mode 100644 index 000000000..1029b04a4 --- /dev/null +++ b/systemregistry/src/test/java/eu/arrowhead/core/systemregistry/StandaloneModeInSystemRegistryTests.java @@ -0,0 +1,9 @@ +package eu.arrowhead.core.systemregistry; + +import eu.arrowhead.common.testhelper.StandaloneModeInTests; +import org.springframework.stereotype.Component; + +@Component +public class StandaloneModeInSystemRegistryTests extends StandaloneModeInTests { + +} \ No newline at end of file diff --git a/systemregistry/src/test/java/eu/arrowhead/core/systemregistry/SystemRegistryControllerSystemRegistryTest.java b/systemregistry/src/test/java/eu/arrowhead/core/systemregistry/SystemRegistryControllerSystemRegistryTest.java new file mode 100644 index 000000000..1188ee1b1 --- /dev/null +++ b/systemregistry/src/test/java/eu/arrowhead/core/systemregistry/SystemRegistryControllerSystemRegistryTest.java @@ -0,0 +1,434 @@ +package eu.arrowhead.core.systemregistry; + +import com.fasterxml.jackson.databind.ObjectMapper; +import eu.arrowhead.common.dto.internal.SystemRegistryListResponseDTO; +import eu.arrowhead.common.dto.shared.DeviceRequestDTO; +import eu.arrowhead.common.dto.shared.DeviceResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryRequestDTO; +import eu.arrowhead.common.dto.shared.SystemRegistryResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.common.exception.InvalidParameterException; +import eu.arrowhead.core.systemregistry.database.service.SystemRegistryDBService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@SpringBootTest +@ContextConfiguration(classes = {SystemRegistryTestContext.class}) +public class SystemRegistryControllerSystemRegistryTest { + + + //================================================================================================= + // test data + private final static String DATE_STRING = "2020-01-01T00:00:00"; + + private final static long VALID_SYSTEM_ID = 1L; + private final static long VALID_DEVICE_ID = 1L; + + private final static long VALID_SYSTEM_REGISTRY_ID = 1L; + private final static long UNKNOWN_SYSTEM_REGISTRY_ID = 2L; + private final static long INVALID_SYSTEM_REGISTRY_ID = -1L; + + private final static String VALID_DEVICE_NAME = "device"; + private final static String VALID_SYSTEM_NAME = "system"; + private final static String UNKNOWN_SYSTEM_NAME = "unknown"; + private final static String INVALID_SYSTEM_NAME = ""; + + private static final SystemRequestDTO VALID_SYSTEM_REQUEST = + new SystemRequestDTO("system", "address", 80, "authenticationInfo"); + private final static SystemResponseDTO VALID_SYSTEM = + new SystemResponseDTO(VALID_SYSTEM_ID, VALID_SYSTEM_NAME, "address", 80, + "authenticationInfo", DATE_STRING, DATE_STRING); + + private final static DeviceRequestDTO VALID_DEVICE_REQUEST = + new DeviceRequestDTO(VALID_DEVICE_NAME, "address", "macAddress", "authenticationInfo"); + private final static DeviceResponseDTO VALID_DEVICE = + new DeviceResponseDTO(VALID_DEVICE_ID, VALID_DEVICE_NAME, "address", "macAddress", + "authenticationInfo", DATE_STRING, DATE_STRING); + + private final static SystemRegistryResponseDTO VALID_SYSTEM_REGISTRY = + new SystemRegistryResponseDTO(VALID_SYSTEM_REGISTRY_ID, VALID_SYSTEM, VALID_DEVICE, DATE_STRING, + null, 1, DATE_STRING, DATE_STRING); + + + //================================================================================================= + // members + + @Autowired + private WebApplicationContext wac; + + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean(name = "mockSystemRegistryDBService") + private SystemRegistryDBService systemRegistryDBService; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Before + public void setup() { + reset(systemRegistryDBService); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } + + @Test + public void getSystemRegistryEntriesWithoutParameter() throws Exception { + final SystemRegistryListResponseDTO systemListResponseDTO = new SystemRegistryListResponseDTO(List.of(VALID_SYSTEM_REGISTRY), 1); + when(systemRegistryDBService.getSystemRegistryEntries(any(), any())).thenReturn(systemListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get("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/systemregistry/mgmt") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final SystemRegistryListResponseDTO responseBody = readResponse(response, SystemRegistryListResponseDTO.class); + assertEquals(1, responseBody.getCount()); + } + + @Test + public void getSystemRegistryEntriesWithPageAndSizeParameter() throws Exception { + final SystemRegistryListResponseDTO systemListResponseDTO = new SystemRegistryListResponseDTO(List.of(VALID_SYSTEM_REGISTRY), 1); + when(systemRegistryDBService.getSystemRegistryEntries(any(), any())).thenReturn(systemListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get("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/systemregistry/mgmt") + .param("page", "0") + .param("item_per_page", String.valueOf(5)) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final SystemRegistryListResponseDTO responseBody = readResponse(response, SystemRegistryListResponseDTO.class); + assertEquals(1, responseBody.getCount()); + } + + @Test + public void getSystemRegistryEntryById() throws Exception { + when(systemRegistryDBService.getSystemRegistryById(VALID_SYSTEM_REGISTRY_ID)).thenReturn(VALID_SYSTEM_REGISTRY); + final MvcResult response = this.mockMvc.perform(get("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/systemregistry/mgmt/" + VALID_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final SystemRegistryResponseDTO responseDTO = readResponse(response, SystemRegistryResponseDTO.class); + assertEquals(VALID_SYSTEM_REGISTRY, responseDTO); + } + + @Test + public void getSystemRegistryEntryByIdUnknownId() throws Exception { + when(systemRegistryDBService.getSystemRegistryById(UNKNOWN_SYSTEM_REGISTRY_ID)).thenThrow( + new InvalidParameterException("System Registry with id " + UNKNOWN_SYSTEM_REGISTRY_ID + " not found.")); + + this.mockMvc.perform(get("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/systemregistry/mgmt/" + UNKNOWN_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void getSystemRegistryEntryByIdNegativeId() throws Exception { + this.mockMvc.perform(get("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/systemregistry/mgmt/" + INVALID_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void getSystemRegistryEntriesBySystemName() throws Exception { + final SystemRegistryListResponseDTO systemListResponseDTO = new SystemRegistryListResponseDTO(List.of(VALID_SYSTEM_REGISTRY), 1); + when(systemRegistryDBService.getSystemRegistryEntriesBySystemName(eq(VALID_SYSTEM_NAME), any(), any())) + .thenReturn(systemListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get("/systemregistry/mgmt/systemname/" + VALID_SYSTEM_NAME) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final SystemRegistryListResponseDTO responseBody = readResponse(response, SystemRegistryListResponseDTO.class); + assertEquals(1, responseBody.getCount()); + } + + @Test + public void getSystemRegistryEntriesByUnknownSystemName() throws Exception { + final SystemRegistryListResponseDTO systemListResponseDTO = new SystemRegistryListResponseDTO(List.of(), 0); + when(systemRegistryDBService.getSystemRegistryEntriesBySystemName(eq(UNKNOWN_SYSTEM_NAME), any(), any())) + .thenReturn(systemListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get("/systemregistry/mgmt/systemname/" + UNKNOWN_SYSTEM_NAME) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final SystemRegistryListResponseDTO responseBody = readResponse(response, SystemRegistryListResponseDTO.class); + assertEquals(0, responseBody.getCount()); + } + + @Test + public void getSystemRegistryEntriesByInvalidSystemName() throws Exception { + this.mockMvc.perform(get("/systemregistry/mgmt/systemname/" + INVALID_SYSTEM_NAME) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void removeSystemRegistryEntryByInvalidId() throws Exception { + this.mockMvc.perform(delete("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/systemregistry/mgmt/" + INVALID_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void removeSystemRegistryEntryByUnknownId() throws Exception { + doThrow(new InvalidParameterException("No system registry with id : " + UNKNOWN_SYSTEM_REGISTRY_ID)) + .when(systemRegistryDBService) + .removeSystemRegistryEntryById(eq(UNKNOWN_SYSTEM_REGISTRY_ID)); + + this.mockMvc.perform(delete("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/systemregistry/mgmt/" + UNKNOWN_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void removeSystemRegistryEntryById() throws Exception { + + this.mockMvc.perform(delete("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/systemregistry/mgmt/" + VALID_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + } + + @Test + public void updateSystemRegistryRequest() throws Exception { + final SystemRegistryRequestDTO dto = new SystemRegistryRequestDTO(VALID_SYSTEM_REQUEST, VALID_DEVICE_REQUEST, null, null, 1); + when(systemRegistryDBService.updateSystemRegistryById(eq(VALID_SYSTEM_REGISTRY_ID), any())).thenReturn(VALID_SYSTEM_REGISTRY); + + final MvcResult result = this.mockMvc.perform(put("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/systemregistry/mgmt/" + VALID_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + assertEquals(VALID_SYSTEM_REGISTRY, objectMapper.readValue(result.getResponse().getContentAsString(), SystemRegistryResponseDTO.class)); + } + + @Test + public void updateSystemRegistryUnknownId() throws Exception { + final SystemRegistryRequestDTO dto = new SystemRegistryRequestDTO(VALID_SYSTEM_REQUEST, VALID_DEVICE_REQUEST, null, null, 1); + when(systemRegistryDBService.updateSystemRegistryById(eq(UNKNOWN_SYSTEM_REGISTRY_ID), any())) + .thenThrow(new InvalidParameterException("No system registry with id : " + UNKNOWN_SYSTEM_REGISTRY_ID)); + + this.mockMvc.perform(put("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/systemregistry/mgmt/" + UNKNOWN_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateSystemRegistryInvalidId() throws Exception { + final SystemRegistryRequestDTO dto = new SystemRegistryRequestDTO(VALID_SYSTEM_REQUEST, VALID_DEVICE_REQUEST, null, null, 1); + this.mockMvc.perform(put("/systemregistry/mgmt/systems/" + INVALID_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateSystemRegistryNullPayload() throws Exception { + when(systemRegistryDBService.updateSystemRegistryById(eq(VALID_SYSTEM_REGISTRY_ID), any())).thenReturn(VALID_SYSTEM_REGISTRY); + this.mockMvc.perform(put("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(null))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void mergeSystemWithOneField() throws Exception { + SystemRegistryRequestDTO dto = null; + when(systemRegistryDBService.mergeSystemRegistryById(eq(VALID_SYSTEM_REGISTRY_ID), any())).thenReturn(VALID_SYSTEM_REGISTRY); + + dto = new SystemRegistryRequestDTO(); + dto.setSystem(VALID_SYSTEM_REQUEST); + this.mockMvc.perform(patch("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/systemregistry/mgmt/" + VALID_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + + dto = new SystemRegistryRequestDTO(); + dto.setEndOfValidity(DATE_STRING); + this.mockMvc.perform(patch("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/systemregistry/mgmt/" + VALID_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + + dto = new SystemRegistryRequestDTO(); + dto.setMetadata(Map.of()); + this.mockMvc.perform(patch("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/systemregistry/mgmt/" + VALID_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + + dto = new SystemRegistryRequestDTO(); + dto.setVersion(2); + this.mockMvc.perform(patch("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/systemregistry/mgmt/" + VALID_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + } + + @Test + public void mergeSystemWithEmpty() throws Exception { + final SystemRegistryRequestDTO dto = new SystemRegistryRequestDTO(); + when(systemRegistryDBService.mergeSystemRegistryById(eq(VALID_SYSTEM_REGISTRY_ID), any())).thenReturn(VALID_SYSTEM_REGISTRY); + + this.mockMvc.perform(patch("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/systemregistry/mgmt/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void mergeSystemUnknownId() throws Exception { + final SystemRegistryRequestDTO dto = new SystemRegistryRequestDTO(VALID_SYSTEM_REQUEST, VALID_DEVICE_REQUEST, DATE_STRING, null, 1); + when(systemRegistryDBService.mergeSystemRegistryById(eq(UNKNOWN_SYSTEM_REGISTRY_ID), any())) + .thenThrow(new InvalidParameterException("No system with id : " + UNKNOWN_SYSTEM_REGISTRY_ID)); + + this.mockMvc.perform(patch("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/systemregistry/mgmt/" + UNKNOWN_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void mergeSystemInvalidId() throws Exception { + final SystemRegistryRequestDTO dto = new SystemRegistryRequestDTO(VALID_SYSTEM_REQUEST, VALID_DEVICE_REQUEST, DATE_STRING, null, 1); + + this.mockMvc.perform(patch("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/systemregistry/mgmt/" + INVALID_SYSTEM_REGISTRY_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void registerSystemNullPayload() throws Exception { + when(systemRegistryDBService.registerSystemRegistry(any())).thenReturn(VALID_SYSTEM_REGISTRY); + + this.mockMvc.perform(post("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/systemregistry/register") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(null))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void registerSystemNullEndOfValidity() throws Exception { + final SystemRegistryRequestDTO systemRegistryRequestDTO = + new SystemRegistryRequestDTO(VALID_SYSTEM_REQUEST, VALID_DEVICE_REQUEST, null, null, 1); + + when(systemRegistryDBService.registerSystemRegistry(any())).thenReturn(VALID_SYSTEM_REGISTRY); + + this.mockMvc.perform(post("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/systemregistry/register") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(systemRegistryRequestDTO))) + .andExpect(status().isCreated()) + .andReturn(); + } + + @Test + public void registerSystemInvalidEndOfValidity() throws Exception { + final SystemRegistryRequestDTO systemRegistryRequestDTO = + new SystemRegistryRequestDTO(VALID_SYSTEM_REQUEST, VALID_DEVICE_REQUEST, "not parsable", null, 1); + + when(systemRegistryDBService.registerSystemRegistry(any())).thenReturn(VALID_SYSTEM_REGISTRY); + + this.mockMvc.perform(post("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/systemregistry/register") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(systemRegistryRequestDTO))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void unregisterSystemNullSystemName() throws Exception { + this.mockMvc.perform(delete("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/systemregistry/unregister") + .param("system_name", "") + .param("port", "80")) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void unregisterSystemNullPort() throws Exception { + this.mockMvc.perform(delete("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/systemregistry/unregister") + .param("system_name", "system") + .param("port", "")) + .andExpect(status().isBadRequest()) + .andReturn(); + } + //================================================================================================= + // Tests of system registry + + private T readResponse(final MvcResult result, final Class clz) throws IOException { + return objectMapper.readValue(result.getResponse().getContentAsString(), clz); + } +} \ No newline at end of file diff --git a/systemregistry/src/test/java/eu/arrowhead/core/systemregistry/SystemRegistryControllerSystemTest.java b/systemregistry/src/test/java/eu/arrowhead/core/systemregistry/SystemRegistryControllerSystemTest.java new file mode 100644 index 000000000..d4a3e0cb5 --- /dev/null +++ b/systemregistry/src/test/java/eu/arrowhead/core/systemregistry/SystemRegistryControllerSystemTest.java @@ -0,0 +1,496 @@ +package eu.arrowhead.core.systemregistry; + +import com.fasterxml.jackson.databind.ObjectMapper; +import eu.arrowhead.common.dto.internal.SystemListResponseDTO; +import eu.arrowhead.common.dto.shared.SystemRequestDTO; +import eu.arrowhead.common.dto.shared.SystemResponseDTO; +import eu.arrowhead.common.exception.InvalidParameterException; +import eu.arrowhead.core.systemregistry.database.service.SystemRegistryDBService; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.http.MediaType; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.context.WebApplicationContext; + +import java.io.IOException; +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@SpringBootTest +@ContextConfiguration(classes = {SystemRegistryTestContext.class}) +public class SystemRegistryControllerSystemTest { + + + //================================================================================================= + // test data + private final static long VALID_SYSTEM_ID = 1L; + private final static long UNKNOWN_SYSTEM_ID = 2L; + private final static long NEGATIVE_SYSTEM_ID = -1L; + + private final static SystemResponseDTO VALID_SYSTEM = + new SystemResponseDTO(VALID_SYSTEM_ID, "system", "address", 80, + "authenticationInfo", "2020-01-01T00:00:00", "2020-01-01T00:00:00"); + + + //================================================================================================= + // members + + @Autowired + private WebApplicationContext wac; + + private MockMvc mockMvc; + + @Autowired + private ObjectMapper objectMapper; + + @MockBean(name = "mockSystemRegistryDBService") + private SystemRegistryDBService systemRegistryDBService; + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Before + public void setup() { + reset(systemRegistryDBService); + this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); + } + + //================================================================================================= + // Tests of system registry + + @Test + public void echoOnboarding() throws Exception { + final MvcResult response = this.mockMvc.perform(get("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/systemregistry/echo") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + assertEquals("Got it!", response.getResponse().getContentAsString()); + } + + @Test + public void getSystemById() throws Exception { + when(systemRegistryDBService.getSystemById(VALID_SYSTEM_ID)).thenReturn(VALID_SYSTEM); + final MvcResult response = this.mockMvc.perform(get("/systemregistry/mgmt/system/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final SystemResponseDTO responseDTO = readResponse(response, SystemResponseDTO.class); + assertEquals(VALID_SYSTEM, responseDTO); + } + + @Test + public void getSystemByUnknownId() throws Exception { + when(systemRegistryDBService.getSystemById(UNKNOWN_SYSTEM_ID)) + .thenThrow(new InvalidParameterException("System with id " + UNKNOWN_SYSTEM_ID + " not found.")); + + this.mockMvc.perform(get("/systemregistry/mgmt/system/" + UNKNOWN_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void getSystemByNegativeId() throws Exception { + this.mockMvc.perform(get("/systemregistry/mgmt/system/" + NEGATIVE_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void getSystemsWithoutParameter() throws Exception { + final SystemListResponseDTO systemListResponseDTO = new SystemListResponseDTO(List.of(VALID_SYSTEM), 1); + when(systemRegistryDBService.getSystemEntries(any(), any())).thenReturn(systemListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get("/systemregistry/mgmt/systems") + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final SystemListResponseDTO responseBody = readResponse(response, SystemListResponseDTO.class); + assertEquals(1, responseBody.getCount()); + } + + @Test + public void getSystemsWithPageAndSizeParameter() throws Exception { + final SystemListResponseDTO systemListResponseDTO = new SystemListResponseDTO(List.of(VALID_SYSTEM), 1); + when(systemRegistryDBService.getSystemEntries(any(), any())).thenReturn(systemListResponseDTO); + + final MvcResult response = this.mockMvc.perform(get("/systemregistry/mgmt/systems") + .param("page", "0") + .param("item_per_page", String.valueOf(5)) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + + final SystemListResponseDTO responseBody = readResponse(response, SystemListResponseDTO.class); + assertEquals(1, responseBody.getCount()); + } + + @Test + public void createSystemRequest() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", "address", 80, "authenticationInfo"); + when(systemRegistryDBService.createSystemDto(anyString(), anyString(), anyInt(), anyString())).thenReturn(VALID_SYSTEM); + + final MvcResult response = this.mockMvc.perform(post("/systemregistry/mgmt/systems") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isCreated()) + .andReturn(); + assertEquals(VALID_SYSTEM, readResponse(response, SystemResponseDTO.class)); + } + + @Test + public void createSystemRequestNullPayload() throws Exception { + when(systemRegistryDBService.createSystemDto(anyString(), anyString(), anyInt(), anyString())).thenReturn(VALID_SYSTEM); + + this.mockMvc.perform(post("/systemregistry/mgmt/systems") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(null))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void createSystemRequestNullSystemName() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO(null, "address", 80, "authenticationInfo"); + when(systemRegistryDBService.createSystemDto(anyString(), anyString(), anyInt(), anyString())).thenReturn(VALID_SYSTEM); + + this.mockMvc.perform(post("/systemregistry/mgmt/systems") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void createSystemRequestEmptySystemName() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("", "address", 80, "authenticationInfo"); + when(systemRegistryDBService.createSystemDto(anyString(), anyString(), anyInt(), anyString())).thenReturn(VALID_SYSTEM); + + this.mockMvc.perform(post("/systemregistry/mgmt/systems") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void createSystemRequestNullAddress() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", null, 80, "authenticationInfo"); + when(systemRegistryDBService.createSystemDto(anyString(), anyString(), anyInt(), anyString())).thenReturn(VALID_SYSTEM); + + this.mockMvc.perform(post("/systemregistry/mgmt/systems") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void createSystemRequestEmptyAddress() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", "", 80, "authenticationInfo"); + when(systemRegistryDBService.createSystemDto(anyString(), anyString(), anyInt(), anyString())).thenReturn(VALID_SYSTEM); + + this.mockMvc.perform(post("/systemregistry/mgmt/systems") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void createSystemRequestNullPort() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", "address", null, "authenticationInfo"); + when(systemRegistryDBService.createSystemDto(anyString(), anyString(), anyInt(), anyString())).thenReturn(VALID_SYSTEM); + + this.mockMvc.perform(post("/systemregistry/mgmt/systems") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void createSystemRequestZeroPort() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", "address", 0, "authenticationInfo"); + when(systemRegistryDBService.createSystemDto(anyString(), anyString(), anyInt(), anyString())).thenReturn(VALID_SYSTEM); + + this.mockMvc.perform(post("/systemregistry/mgmt/systems/") + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateSystemRequest() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", "address", 80, "authenticationInfo"); + when(systemRegistryDBService.updateSystemDto(eq(VALID_SYSTEM_ID), anyString(), anyString(), anyInt(), anyString())) + .thenReturn(VALID_SYSTEM); + + final MvcResult response = this.mockMvc.perform(put("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + assertEquals(VALID_SYSTEM, readResponse(response, SystemResponseDTO.class)); + } + + @Test + public void updateSystemUnknownId() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", "address", 80, "authenticationInfo"); + when(systemRegistryDBService.updateSystemDto(eq(UNKNOWN_SYSTEM_ID), anyString(), anyString(), anyInt(), anyString())) + .thenThrow(new InvalidParameterException("No system with id : " + UNKNOWN_SYSTEM_ID)); + + this.mockMvc.perform(put("/systemregistry/mgmt/systems/" + UNKNOWN_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateSystemInvalidId() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", "address", 80, "authenticationInfo"); + + this.mockMvc.perform(put("/systemregistry/mgmt/systems/" + NEGATIVE_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateSystemRequestNullPayload() throws Exception { + when(systemRegistryDBService.updateSystemDto(eq(VALID_SYSTEM_ID), anyString(), anyString(), anyInt(), anyString())) + .thenReturn(VALID_SYSTEM); + this.mockMvc.perform(put("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(null))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateSystemRequestNullSystemName() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO(null, "address", 80, "authenticationInfo"); + this.mockMvc.perform(put("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateSystemRequestEmptySystemName() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("", "address", 80, "authenticationInfo"); + this.mockMvc.perform(put("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateSystemRequestNullAddress() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", null, 80, "authenticationInfo"); + this.mockMvc.perform(put("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateSystemRequestEmptyAddress() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", "", 80, "authenticationInfo"); + this.mockMvc.perform(put("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateSystemRequestNullPort() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", "address", null, "authenticationInfo"); + this.mockMvc.perform(put("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void updateSystemRequestZeroPort() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", "address", 0, "authenticationInfo"); + this.mockMvc.perform(put("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void mergeSystemWithOneField() throws Exception { + SystemRequestDTO dto = null; + when(systemRegistryDBService.mergeSystemResponse(eq(VALID_SYSTEM_ID), anyString(), anyString(), anyInt(), anyString())).thenReturn(VALID_SYSTEM); + + dto = new SystemRequestDTO(); + dto.setSystemName("not empty"); + this.mockMvc.perform(patch("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + + dto = new SystemRequestDTO(); + dto.setPort(80); + this.mockMvc.perform(patch("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + + dto = new SystemRequestDTO(); + dto.setAddress("not empty"); + this.mockMvc.perform(patch("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + + dto = new SystemRequestDTO(); + dto.setAuthenticationInfo("not empty"); + this.mockMvc.perform(patch("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isOk()) + .andReturn(); + } + + @Test + public void mergeSystemWithEmpty() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO(); + when(systemRegistryDBService.mergeSystemResponse(eq(VALID_SYSTEM_ID), anyString(), anyString(), anyInt(), anyString())).thenReturn(VALID_SYSTEM); + + this.mockMvc.perform(patch("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void mergeSystemUnknownId() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", "address", 80, "authenticationInfo"); + when(systemRegistryDBService.mergeSystemResponse(eq(UNKNOWN_SYSTEM_ID), anyString(), anyString(), anyInt(), anyString())) + .thenThrow(new InvalidParameterException("No system with id : " + UNKNOWN_SYSTEM_ID)); + + this.mockMvc.perform(patch("/systemregistry/mgmt/systems/" + UNKNOWN_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void mergeSystemInvalidId() throws Exception { + final SystemRequestDTO dto = new SystemRequestDTO("system", "address", 80, "authenticationInfo"); + + this.mockMvc.perform(patch("/systemregistry/mgmt/systems/" + NEGATIVE_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON) + .content(objectMapper.writeValueAsString(dto))) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void removeSystemInvalidId() throws Exception { + this.mockMvc.perform(delete("/systemregistry/mgmt/systems/" + NEGATIVE_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void removeSystemUnknownId() throws Exception { + doThrow(new InvalidParameterException("No system with id : " + UNKNOWN_SYSTEM_ID)) + .when(systemRegistryDBService) + .removeSystemById(eq(UNKNOWN_SYSTEM_ID)); + + this.mockMvc.perform(delete("/systemregistry/mgmt/systems/" + UNKNOWN_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isBadRequest()) + .andReturn(); + } + + @Test + public void removeSystem() throws Exception { + + this.mockMvc.perform(delete("/systemregistry/mgmt/systems/" + VALID_SYSTEM_ID) + .accept(MediaType.APPLICATION_JSON) + .contentType(MediaType.APPLICATION_JSON)) + .andExpect(status().isOk()) + .andReturn(); + } + //================================================================================================= + // Tests of system registry + + private T readResponse(final MvcResult response, final Class clz) throws IOException { + return objectMapper.readValue(response.getResponse().getContentAsString(), clz); + } +} \ No newline at end of file diff --git a/systemregistry/src/test/java/eu/arrowhead/core/systemregistry/SystemRegistryTestContext.java b/systemregistry/src/test/java/eu/arrowhead/core/systemregistry/SystemRegistryTestContext.java new file mode 100644 index 000000000..064312019 --- /dev/null +++ b/systemregistry/src/test/java/eu/arrowhead/core/systemregistry/SystemRegistryTestContext.java @@ -0,0 +1,50 @@ +package eu.arrowhead.core.systemregistry; + +import eu.arrowhead.common.CommonConstants; +import eu.arrowhead.common.database.repository.CloudRepository; +import eu.arrowhead.common.database.service.CommonDBService; +import eu.arrowhead.core.systemregistry.database.service.SystemRegistryDBService; +import org.mockito.Mockito; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; +import org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration; +import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.FilterType; +import org.springframework.context.annotation.Primary; + +@Configuration +@ComponentScan(basePackages = CommonConstants.BASE_PACKAGE, + excludeFilters = { + @ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*database.*"), + @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SystemRegistryMain.class), + }) +@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class}) +public class SystemRegistryTestContext { + + //================================================================================================= + // methods + + //------------------------------------------------------------------------------------------------- + @Bean + @Primary // This bean is primary only in test context + public SystemRegistryDBService mockSystemRegistryDBService() { + return Mockito.mock(SystemRegistryDBService.class); + } + + //------------------------------------------------------------------------------------------------- + @Bean + @Primary // This bean is primary only in test context + public CommonDBService mockCommonDBService() { + return Mockito.mock(CommonDBService.class); + } + + //------------------------------------------------------------------------------------------------- + @Bean + @Primary // This bean is primary only in test context + public CloudRepository mockCloudRepository() { + return Mockito.mock(CloudRepository.class); + } +} \ No newline at end of file diff --git a/systemregistry/src/test/resources/banner.txt b/systemregistry/src/test/resources/banner.txt new file mode 100644 index 000000000..e69de29bb diff --git a/systemregistry/src/test/resources/log4j2.xml b/systemregistry/src/test/resources/log4j2.xml new file mode 100644 index 000000000..ec4482ce9 --- /dev/null +++ b/systemregistry/src/test/resources/log4j2.xml @@ -0,0 +1,45 @@ + + + + + %d{yyyy-MM-dd HH:mm:ss.SSS} %5p ${hostName} --- [%15.15t] %-40.40c{1.} : %m%n%ex + + OFF + OFF + + + + + + + + ${LOG_PATTERN} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/systemregistry/src/test/resources/sql/device.sql b/systemregistry/src/test/resources/sql/device.sql new file mode 100644 index 000000000..e6ab7fa20 --- /dev/null +++ b/systemregistry/src/test/resources/sql/device.sql @@ -0,0 +1,7 @@ +insert into device (id, device_name, address, mac_address, authentication_info, created_at, updated_at) +values (1, 'device1', '192.168.1.1', '01:23:45:67:89:AB', null, '2020-01-01 00:00:00', '2020-01-01 00:00:00'), + (2, 'device1', '192.168.1.2', '02:23:45:67:89:AB', null, '2020-01-02 00:00:00', '2020-01-02 00:00:00'), + (3, 'device2', '192.168.2.3', '03:23:45:67:89:AB', null, '2020-01-03 00:00:00', '2020-01-03 00:00:00'), + (4, 'device2', '192.168.2.4', '04:23:45:67:89:AB', null, '2020-01-04 00:00:00', '2020-01-04 00:00:00'), + (5, 'device3', '192.168.3.5', '05:23:45:67:89:AB', null, '2020-01-05 00:00:00', '2020-01-05 00:00:00'), + (6, 'device3', '192.168.3.6', '06:23:45:67:89:AB', null, '2020-01-06 00:00:00', '2020-01-06 00:00:00'); \ No newline at end of file diff --git a/systemregistry/src/test/resources/sql/systems.sql b/systemregistry/src/test/resources/sql/systems.sql new file mode 100644 index 000000000..a4d351902 --- /dev/null +++ b/systemregistry/src/test/resources/sql/systems.sql @@ -0,0 +1,7 @@ +insert into system_ (id, address, authentication_info, created_at, port, system_name, updated_at) +values (1, '192.168.1.1', null, '2020-01-01 00:00:00', 1, 'system1', '2020-01-01 00:00:00'), + (2, '192.168.1.2', null, '2020-01-02 00:00:00', 2, 'system2', '2020-01-02 00:00:00'), + (3, '192.168.2.2', null, '2020-01-03 00:00:00', 2, 'system2', '2020-01-03 00:00:00'), + (4, '192.168.1.3', null, '2020-01-04 00:00:00', 3, 'system3', '2020-01-04 00:00:00'), + (5, '192.168.2.3', null, '2020-01-05 00:00:00', 3, 'system3', '2020-01-05 00:00:00'), + (6, '192.168.3.3', null, '2020-01-06 00:00:00', 3, 'system3', '2020-01-06 00:00:00'); \ No newline at end of file