diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..f53cebc
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,27 @@
+# docker build -t $DOCKER_BUILD_NAME \
+# --build-arg="MVN_FINALNAME=$MVN_FINALNAME" \
+# --build-arg="MVN_NAME=${MVN_NAME}" \
+# --build-arg="CONTAINER_INI=${CONTAINER_INI}" \
+# --build-arg="JAVA_VERSION=${JAVA_VERSION}" \
+# --build-arg="SMARTGEARS_VERSION=${SMARTGEARS_VERSION}" \
+# -f Dockerfile \
+# $PLATFORMS .
+
+ARG JAVA_VERSION
+ARG SMARTGEARS_VERSION
+
+#FROM d4science/smartgears-distribution:${SMARTGEARS_VERSION}-java${JAVA_VERSION}-tomcat10.1.19
+FROM hub.dev.d4science.org/gcube/smartgears-distribution:${SMARTGEARS_VERSION}-java${JAVA_VERSION}-tomcat10.1.19
+ ARG CONTAINER_INI="./dockerize/configuration/container.ini"
+ ARG MVN_FINALNAME
+ ARG MVN_NAME
+
+ #FROM smartgears-distribution:${SMARTGEARS_VERSION}-java${JAVA_VERSION}-tomcat10.1.19
+
+ COPY ./dockerize/configuration/logback.xml /etc/
+ COPY ./dockerize/configuration/*.gcubekey /tomcat/lib
+ COPY ./target/${MVN_FINALNAME}.war /tmp
+ RUN unzip /tmp/${MVN_FINALNAME}.war -d /tomcat/webapps/${MVN_NAME}
+ COPY ${CONTAINER_INI} /etc/container.ini
+
+ EXPOSE 8080
diff --git a/dockerize/buildImageAndStart.sh b/dockerize/buildImageAndStart.sh
new file mode 100755
index 0000000..3a06d1d
--- /dev/null
+++ b/dockerize/buildImageAndStart.sh
@@ -0,0 +1,180 @@
+#!/bin/bash
+
+# set -x # uncomment to debug script
+set -a
+source ./build_conf
+set +a
+
+ACCEPTED_JAVA_VERSIONs=(11 17)
+PORT=8080
+DEBUG_PORT=5005
+DEBUG=false
+EXECUTE=false
+TEST=false
+COMPILE=true
+
+GOAL="clean package"
+
+PUSH_DOCKER=false
+PUSH_HARBOR=false
+LOGIN_HARBOR=false
+
+################################################################################
+# Help #
+################################################################################
+Help() {
+ # Display Help
+ echo "build, create and run in docker the identity manager service"
+ echo
+ echo "Syntax: buildDistribution "
+ echo "options:"
+
+ echo "-e execute the docker image"
+ echo "-g arg specifies the maven [g]oals {package, install, deploy etc} default is $GOAL."
+ echo "-d arg? enable java debug mode for execution"
+
+ echo "-r push image to d4science harbo[r] (with login already done, or -l to login)"
+ echo "-u p[u]sh image to dockerhub (with docker login already done)"
+
+ echo "-p arg specifies the port to be exposed for the docker container to access the service (default $PORT)"
+
+ echo "-c arg path of the file to deploy as container.ini (default ./docker/container.ini)"
+
+ echo "-j arg specify java version (default is $JAVA_VERSION)"
+ echo " accepted version are: ${ACCEPTED_JAVA_VERSIONs[@]}"
+ echo " arg is the debug port (default is $DEBUG_PORT)"
+
+ echo "-s skip maven package"
+ echo "-t exec also maven tests"
+
+ echo "-n arg specifies the docker image name (default is $MVN_NAME)."
+
+ echo "-l [l]ogin to d4science harbor"
+ echo "-h Print this Help."
+ echo
+ echo "to compile and push to harbor registry with a custom container.ini file: "
+ echo " ./buildImageAndStart.sh -r -m -l -c \"./docker/container-XXX.ini\" "
+ echo
+ echo "to debug locally: "
+ echo " ./buildImageAndStart.sh -d "
+}
+
+################################################################################
+################################################################################
+# Main program #
+################################################################################
+################################################################################
+
+set -e
+
+#OPTSTRING=":sn:p:d:j:?h"
+OPTSTRING=":c:n:p:g:d:?jsmulrteh"
+
+while getopts $OPTSTRING opt; do
+ # echo "Option -${opt} was triggered, Argument: ${OPTARG}"
+ case "${opt}" in
+ s) COMPILE=false && echo "compile $COMPILE" ;;
+ g) GOAL=${OPTARG} ;;
+ c)
+ CONTAINER_INI=${OPTARG}
+ echo "CONTAINER_INI: $CONTAINER_INI"
+ ;;
+ m) MULTI_PLATFORM=true ;;
+ n) NAME=${OPTARG} ;;
+ p) PORT=${OPTARG} ;;
+
+ u) PUSH_DOCKER=true ;;
+ l) LOGIN_HARBOR=true ;;
+ r) PUSH_HARBOR=true ;;
+
+ t) TEST=true ;;
+ e) EXECUTE=true ;;
+ d)
+ DEBUG=true
+ DEBUG_PORT=${OPTARG}
+ echo "debug enabled, port $DEBUG_PORT, execute $EXECUTE"
+ ;;
+ j)
+ if [[ ${ACCEPTED_JAVA_VERSIONs[@]} =~ ${OPTARG} ]]; then
+ JAVA_VERSION=${OPTARG}
+ else
+ echo "Invalid java version" && echo "accepted version are: ${ACCEPTED_JAVA_VERSIONs[@]}" && exit 1
+ fi
+ ;;
+ h) Help && exit 0 ;;
+
+ :)
+ # matched when an option that is expected to have an argument is passed without one
+ if [ ${OPTARG} = "d" ]; then
+ DEBUG=true
+ EXECUTE=true
+ echo "debug enabled, port $DEBUG_PORT"
+ else
+ # matched when an option that is expected to have an argument is passed without one
+ echo "Option -${OPTARG} requires an argument."
+ exit 1
+ fi
+ ;;
+ ?) # match any invalid option that is passed
+ echo "Invalid option: -${OPTARG}."
+ exit 1
+ ;;
+ esac
+done
+
+if [ $COMPILE = true ]; then
+ SKIP_TEST=""
+ if [ $TEST = false ]; then
+ SKIP_TEST="-Dmaven.test.skip"
+ fi
+
+ ( cd .. && mvn $GOAL $SKIP_TEST );
+else
+ echo "skipping mvn package"
+fi
+
+echo "SMARTGEAR IMAGE: $SMARTGEAR_IMAGE"
+docker pull $SMARTGEAR_IMAGE
+
+if [ $MULTI_PLATFORM ]; then
+ PLATFORMS="--platform=linux/amd64,linux/arm64,linux/arm/v7"
+ echo "build multiple platform $PLATFORMS"
+fi
+
+echo "DOCKER_BUILD_NAME: $DOCKER_BUILD_NAME"
+
+( cd .. && docker build -t $DOCKER_BUILD_NAME \
+ --build-arg="MVN_FINALNAME=$MVN_FINALNAME" \
+ --build-arg="MVN_NAME=${MVN_NAME}" \
+ --build-arg="CONTAINER_INI=${CONTAINER_INI}" \
+ --build-arg="JAVA_VERSION=${JAVA_VERSION}" \
+ --build-arg="SMARTGEARS_VERSION=${SMARTGEARS_VERSION}" \
+ -f Dockerfile \
+ $PLATFORMS . );
+
+if [ ${PUSH_DOCKER} = true ]; then
+ docker tag $DOCKER_BUILD_NAME $DOCKER_IMAGE_NAME
+ docker push $DOCKER_IMAGE_NAME
+ echo ">>> pushed on dockerhub the image $DOCKER_IMAGE_NAME"
+fi
+
+if [ ${LOGIN_HARBOR} = true ]; then
+ ./loginHarborHub.sh
+fi
+
+if [ $PUSH_HARBOR = true ]; then
+ echo ">>> PUSHING on hub.dev.d4science.org the image $HARBOR_IMAGE_NAME"
+
+ docker tag $DOCKER_BUILD_NAME $HARBOR_IMAGE_NAME
+ echo ">>> docker push $HARBOR_IMAGE_NAME"
+ docker push $HARBOR_IMAGE_NAME
+ echo ">>> pushed on hub.dev.d4science.org the image $HARBOR_IMAGE_NAME"
+fi
+
+if [ ${EXECUTE} = true ]; then
+ if [ $DEBUG = true ]; then
+ docker run -p $PORT:8080 -p $DEBUG_PORT:5005 -e JAVA_TOOL_OPTIONS="-agentlib:jdwp=transport=dt_socket,address=*:5005,server=y,suspend=y" $DOCKER_BUILD_NAME
+ else
+ docker run -p $PORT:8080 $DOCKER_BUILD_NAME
+ fi
+fi
diff --git a/dockerize/build_conf b/dockerize/build_conf
new file mode 100644
index 0000000..5d16972
--- /dev/null
+++ b/dockerize/build_conf
@@ -0,0 +1,55 @@
+MVN_VERSION=$(cd .. && mvn -q \
+ -Dexec.executable=echo \
+ -Dexec.args='${project.version}' \
+ --non-recursive \
+ exec:exec)
+echo "MVN_VERSION: ${MVN_VERSION}"
+
+MVN_NAME=$(cd .. && mvn -q \
+ -Dexec.executable=echo \
+ -Dexec.args='${project.artifactId}' \
+ --non-recursive \
+ exec:exec)
+echo "MVN_NAME: ${MVN_NAME}"
+
+MVN_FINALNAME=$(cd .. && mvn -q \
+ -Dexec.executable=echo \
+ -Dexec.args='${project.build.finalName}' \
+ --non-recursive \
+ exec:exec)
+echo "MVN_FINALNAME: ${MVN_FINALNAME}"
+
+JAVA_VERSION=$(cd .. && mvn -q \
+ -Dexec.executable=echo \
+ -Dexec.args='${maven.compiler.target}' \
+ --non-recursive \
+ exec:exec)
+echo "JAVA_VERSION: ${JAVA_VERSION}"
+
+TOMCAT_VERSION=tomcat10.1.19
+echo "TOMCAT_VERSION: ${TOMCAT_VERSION}"
+
+SMARTGEARS_VERSION=$(cd .. && mvn -q \
+ -Dexec.executable=echo \
+ -Dexec.args='${docker.smartgear.version}' \
+ --non-recursive \
+ exec:exec)
+echo "SMARTGEARS_VERSION: ${SMARTGEARS_VERSION}"
+
+CONTAINER_INI="./dockerize/configuration/container.ini"
+echo "CONTAINER_INI: ${CONTAINER_INI}"
+
+IMAGE_VERSION=${MVN_VERSION}-java${JAVA_VERSION}-smartgears${SMARTGEARS_VERSION}
+echo "IMAGE_VERSION: ${IMAGE_VERSION}"
+
+DOCKER_BUILD_NAME=$MVN_NAME:$IMAGE_VERSION
+echo "DOCKER_BUILD_NAME: ${DOCKER_BUILD_NAME}"
+
+SMARTGEAR_IMAGE=hub.dev.d4science.org/gcube/smartgears-distribution:${SMARTGEARS_VERSION}-java${JAVA_VERSION}-${TOMCAT_VERSION}
+echo "SMARTGEAR_IMAGE: ${SMARTGEAR_IMAGE}"
+
+DOCKER_IMAGE_NAME=d4science/$DOCKER_BUILD_NAME
+echo "DOCKER_IMAGE_NAME: ${DOCKER_IMAGE_NAME}"
+
+HARBOR_IMAGE_NAME=hub.dev.d4science.org/gcube/$DOCKER_BUILD_NAME
+echo "HARBOR_IMAGE_NAME: ${HARBOR_IMAGE_NAME}"
diff --git a/dockerize/configuration/.gitignore b/dockerize/configuration/.gitignore
new file mode 100644
index 0000000..600791e
--- /dev/null
+++ b/dockerize/configuration/.gitignore
@@ -0,0 +1,3 @@
+container*.ini
+!container.default.ini
+*.gcubekey
\ No newline at end of file
diff --git a/dockerize/configuration/container.default.ini b/dockerize/configuration/container.default.ini
new file mode 100644
index 0000000..38e0373
--- /dev/null
+++ b/dockerize/configuration/container.default.ini
@@ -0,0 +1,26 @@
+[node]
+mode = offline
+hostname = localhost
+protocol= http
+port = 8080
+infrastructure = gcube
+authorizeChildrenContext = true
+publicationFrequencyInSeconds = 60
+
+[properties]
+SmartGearsDistribution = 4.0.1-SNAPSHOT
+SmartGearsDistributionBundle = UnBundled
+
+[site]
+country = it
+location = pisa
+
+[authorization]
+factory = org.gcube.smartgears.security.defaults.DefaultAuthorizationProviderFactory
+factory.endpoint = https://accounts.dev.d4science.org/auth/realms/d4science/protocol/openid-connect/token
+credentials.class = org.gcube.smartgears.security.SimpleCredentials
+
+credentials.clientID =
+credentials.secret =
+
+
diff --git a/dockerize/configuration/logback.xml b/dockerize/configuration/logback.xml
new file mode 100644
index 0000000..4583a72
--- /dev/null
+++ b/dockerize/configuration/logback.xml
@@ -0,0 +1,27 @@
+
+
+
+ Ï %-5level %logger{36} - %msg%n
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/dockerize/docker.conf b/dockerize/docker.conf
new file mode 100644
index 0000000..a96b5e7
--- /dev/null
+++ b/dockerize/docker.conf
@@ -0,0 +1,12 @@
+MVN_VERSION: 1.0.0-SNAPSHOT
+MVN_NAME: hello-world-service
+MVN_FINALNAME: hello-world-service-1.0.0-SNAPSHOT
+JAVA_VERSION: 11
+TOMCAT_VERSION: tomcat10.1.19
+SMARTGEARS_VERSION: 4.0.1-SNAPSHOT
+CONTAINER_INI: ./dockerize/configuration/container.ini
+IMAGE_VERSION: 1.0.0-SNAPSHOT-java11-smartgears4.0.1-SNAPSHOT
+DOCKER_BUILD_NAME: hello-world-service:1.0.0-SNAPSHOT-java11-smartgears4.0.1-SNAPSHOT
+SMARTGEAR_IMAGE: hub.dev.d4science.org/gcube/smartgears-distribution:4.0.1-SNAPSHOT-java11-tomcat10.1.19
+DOCKER_IMAGE_NAME: d4science/hello-world-service:1.0.0-SNAPSHOT-java11-smartgears4.0.1-SNAPSHOT
+HARBOR_IMAGE_NAME: hub.dev.d4science.org/gcube/hello-world-service:1.0.0-SNAPSHOT-java11-smartgears4.0.1-SNAPSHOT
diff --git a/dockerize/loginHarborHub.sh b/dockerize/loginHarborHub.sh
new file mode 100755
index 0000000..48a84cd
--- /dev/null
+++ b/dockerize/loginHarborHub.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+REGISTRY_URL="hub.dev.d4science.org"
+#USERNAME="alfredo.oliviero"
+echo "to obtain Harbor username and CLI secret:"
+echo "https://hub.dev.d4science.org/ -> user profile -> CLI secret"
+
+read -p "username:" USERNAME
+
+echo ""
+
+read -s -p "CLI secret:" ACCESS_TOKEN
+echo "$ACCESS_TOKEN" | docker login $REGISTRY_URL -u $USERNAME --password-stdin
+unset ACCESS_TOKEN
diff --git a/dockerize/pull_docker.sh b/dockerize/pull_docker.sh
new file mode 100755
index 0000000..05c16b2
--- /dev/null
+++ b/dockerize/pull_docker.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+set -a
+# source build_conf > docker.conf # generate current conf
+# source docker.conf
+source build_conf
+
+docker pull $HARBOR_IMAGE_NAME
+
+echo "Docker image $HARBOR_IMAGE_NAME"
+
+set +a
diff --git a/dockerize/start_docker.sh b/dockerize/start_docker.sh
new file mode 100755
index 0000000..2235079
--- /dev/null
+++ b/dockerize/start_docker.sh
@@ -0,0 +1,12 @@
+#!/bin/sh
+
+set -a
+# source build_conf > docker.conf # generate current conf
+# source docker.conf
+source build_conf
+
+echo "Docker image $HARBOR_IMAGE_NAME"
+docker pull $HARBOR_IMAGE_NAME
+docker run -d -p 9991:8080 --name $NAME $HARBOR_IMAGE_NAME
+
+set +a
diff --git a/dockerize/stop_docker.sh b/dockerize/stop_docker.sh
new file mode 100755
index 0000000..1d74417
--- /dev/null
+++ b/dockerize/stop_docker.sh
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+set -a
+# source build_conf > docker.conf # generate current conf
+# source docker.conf
+source build_conf
+
+docker stop $NAME
+docker rm $NAME
+
+set +a
diff --git a/documentation/.DS_Store b/documentation/.DS_Store
new file mode 100644
index 0000000..9a04531
Binary files /dev/null and b/documentation/.DS_Store differ
diff --git a/documentation/dockerizing.md b/documentation/dockerizing.md
new file mode 100644
index 0000000..85ca509
--- /dev/null
+++ b/documentation/dockerizing.md
@@ -0,0 +1,5 @@
+
+[visual studio code - Dev Containers tutorial](https://code.visualstudio.com/docs/devcontainers/tutorial)
+
+installare su vscode estensione [Dev Containers extension](vscode:extension/ms-vscode-remote.remote-containers)
+
\ No newline at end of file
diff --git a/documentation/enunciate.xml b/documentation/enunciate.xml
new file mode 100644
index 0000000..aae5fa6
--- /dev/null
+++ b/documentation/enunciate.xml
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/documentation/postman/Hello World Env for devVRE.postman_environment.json b/documentation/postman/Hello World Env for devVRE.postman_environment.json
new file mode 100644
index 0000000..02bbf3e
--- /dev/null
+++ b/documentation/postman/Hello World Env for devVRE.postman_environment.json
@@ -0,0 +1,75 @@
+{
+ "id": "ff7036fd-e12d-4dd7-9d0f-816bb5a0f06a",
+ "name": "Hello World Env for devVRE",
+ "values": [
+ {
+ "key": "introspect_secret",
+ "value": "",
+ "type": "secret",
+ "enabled": true
+ },
+ {
+ "key": "password",
+ "value": "",
+ "type": "secret",
+ "enabled": true
+ },
+{
+ "key": "service_client_secret",
+ "value": "",
+ "type": "secret",
+ "enabled": true
+ },
+ {
+ "key": "realm",
+ "value": "d4science",
+ "type": "any",
+ "enabled": true
+ },
+ {
+ "key": "username",
+ "value": "luca.frosini",
+ "type": "default",
+ "enabled": true
+ },
+ {
+ "key": "service_client_id",
+ "value": "id.d4science.org",
+ "type": "default",
+ "enabled": true
+ },
+ {
+ "key": "context",
+ "value": "/gcube/devsec/devVRE",
+ "type": "default",
+ "enabled": true
+ },
+ {
+ "key": "keycloak_url",
+ "value": "https://accounts.dev.d4science.org/auth",
+ "type": "any",
+ "enabled": true
+ },
+ {
+ "key": "encoded_context",
+ "value": "%2Fgcube%2Fdevsec%2FdevVRE",
+ "type": "any",
+ "enabled": true
+ },
+ {
+ "key": "client-id-user",
+ "value": "next.d4science.org",
+ "type": "default",
+ "enabled": true
+ },
+ {
+ "key": "introspect_client",
+ "value": "token-exchange-dedicated",
+ "type": "default",
+ "enabled": true
+ }
+ ],
+ "_postman_variable_scope": "environment",
+ "_postman_exported_at": "2024-05-24T16:06:23.560Z",
+ "_postman_exported_using": "Postman/11.1.14"
+}
\ No newline at end of file
diff --git a/documentation/postman/Hello World Service.postman_collection.json b/documentation/postman/Hello World Service.postman_collection.json
new file mode 100644
index 0000000..d843f68
--- /dev/null
+++ b/documentation/postman/Hello World Service.postman_collection.json
@@ -0,0 +1,692 @@
+{
+ "info": {
+ "_postman_id": "e152bab3-7be5-4fe2-81bd-625fec76373d",
+ "name": "Hello World Service",
+ "description": "An example collection that can be used for communicating with gcube services\n\nget TOKEN and at UMA_TOKEN from url: [https://next.dev.d4science.org/group/gcube/home](https://next.dev.d4science.org/group/gcube/home)\n\nupdate the collection's variables gcube_token and uma_token",
+ "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
+ "_exporter_id": "3092110"
+ },
+ "item": [
+ {
+ "name": "LOGIN",
+ "item": [
+ {
+ "name": "Clear Env",
+ "event": [
+ {
+ "listen": "prerequest",
+ "script": {
+ "exec": [
+ "console.log(\"executing clear script\");",
+ "",
+ "variables = [",
+ " 'token',",
+ " 'access_token',",
+ " 'refresh_token',",
+ "",
+ " 'uma_token',",
+ " 'uma_refresh',",
+ "",
+ " 'profile_token',",
+ " 'gcube_token',",
+ " 'oidc_access_token',",
+ " 'oidc_refresh_token',",
+ " 'id_token',",
+ "",
+ " 'clientId',",
+ "",
+ " 'current_username',",
+ " 'current_password',",
+ " 'current_context',",
+ " 'current_url-encoded-context',",
+ " 'current_iam-url',",
+ " 'current_client-id',",
+ " 'current_uma-token',",
+ " 'current_access-token',",
+ "",
+ " 'oidc_token',",
+ " 'oidc_access_token',",
+ " 'oidc_refresh_token',",
+ " 'uma_token',",
+ " 'exchanged_token'",
+ "",
+ "]",
+ "",
+ "for (var v of variables) {",
+ " pm.environment.unset(v);",
+ " pm.globals.unset(v);",
+ "}",
+ "",
+ " ",
+ "",
+ "",
+ " ",
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "/",
+ "path": [
+ ""
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "Get User Token For Context",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var jsonData = JSON.parse(responseBody);",
+ "postman.setEnvironmentVariable(\"oidc_access_token\", jsonData.access_token);",
+ "postman.setEnvironmentVariable(\"oidc_refresh_token\", jsonData.refresh_token);",
+ "",
+ "postman.setEnvironmentVariable(\"uma_token\", jsonData.access_token);",
+ "",
+ "postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);",
+ "postman.setEnvironmentVariable(\"refresh_token\", jsonData.refresh_token);",
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ },
+ {
+ "listen": "prerequest",
+ "script": {
+ "exec": [
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "POST",
+ "header": [
+ {
+ "key": "Content-Type",
+ "value": "application/x-www-form-urlencoded"
+ },
+ {
+ "key": "X-D4Science-Context",
+ "value": "{{encoded_context}}"
+ }
+ ],
+ "body": {
+ "mode": "urlencoded",
+ "urlencoded": [
+ {
+ "key": "client_id",
+ "value": "{{service_client_id}}",
+ "type": "text"
+ },
+ {
+ "key": "username",
+ "value": "{{username}}",
+ "type": "text"
+ },
+ {
+ "key": "password",
+ "value": "{{password}}",
+ "type": "text"
+ },
+ {
+ "key": "grant_type",
+ "value": "password",
+ "type": "text"
+ },
+ {
+ "key": "client_secret",
+ "value": "{{service_client_secret}}",
+ "type": "text"
+ }
+ ]
+ },
+ "url": {
+ "raw": "{{keycloak_url}}/realms/{{realm}}/protocol/openid-connect/token",
+ "host": [
+ "{{keycloak_url}}"
+ ],
+ "path": [
+ "realms",
+ "{{realm}}",
+ "protocol",
+ "openid-connect",
+ "token"
+ ]
+ },
+ "description": "Obtain UAT = user access token from a user in realm"
+ },
+ "response": []
+ },
+ {
+ "name": "Get ClientId Token For Context",
+ "event": [
+ {
+ "listen": "test",
+ "script": {
+ "exec": [
+ "var jsonData = JSON.parse(responseBody);",
+ "",
+ "// postman.setEnvironmentVariable(\"refresh_token\", jsonData.refresh_token);",
+ "// postman.setEnvironmentVariable(\"id_token\", jsonData.id_token);",
+ "",
+ "postman.setEnvironmentVariable(\"oidc_access_token\", jsonData.access_token);",
+ "",
+ "postman.setEnvironmentVariable(\"access_token\", jsonData.access_token);",
+ "postman.setEnvironmentVariable(\"token\", jsonData.access_token);",
+ "",
+ ""
+ ],
+ "type": "text/javascript",
+ "packages": {}
+ }
+ }
+ ],
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "POST",
+ "header": [
+ {
+ "key": "Content-Type",
+ "value": "application/x-www-form-urlencoded"
+ },
+ {
+ "key": "X-D4Science-Context",
+ "value": "{{encoded_context}}"
+ }
+ ],
+ "body": {
+ "mode": "urlencoded",
+ "urlencoded": [
+ {
+ "key": "client_id",
+ "value": "{{service_client_id}}",
+ "type": "text"
+ },
+ {
+ "key": "client_secret",
+ "value": "{{service_client_secret}}",
+ "type": "text"
+ },
+ {
+ "key": "grant_type",
+ "value": "client_credentials",
+ "type": "text"
+ }
+ ]
+ },
+ "url": {
+ "raw": "{{keycloak_url}}/realms/{{realm}}/protocol/openid-connect/token",
+ "host": [
+ "{{keycloak_url}}"
+ ],
+ "path": [
+ "realms",
+ "{{realm}}",
+ "protocol",
+ "openid-connect",
+ "token"
+ ]
+ },
+ "description": "Obtain SAT (service account token)"
+ },
+ "response": []
+ },
+ {
+ "name": "Validate Access Token",
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "POST",
+ "header": [
+ {
+ "key": "Authorization",
+ "value": "Basic YWxmcmVkby1pZG0tc2VydmljZS1kZXY6OTc5YmQzYmMtNWNjNC0xMWVjLWJmNjMtMDI0MmFjMTMwMDAy"
+ }
+ ],
+ "body": {
+ "mode": "urlencoded",
+ "urlencoded": [
+ {
+ "key": "token",
+ "value": "{{access_token}}",
+ "type": "text"
+ },
+ {
+ "key": "username\n",
+ "value": "{{introspect_client}}",
+ "type": "text",
+ "disabled": true
+ },
+ {
+ "key": "password",
+ "value": "{{introspect_secret}}",
+ "type": "text",
+ "disabled": true
+ },
+ {
+ "key": "client_id",
+ "value": "{{introspect_client}}",
+ "type": "text"
+ },
+ {
+ "key": "client_secret",
+ "value": "{{introspect_secret}}",
+ "type": "text"
+ }
+ ]
+ },
+ "url": {
+ "raw": "{{keycloak_url}}/realms/{{realm}}/protocol/openid-connect/token/introspect",
+ "host": [
+ "{{keycloak_url}}"
+ ],
+ "path": [
+ "realms",
+ "{{realm}}",
+ "protocol",
+ "openid-connect",
+ "token",
+ "introspect"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
+ {
+ "name": "REST",
+ "item": [
+ {
+ "name": "authorized",
+ "item": [
+ {
+ "name": "legacy-token",
+ "item": [
+ {
+ "name": "hello TOKEN PARAM",
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "GET",
+ "header": [
+ {
+ "key": "",
+ "value": "{{token}}"
+ }
+ ],
+ "url": {
+ "raw": "{{base_url}}/{{application}}/hello?gcube-token={{gcube_token}}",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{application}}",
+ "hello"
+ ],
+ "query": [
+ {
+ "key": "gcube-token",
+ "value": "{{gcube_token}}"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "details TOKEN PARAM",
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}/{{application}}/details?gcube-token={{gcube_token}}",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{application}}",
+ "details"
+ ],
+ "query": [
+ {
+ "key": "gcube-token",
+ "value": "{{gcube_token}}"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "auth org member TOKEN PARAM",
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}/{{application}}/auth/org_member?gcube-token={{gcube_token}}",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{application}}",
+ "auth",
+ "org_member"
+ ],
+ "query": [
+ {
+ "key": "gcube-token",
+ "value": "{{gcube_token}}"
+ }
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "auth member TOKEN PARAM",
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}/{{application}}/auth/member?gcube-token={{gcube_token}}",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{application}}",
+ "auth",
+ "member"
+ ],
+ "query": [
+ {
+ "key": "gcube-token",
+ "value": "{{gcube_token}}"
+ }
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
+ {
+ "name": "hello",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}/{{application}}/hello",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{application}}",
+ "hello"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "details",
+ "request": {
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}/{{application}}/details",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{application}}",
+ "details"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "auth org member",
+ "request": {
+ "auth": {
+ "type": "bearer",
+ "bearer": [
+ {
+ "key": "token",
+ "value": "{{uma_token}}",
+ "type": "string"
+ }
+ ]
+ },
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}/{{application}}/auth/org_member",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{application}}",
+ "auth",
+ "org_member"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "auth member",
+ "request": {
+ "auth": {
+ "type": "bearer",
+ "bearer": [
+ {
+ "key": "token",
+ "value": "{{uma_token}}",
+ "type": "string"
+ }
+ ]
+ },
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}/{{application}}/auth/member",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{application}}",
+ "auth",
+ "member"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ },
+ {
+ "name": "No Auth Required",
+ "item": [
+ {
+ "name": "guest",
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}/{{application}}/guest",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{application}}",
+ "guest"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "404 Not Found",
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}/{{application}}/guest/not-found",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{application}}",
+ "guest",
+ "not-found"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "400 Bad Request",
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "GET",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}/{{application}}/guest/bad-request",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{application}}",
+ "guest",
+ "bad-request"
+ ]
+ }
+ },
+ "response": []
+ },
+ {
+ "name": "PURGE with 204 No Content",
+ "request": {
+ "auth": {
+ "type": "noauth"
+ },
+ "method": "PURGE",
+ "header": [],
+ "url": {
+ "raw": "{{base_url}}/{{application}}/guest/test-purge",
+ "host": [
+ "{{base_url}}"
+ ],
+ "path": [
+ "{{application}}",
+ "guest",
+ "test-purge"
+ ]
+ }
+ },
+ "response": []
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "auth": {
+ "type": "bearer",
+ "bearer": [
+ {
+ "key": "token",
+ "value": "{{access_token}}",
+ "type": "string"
+ }
+ ]
+ },
+ "event": [
+ {
+ "listen": "prerequest",
+ "script": {
+ "type": "text/javascript",
+ "packages": {},
+ "exec": [
+ ""
+ ]
+ }
+ },
+ {
+ "listen": "test",
+ "script": {
+ "type": "text/javascript",
+ "packages": {},
+ "exec": [
+ ""
+ ]
+ }
+ }
+ ],
+ "variable": [
+ {
+ "key": "base_url",
+ "value": "http://localhost:8080",
+ "type": "string"
+ },
+ {
+ "key": "role_name",
+ "value": "Member"
+ },
+ {
+ "key": "application",
+ "value": "hello-world-service",
+ "type": "string"
+ },
+ {
+ "key": "base_url_marco",
+ "value": "http://146.48.85.179:9999",
+ "type": "string"
+ },
+ {
+ "key": "base_url_local",
+ "value": "http://localhost:8080",
+ "type": "string"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/documentation/sphinx/Makefile b/documentation/sphinx/Makefile
new file mode 100644
index 0000000..d4bb2cb
--- /dev/null
+++ b/documentation/sphinx/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = .
+BUILDDIR = _build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/documentation/sphinx/conf.py b/documentation/sphinx/conf.py
new file mode 100644
index 0000000..5b7a2d5
--- /dev/null
+++ b/documentation/sphinx/conf.py
@@ -0,0 +1,62 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# This file only contains a selection of the most common options. For a full
+# list see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Path setup --------------------------------------------------------------
+
+# If extensions (or modules to document with autodoc) are in another directory,
+# add these directories to sys.path here. If the directory is relative to the
+# documentation root, use os.path.abspath to make it absolute, like shown here.
+#
+import os
+# import sys
+# sys.path.insert(0, os.path.abspath('.'))
+
+_POM_PATH = "../.."
+
+def getMvnVariable(variable):
+ cmd = """cd %s && mvn -q \
+ -Dexec.executable=echo \
+ -Dexec.args='${project.%s}' \
+ --non-recursive \
+ exec:exec""" % (_POM_PATH, variable)
+ stream = os.popen(cmd)
+ return stream.read().strip()
+
+# -- Project information -----------------------------------------------------
+# The full version, including alpha/beta/rc tags
+release = getMvnVariable("version")
+project = getMvnVariable("name")
+
+copyright = '2024, %s' % getMvnVariable("organization.name")
+author = 'Luca Frosini (ISTI-CNR)'
+
+# -- General configuration ---------------------------------------------------
+
+# Add any Sphinx extension module names here, as strings. They can be
+# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
+# ones.
+extensions = []
+
+# Add any paths that contain templates here, relative to this directory.
+templates_path = ['_templates']
+
+# List of patterns, relative to source directory, that match files and
+# directories to ignore when looking for source files.
+# This pattern also affects html_static_path and html_extra_path.
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+
+# -- Options for HTML output -------------------------------------------------
+
+# The theme to use for HTML and HTML Help pages. See the documentation for
+# a list of builtin themes.
+#
+html_theme = 'sphinxdoc'
+
+# Add any paths that contain custom static files (such as style sheets) here,
+# relative to this directory. They are copied after the builtin static files,
+# so a file named "default.css" will overwrite the builtin "default.css".
+html_static_path = ['_static']
\ No newline at end of file
diff --git a/documentation/sphinx/index.rst b/documentation/sphinx/index.rst
new file mode 100644
index 0000000..7883f7a
--- /dev/null
+++ b/documentation/sphinx/index.rst
@@ -0,0 +1,258 @@
+***********************************************************
+Welcome to Hello World SG4 documentation
+***********************************************************
+
+Hello World SG4 is a RESTful application that exposes operations via REST-API.
+
+See the available `REST-API docs <../api-docs/index.html>`_.
+
+Base URL
+========
+
+In the production environment, its current value is
+
+
+Authorization
+=============
+
+D4Science adopts state-of-the-art industry standards for authentication and authorization.
+Specifically, the implementation fully adopts `OIDC (OpenID Connect) `_ for authentication and UMA 2 (User-Managed Authorization) for authorization flows.
+`JSON Web Token (JWT) Access token `_ are used for both authentication and authorization.
+
+Obtain your Bearer token here: https://dev.d4science.org/how-to-access-resources
+
+Service
+=======
+
+You can call the methods of the Web Service by writing your REST client application or using existing REST client plugins.
+
+
+HTTP Statuses
+-------------
+
+Any successful operation returns a *200 OK* HTTP status code.
+The create operation returns *201 Created*.
+Any Background operation returns *202 Accepted*.
+Any operation that does not provide any content returns *204 No Content*.
+
+
+
+The most common error statuses a client can obtain are:
+
+* **400 Bad Request** used to indicate a clients error ``_;
+* **401 Unauthorized** used to indicate that the client does not provide the authorization token in the HTTP Header or the client does not have enough right to perform such request ``_;
+* **404 Not Found** used to indicate that the requested instance does not exist ``_;
+* **405 Method Not Allowed** the used HTTP method is not supported for the requested URL ``_.
+ The response contains the *Allow* HTTP Header indicating the supported HTTP method for such URL ``_;
+* **409 Conflict** the request could not be completed due to a conflict with the current state of the target resource (e.g. the name of the resource already exists) ``_;
+* **500 Internal Server Error** indicate a server failure ``_.
+
+You can find a complete list of HTTP Status at ``_ or ``_
+
+If you get a *500 Internal Server Error*, please report it in the `gCube ticketing system `_.
+
+Please use this checklist before reporting an error:
+
+* Replicate the request;
+* The failure could be temporal due to a network error, a server issue, and many other temporal issues. For this reason, please retry the request after a certain amount of time before reporting the issue;
+* indicate how to replicate the error;
+* indicate the time when the error occurred (this simplifies identifying the issue).
+
+HTTP Methods
+------------
+
+gCat is a pure RESTful service. It uses standard HTTP Methods to perform a listing of collections and CRUD (Create Read Update Delete) operations on instances.
+
+
+.. table::
+
+ +--------------+-------------+----------------------------------------+---------------------+--------+------------+
+ | Operation | HTTP Method | URL | Success HTTP Status | Safe | Idempotent |
+ +==============+=============+========================================+=====================+========+============+
+ | Supported | OPTIONS | /{COLLECTION} | 204 No Content | Y | Y |
+ | HTTP Methods | | | [#allow]_ | | |
+ +--------------+-------------+----------------------------------------+---------------------+--------+------------+
+ | List | GET | /{COLLECTION} | 200 OK | Y | Y |
+ +--------------+-------------+----------------------------------------+---------------------+--------+------------+
+ | Count | GET | /{COLLECTION}?count=true | 200 OK | Y | Y |
+ +--------------+-------------+----------------------------------------+---------------------+--------+------------+
+ | Exists | HEAD | /{COLLECTION} | 204 No Content | Y | Y |
+ +--------------+-------------+----------------------------------------+---------------------+--------+------------+
+ | Create | POST | /{COLLECTION} | 201 Created | N | N |
+ +--------------+-------------+----------------------------------------+---------------------+--------+------------+
+ | Supported | OPTIONS | /{COLLECTION}/{INSTANCE_ID} | 204 No Content | Y | Y |
+ | HTTP Methods | | | [#allow]_ | | |
+ +--------------+-------------+----------------------------------------+---------------------+--------+------------+
+ | Exist | HEAD | /{COLLECTION}/{INSTANCE_ID} | 204 No Content | Y | Y |
+ +--------------+-------------+----------------------------------------+---------------------+--------+------------+
+ | Read | GET | /{COLLECTION}/{INSTANCE_ID} | 200 OK | Y | Y |
+ +--------------+-------------+----------------------------------------+---------------------+--------+------------+
+ | Update | PUT | /{COLLECTION}/{INSTANCE_ID} | 200 OK | N | Y |
+ +--------------+-------------+----------------------------------------+---------------------+--------+------------+
+ | Patch | PATCH | /{COLLECTION}/{INSTANCE_ID} | 200 OK | N | Y |
+ +--------------+-------------+----------------------------------------+---------------------+--------+------------+
+ | Delete | DELETE | /{COLLECTION}/{INSTANCE_ID} | 204 No Content | N | N [#del]_ |
+ +--------------+-------------+----------------------------------------+---------------------+--------+------------+
+ | Purge | DELETE | /{COLLECTION}/{INSTANCE_ID}?purge=true | 204 No Content | N | N [#del]_ |
+ + +-------------+----------------------------------------+---------------------+--------+------------+
+ | | PURGE | /{COLLECTION}/{INSTANCE_ID} | 204 No Content | N | N [#del]_ |
+ +--------------+-------------+----------------------------------------+---------------------+--------+------------+
+
+.. [#allow] Supported HTTP Methods in **Allow** HTTP Header
+
+.. [#del] DELETE has been defined as idempotent.
+
+ *Allamaraju* [#Allamaraju]_ argues that DELETE idempotency should be accomplished client-side.
+ The server should inform the client if the delete operation succeeded because the resource was deleted or it was not found, i.e., **404 Not Found** error is suggested instead of **204 No Content**.
+ The latter situation should be treated as idempotent by the client.
+
+ We share the same vision. For this reason, gCat does not provide server-side idempotency for DELETE and PURGE operations.
+
+.. [#Allamaraju] Allamaraju S. RESTful Web Services Cookbook: Solutions for Improving Scalability and Simplicity. O’Reilly. first ed. 2010
+
+
+About URL
+^^^^^^^^^
+
+The presented URL uses the following convention:
+
+* **{COLLECTION}** is the plural name of the entity type;
+* **{INSTANCE_ID}** is an identification that enables univocally identifying the instance in the collection.
+
+
+About Safety and Idempotency properties
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+
+* A method is *Safe* if it does not produce any side effects.
+ "This does not prevent an implementation from including behaviour that is potentially harmful, that is not entirely read-only, or that causes side effects while invoking a safe method"
+ ``_;
+* A method is *Idempotent* if the same operation repeated multiple times has the same side effect as using it one time.
+ "repeating the request will have the same intended effect, even if the original request succeeded, though the response might differ"
+ ``_.
+
+You can find more information about HTTP Methods at ``_
+
+Uncommon HTTP Methods
+^^^^^^^^^^^^^^^^^^^^^
+
+* PATCH method allows to perform a differential update (i.e. an update which provides only the differences and not the whole new representation);
+* PURGE method is not a standard but is widely used in services that require this action
+ (e.g. `Varnish `_, `Squid `_).
+ gCat provides support for this method, but to support a wider range of clients, it also provides the Purge action via *DELETE* with the additional get parameter ``purge=true``.
+
+
+Content-Type
+------------
+
+Any request must contain an indication of the interesting content type.
+
+The client must specify the **Accept** HTTP Header for any operation returning a result.
+
+.. code-block:: rest
+
+ Accept: application/json
+
+For any operation sending content to the service, it is necessary to specify the **Content-Type** HTTP Header.
+
+.. code-block:: rest
+
+ Content-Type: application/json
+
+The service accepts and returns only JSON objects.
+
+
+
+Collections
+-----------
+
+
+
+
+Roles
+-----
+
+
+
+Java Client
+===========
+
+We provide the following Java Client out-of-the-box.
+
+ .. TIP::
+ If you're coding in Java, it is recommended that you use this Java Client.
+
+**Maven Coordinates**
+
+.. code:: xml
+
+ org.gcube.service
+ helloworld-client
+ [1.0.0-SNAPSHOT, 2.0.0-SNAPSHOT)
+
+**Methods Result**
+
+The service exposes `its methods <../api-docs/index.html>`_ using a standard naming approach. Moreover, they accept (in the case of HTTP POST/PUT methods) JSON objects.
+
+ .. IMPORTANT::
+ The result of all methods is always a JSON object as per below:
+
+.. code:: javascript
+
+ {
+ ....
+ }
+
+*Inputs are automatically validated before the request is served.*
+
+
+**Usage examples**
+
+- Example 1
+
+.. code:: java
+
+ import org.gcube....;
+
+
+
+
+Service Discovery on IS
+=======================
+
+The service can be discovered in the gCore IS as gCore Endpoint with the following parameter:
+
+.. code:: xml
+
+ org.gcube.service
+ helloworld
+
+
+The service can be discovered in the Facet-Based IS as EService with the following JSON query:
+
+.. code:: json
+
+ {
+ "@class": "EService",
+ "consistsOf": [
+ {
+ "@class": "IsIdentifiedBy",
+ "target": {
+ "@class": "SoftwareFacet",
+ "group": "org.gcube.service",
+ "name": "helloworld"
+ }
+ }
+ ]
+ }
+
+Service Maven Coordinates
+=========================
+
+The maven coordinates of the Hello World SG4 service are:
+
+.. code:: xml
+
+ org.gcube.service
+ helloworld
+
\ No newline at end of file
diff --git a/documentation/sphinx/make.bat b/documentation/sphinx/make.bat
new file mode 100644
index 0000000..153be5e
--- /dev/null
+++ b/documentation/sphinx/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=.
+set BUILDDIR=_build
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.https://www.sphinx-doc.org/
+ exit /b 1
+)
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/documentation/sphinx/tests.rst b/documentation/sphinx/tests.rst
new file mode 100644
index 0000000..fca9245
--- /dev/null
+++ b/documentation/sphinx/tests.rst
@@ -0,0 +1,23 @@
+Dev and Pre Users used for moderation tests
+========
+
+To perform moderation tests in dev and preproduction infrastructure we use different users with the indicated roles.
+
+.. table::
+
+ +---------------+---------------+----------------------------------------+
+ | User | Username | Role |
+ +===============+===============+========================================+
+ | Mister Blonde | mister.blonde | Catalogue-Admin + Catalogue-Moderator |
+ +---------------+---------------+----------------------------------------+
+ | Mister Blue | mister.blue | Catalogue-Admin |
+ +---------------+---------------+----------------------------------------+
+ | Mister Brown | mister.brown | Catalogue-Moderator |
+ +---------------+---------------+----------------------------------------+
+ | Mister Orange | mister.orange | Catalogue-Editor |
+ +---------------+---------------+----------------------------------------+
+ | Mister Pink | mister.pink | NO ROLE (means Catalogue-Member) |
+ +---------------+---------------+----------------------------------------+
+ | Mister White | mister.white | Catalogue-Manager |
+ +---------------+---------------+----------------------------------------+
+
diff --git a/pom.xml b/pom.xml
index fad40eb..ecfdd98 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,23 +1,49 @@
-
- 4.0.0
-
- org.gcube.tools
- maven-parent
- 1.2.0
-
- org.gcube.resource-management
- resource-manager
- 1.0.0-SNAPSHOT
- war
- Resource Manager
-
-
- 11
- UTF-8
+
+ 4.0.0
+
+ org.gcube.tools
+ maven-parent
+ 1.2.0
+
+ org.gcube.resource-management
+ resource-manager
+ 1.0.0-SNAPSHOT
+ war
+ Resource Manager
+
+
+ gCube System
+ https://www.gcube-system.org/
+
+
+
+
+ luca.frosini
+ Luca Frosini
+ luca.frosini@isti.cnr.it
+ https://www.isti.cnr.it/en/about/people-detail/141/Frosini_Luca
+ ISTI-CNR
+ https://www.isti.cnr.it/
+
+ researcher
+ developer
+
+ Europe/Rome
+
+
+
+
+ 11
${java.version}
${java.version}
- ${project.basedir}${file.separator}src${file.separator}main${file.separator}webapp${file.separator}WEB-INF
+ UTF-8
+
+ ${project.basedir}${file.separator}src${file.separator}main${file.separator}webapp${file.separator}WEB-INF
+
2.14.0
+ 4.0.1-SNAPSHOT
@@ -79,7 +105,6 @@
org.glassfish.jersey.containers
jersey-container-servlet
-
org.gcube.common
gxHTTP
@@ -93,6 +118,7 @@
org.gcube.core
common-smartgears
+
com.webcohesion.enunciate
@@ -107,10 +133,10 @@
provided
- javax.servlet
- javax.servlet-api
- 3.1.0
- provided
+ javax.servlet
+ javax.servlet-api
+ 3.1.0
+ provided
@@ -130,17 +156,21 @@
-
+
kr.motd.maven
sphinx-maven-plugin
2.10.0
- ${project.build.directory}/${project.artifactId}-${project.version}/docs
+
+ ${project.build.directory}${file.separator}${project.build.finalName}${file.separator}docs
html
- ${basedir}/docs
- ${basedir}/docs
+ ${project.basedir}${file.separator}documentation${file.separator}sphinx
+ ${project.basedir}${file.separator}documentation${file.separator}sphinx
+
+
+ file:/opt/homebrew/opt/sphinx-doc/bin/sphinx-build
@@ -151,45 +181,53 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ com.webcohesion.enunciate
+ enunciate-maven-plugin
+ ${enunciate.version}
+
+
+ assemble
+
+ assemble
+
+
+
+
+
+ ${project.basedir}${file.separator}documentation${file.separator}enunciate.xml
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+ org.apache.maven.plugins
+ maven-resources-plugin
+
+
+ copy-enunciate-docs
+ process-resources
+
+ copy-resources
+
+
+ target
+
+
+ ${project.build.directory}${file.separator}${project.artifactId}-${project.version}${file.separator}api-docs
+ ${project.build.directory}/api-docs
+ true
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/main/java/org/gcube/resourcemanagement/ResourceInitializer.java b/src/main/java/org/gcube/resourcemanagement/RMInitializer.java
similarity index 85%
rename from src/main/java/org/gcube/resourcemanagement/ResourceInitializer.java
rename to src/main/java/org/gcube/resourcemanagement/RMInitializer.java
index c000d47..4954e03 100644
--- a/src/main/java/org/gcube/resourcemanagement/ResourceInitializer.java
+++ b/src/main/java/org/gcube/resourcemanagement/RMInitializer.java
@@ -12,9 +12,9 @@ import jakarta.ws.rs.ApplicationPath;
*/
@ApplicationPath("/")
@ManagedBy(ResourceManager.class)
-public class ResourceInitializer extends ResourceConfig {
+public class RMInitializer extends ResourceConfig {
- public ResourceInitializer() {
+ public RMInitializer() {
packages(BaseREST.class.getPackage().toString());
packages(Configuration.class.getPackage().toString());
}
diff --git a/src/main/java/org/gcube/resourcemanagement/ResourceManager.java b/src/main/java/org/gcube/resourcemanagement/ResourceManager.java
index 1eff703..1ca107c 100644
--- a/src/main/java/org/gcube/resourcemanagement/ResourceManager.java
+++ b/src/main/java/org/gcube/resourcemanagement/ResourceManager.java
@@ -38,7 +38,8 @@ public class ResourceManager implements ApplicationManager {
context);
ApplicationContext applicationContext = ContextProvider.get();
- String rrEServiceID = applicationContext.id();
+ String rmEServiceID = applicationContext.id();
+ logger.info("Resource Manager ahs the following ID {}", rmEServiceID);
logger.trace(
diff --git a/src/main/java/org/gcube/resourcemanagement/rest/BaseREST.java b/src/main/java/org/gcube/resourcemanagement/rest/BaseREST.java
index 7a2d1d2..ece3a48 100644
--- a/src/main/java/org/gcube/resourcemanagement/rest/BaseREST.java
+++ b/src/main/java/org/gcube/resourcemanagement/rest/BaseREST.java
@@ -20,7 +20,7 @@ import jakarta.ws.rs.core.UriInfo;
})
public class BaseREST {
- private final Logger logger = LoggerFactory.getLogger(this.getClass());
+ protected final Logger logger = LoggerFactory.getLogger(this.getClass());
public static final String APPLICATION_JSON_CHARSET_UTF_8 = "application/json;charset=UTF-8";
public static final String APPLICATION_JSON_API = "application/vnd.api+json";
@@ -35,11 +35,6 @@ public class BaseREST {
protected static final String LOCATION_HEADER = "Location";
- protected void setCalledMethod(String method) {
- InnerMethodName.set(method);
- logger.info("{}", uriInfo.getAbsolutePath());
- }
-
protected ResponseBuilder addLocation(ResponseBuilder responseBuilder, String id) {
return responseBuilder.header(LOCATION_HEADER,
String.format("%s/%s", uriInfo.getAbsolutePath().toString(), id));
@@ -55,4 +50,33 @@ public class BaseREST {
return stringBuilder.toString();
}
+ protected void setAccountingMethod(String method) {
+ InnerMethodName.set(method);
+ logger.info("{}", uriInfo.getAbsolutePath());
+ }
+
+// protected void setAccountingMethod(Method method, String type) {
+// StringBuffer accountingMethod = new StringBuffer();
+// accountingMethod.append(method.getPrefix());
+// accountingMethod.append(type);
+// accountingMethod.append(method.getSuffix());
+// setAccountingMethod(accountingMethod.toString());
+// }
+//
+// private ServerRequestInfo initRequestInfo(ServerRequestInfo requestInfo) {
+// requestInfo.setUriInfo(uriInfo);
+// RequestUtility.getRequestInfo().set(requestInfo);
+// return requestInfo;
+// }
+//
+// protected ServerRequestInfo initRequestInfo(int offset, int limit) {
+// ServerRequestInfo requestInfo = new ServerRequestInfo(offset, limit);
+// return initRequestInfo(requestInfo);
+// }
+//
+// protected ServerRequestInfo initRequestInfo() {
+// ServerRequestInfo requestInfo = new ServerRequestInfo();
+// return initRequestInfo(requestInfo);
+// }
+
}
diff --git a/src/main/java/org/gcube/resourcemanagement/rest/ContextManager.java b/src/main/java/org/gcube/resourcemanagement/rest/ContextManager.java
new file mode 100644
index 0000000..b0d6e6e
--- /dev/null
+++ b/src/main/java/org/gcube/resourcemanagement/rest/ContextManager.java
@@ -0,0 +1,114 @@
+package org.gcube.resourcemanagement.rest;
+
+import org.gcube.informationsystem.contexts.reference.entities.Context;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.ResourceRegistryException;
+import org.gcube.informationsystem.resourceregistry.api.exceptions.contexts.ContextNotFoundException;
+import org.gcube.informationsystem.resourceregistry.api.rest.ContextPath;
+
+import jakarta.ws.rs.Consumes;
+import jakarta.ws.rs.DELETE;
+import jakarta.ws.rs.GET;
+import jakarta.ws.rs.POST;
+import jakarta.ws.rs.PUT;
+import jakarta.ws.rs.Path;
+import jakarta.ws.rs.PathParam;
+import jakarta.ws.rs.Produces;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import jakarta.ws.rs.core.Response.Status;
+
+/**
+ * @author Luca Frosini (ISTI - CNR)
+ */
+@Path(ContextManager.CONTEXTS_PATH_PART)
+public class ContextManager extends BaseREST {
+
+ public static final String CONTEXTS_PATH_PART = "contexts";
+
+ public static final String CONTEXT_UUID_PATH_PARAMETER = "CONTEXT_UUID";
+
+ public static final String CURRENT_CONTEXT_PATH_PART = "CURRENT_CONTEXT";
+
+ public ContextManager() {
+ super();
+ }
+
+ /*
+ * Create a new Context suing the provided definition
+ *
+ * POST /contexts
+ *
+ * BODY: {...}
+ *
+ */
+ @POST
+ @Path("{" + ContextManager.CONTEXT_UUID_PATH_PARAMETER + "}")
+ @Consumes({MediaType.TEXT_PLAIN, BaseREST.APPLICATION_JSON_CHARSET_UTF_8})
+ @Produces(BaseREST.APPLICATION_JSON_CHARSET_UTF_8)
+ public String create(String json)
+ throws ResourceRegistryException {
+ logger.info("Requested to update/create {} with json {} ", Context.NAME, json);
+// setAccountingMethod(Method.UPDATE, Context.NAME);
+
+ return "";
+ }
+
+ /*
+ * Allow to read the context definition
+ * GET /contexts/{UUID}
+ * e.g. GET /contexts/c0f314e7-2807-4241-a792-2a6c79ed4fd0
+ *
+ */
+ @GET
+ @Path("{" + ContextManager.CONTEXT_UUID_PATH_PARAMETER + "}")
+ @Consumes({MediaType.TEXT_PLAIN, BaseREST.APPLICATION_JSON_CHARSET_UTF_8})
+ @Produces(BaseREST.APPLICATION_JSON_CHARSET_UTF_8)
+ public String read(@PathParam(ContextManager.CONTEXT_UUID_PATH_PARAMETER) String uuid)
+ throws ContextNotFoundException, ResourceRegistryException {
+ if(uuid.compareTo(ContextPath.CURRENT_CONTEXT_PATH_PART)==0){
+ //uuid = ContextUtility.getCurrentSecurityContext().getUUID().toString();
+ // TODO get from IS
+ }
+ logger.info("Requested to read {} with id {} ", Context.NAME, uuid);
+// setAccountingMethod(Method.READ, Context.NAME);
+
+ return "";
+ }
+
+ /*
+ * Update an existing Context definition
+ *
+ * PUT /contexts/{UUID}
+ * e.g. PUT /contexts/c0f314e7-2807-4241-a792-2a6c79ed4fd0
+ *
+ * BODY: {...}
+ *
+ */
+ @PUT
+ @Path("{" + ContextManager.CONTEXT_UUID_PATH_PARAMETER + "}")
+ @Consumes({MediaType.TEXT_PLAIN, BaseREST.APPLICATION_JSON_CHARSET_UTF_8})
+ @Produces(BaseREST.APPLICATION_JSON_CHARSET_UTF_8)
+ public String update(@PathParam(ContextManager.CONTEXT_UUID_PATH_PARAMETER) String uuid, String json)
+ throws ResourceRegistryException {
+ logger.info("Requested to update/create {} with json {} ", Context.NAME, json);
+// setAccountingMethod(Method.UPDATE, Context.NAME);
+
+ return "";
+ }
+
+ /*
+ * DELETE /contexts/{UUID}
+ * e.g. DELETE /contexts/c0f314e7-2807-4241-a792-2a6c79ed4fd0
+ */
+ @DELETE
+ @Consumes({MediaType.TEXT_PLAIN, BaseREST.APPLICATION_JSON_CHARSET_UTF_8})
+ @Path("{" + ContextManager.CONTEXT_UUID_PATH_PARAMETER + "}")
+ public Response delete(@PathParam(ContextManager.CONTEXT_UUID_PATH_PARAMETER) String uuid)
+ throws ContextNotFoundException, ResourceRegistryException {
+ logger.info("Requested to delete {} with id {} ", Context.NAME, uuid);
+ setAccountingMethod("deleteContext");
+
+ return Response.status(Status.NO_CONTENT).build();
+ }
+
+}
diff --git a/src/main/java/org/gcube/resourcemanagement/rest/ResourceManagerExceptionMapper.java b/src/main/java/org/gcube/resourcemanagement/rest/RMExceptionMapper.java
similarity index 92%
rename from src/main/java/org/gcube/resourcemanagement/rest/ResourceManagerExceptionMapper.java
rename to src/main/java/org/gcube/resourcemanagement/rest/RMExceptionMapper.java
index 5ae3d8a..0fc004f 100644
--- a/src/main/java/org/gcube/resourcemanagement/rest/ResourceManagerExceptionMapper.java
+++ b/src/main/java/org/gcube/resourcemanagement/rest/RMExceptionMapper.java
@@ -11,7 +11,7 @@ import jakarta.ws.rs.ext.Provider;
* @author Luca Frosini (ISTI - CNR)
*/
@Provider
-public class ResourceManagerExceptionMapper implements ExceptionMapper {
+public class RMExceptionMapper implements ExceptionMapper {
@Override
public Response toResponse(Exception exception) {
diff --git a/src/main/java/org/gcube/resourcemanagement/rest/administration/Configuration.java b/src/main/java/org/gcube/resourcemanagement/rest/administration/Configuration.java
index 8303e3a..4ab568a 100644
--- a/src/main/java/org/gcube/resourcemanagement/rest/administration/Configuration.java
+++ b/src/main/java/org/gcube/resourcemanagement/rest/administration/Configuration.java
@@ -32,10 +32,10 @@ import jakarta.ws.rs.core.Response.Status;
import jakarta.xml.ws.WebServiceException;
/**
- * The catalogue configuration for the context of the request
+ * The Resource Manager configuration for the context of the request
* (i.e. the context where the token has been generated).
*
- * Only Catalogue-Managers are able to invoke non-safe methods.
+ * Only Managers are able to invoke non-safe methods.
*
* @author Luca Frosini (ISTI - CNR)
*/
@@ -100,18 +100,18 @@ public class Configuration extends BaseREST {
}
/**
- * This API allows to read the RR configuration for the
+ * This API allows to read the RM configuration for the
* current context (i.e. the context where the token has been generated).
*/
@GET
@Path("/{" + CONTEXT_FULLNAME_PARAMETER + "}")
@Produces(BaseREST.APPLICATION_JSON_CHARSET_UTF_8)
-// @AuthorizationControl(allowedRoles={Role.CATALOGUE_EDITOR, Role.CATALOGUE_ADMIN, Role.CATALOGUE_MANAGER}, exception=NotAuthorizedException.class)
@StatusCodes ({
@ResponseCode(code = 200, condition = "Resource Manager configuration successfully read."),
@ResponseCode(code = 401, condition = "Only User with role Manager above can read the configuration."),
- @ResponseCode(code = 500, condition = "Error while reading catalogue configuration."),
+ @ResponseCode(code = 500, condition = "Error while reading the configuration."),
})
+
/**
* @param context
* @return
@@ -153,11 +153,10 @@ public class Configuration extends BaseREST {
@Path("/{" + CONTEXT_FULLNAME_PARAMETER + "}")
@Consumes(BaseREST.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(BaseREST.APPLICATION_JSON_CHARSET_UTF_8)
-// @AuthorizationControl(allowedRoles={Role.CATALOGUE_MANAGER}, exception=NotAuthorizedException.class)
@StatusCodes ({
- @ResponseCode(code = 200, condition = "Catalogue configuration successfully created/updated."),
- @ResponseCode(code = 401, condition = "Only Catalogue-Managers can create/update catalogue configuration."),
- @ResponseCode(code = 500, condition = "Error while creating/updating catalogue configuration."),
+ @ResponseCode(code = 200, condition = "Resource Manager configuration successfully created/updated."),
+ @ResponseCode(code = 401, condition = "Only User with role Manager above can create/update the configuration."),
+ @ResponseCode(code = 500, condition = "Error while creating/updating the configuration."),
})
@OperationId("Create or Update")
public String createOrUpdate(@PathParam(CONTEXT_FULLNAME_PARAMETER) String context, String json) throws WebServiceException {
@@ -187,7 +186,7 @@ public class Configuration extends BaseREST {
}
/**
- * This API allows to patch the catalogue configuration for the
+ * This API allows to patch the Resource Manager configuration for the
* context of the request (i.e. the context where the token has been generated)
* using the json provided as request body.
*/
@@ -195,11 +194,10 @@ public class Configuration extends BaseREST {
@Path("/{" + CONTEXT_FULLNAME_PARAMETER + "}")
@Consumes(BaseREST.APPLICATION_JSON_CHARSET_UTF_8)
@Produces(BaseREST.APPLICATION_JSON_CHARSET_UTF_8)
-// @AuthorizationControl(allowedRoles={Role.CATALOGUE_MANAGER}, exception=NotAuthorizedException.class)
@StatusCodes ({
- @ResponseCode(code = 200, condition = "Catalogue configuration successfully updated."),
- @ResponseCode(code = 401, condition = "Only Catalogue-Managers can update catalogue configuration."),
- @ResponseCode(code = 500, condition = "Error while updating catalogue configuration."),
+ @ResponseCode(code = 200, condition = "Resource Manager configuration successfully patched."),
+ @ResponseCode(code = 401, condition = "Only User with role Manager above can patch the configuration."),
+ @ResponseCode(code = 500, condition = "Error while patching the configuration."),
})
public Response patch(@PathParam(CONTEXT_FULLNAME_PARAMETER) String context, String json) throws WebServiceException {
try {
@@ -233,11 +231,11 @@ public class Configuration extends BaseREST {
* context of the request (i.e. the context where the token has been generated).
*
* This API forces the service to read again from the Information System (IS)
- * the resource manager configuration for the context of the request.
+ * the Resource Manager configuration for the context of the request.
*
* If the user specifies the purge
query parameter this API
* remove the configuration from the IS. Please note that this implies that
- * the resource manager is no more configured for the context of the request.
+ * the Resource Manager is no more configured for the context of the request.
*
*
* @param context context must contains the context of the request
@@ -253,9 +251,9 @@ public class Configuration extends BaseREST {
@Path("/{" + CONTEXT_FULLNAME_PARAMETER + "}")
// @AuthorizationControl(allowedRoles={Role.CATALOGUE_MANAGER}, exception=NotAuthorizedException.class)
@StatusCodes ({
- @ResponseCode(code = 200, condition = "Catalogue configuration successfully deleted."),
- @ResponseCode(code = 401, condition = "Only Catalogue-Managers can delete catalogue configuration."),
- @ResponseCode(code = 500, condition = "Error while deleting catalogue configuration."),
+ @ResponseCode(code = 200, condition = "Resource Manager configuration successfully deleted."),
+ @ResponseCode(code = 401, condition = "Only User with role Manager above can delete the configuration."),
+ @ResponseCode(code = 500, condition = "Error while deleting the configuration."),
})
public Response delete(@PathParam(CONTEXT_FULLNAME_PARAMETER) String context,
@QueryParam(BaseREST.PURGE_QUERY_PARAMETER) @DefaultValue("false") Boolean purge) throws WebServiceException {
@@ -304,9 +302,9 @@ public class Configuration extends BaseREST {
@Path("/{" + CONTEXT_FULLNAME_PARAMETER + "}")
// @AuthorizationControl(allowedRoles={Role.CATALOGUE_MANAGER}, exception=NotAuthorizedException.class)
@StatusCodes ({
- @ResponseCode(code = 200, condition = "Catalogue configuration successfully deleted."),
- @ResponseCode(code = 401, condition = "Only Catalogue-Managers can delete catalogue configuration."),
- @ResponseCode(code = 500, condition = "Error while deleting catalogue configuration."),
+ @ResponseCode(code = 200, condition = "Resource Manager configuration purged deleted."),
+ @ResponseCode(code = 401, condition = "Only User with role Manager above can purge the configuration."),
+ @ResponseCode(code = 500, condition = "Error while purging the configuration."),
})
public Response purge(@PathParam(CONTEXT_FULLNAME_PARAMETER) String context) throws WebServiceException {
try {
diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml
index 67c7bc7..996a73d 100644
--- a/src/main/webapp/WEB-INF/web.xml
+++ b/src/main/webapp/WEB-INF/web.xml
@@ -3,20 +3,19 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
- Hello World
-
- A gcube HelloWorld service - smartgears 4
-
- HelloWorld
- org.glassfish.jersey.servlet.ServletContainer
-
- jersey.config.server.provider.packages
- org.gcube.service.helloworld.services
-
-
-
- HelloWorld
- /*
+ org.gcube.resourcemanagement.RMInitializer
+
+
+ default
+ /docs/*
+
+ default
+ /api-docs/*
+
+
+ org.gcube.resourcemanagement.RMInitializer
+ /*
+
\ No newline at end of file