[UI] Support UI partial control 48/1248/11
authorIoakeim Samaras <ioakeim.samaras@ericsson.com>
Tue, 23 Jul 2019 15:36:37 +0000 (18:36 +0300)
committerIoakeim Samaras <ioakeim.samaras@ericsson.com>
Fri, 30 Aug 2019 13:49:03 +0000 (16:49 +0300)
The UI is capable of retrieving the results
from Nexus that every blueprint owner has
independently pushed.

JIRA: VAL-38

Signed-off-by: Ioakeim Samaras <ioakeim.samaras@ericsson.com>
Change-Id: I256641d1faed21025bc688a4a469f7af5f43d45f

117 files changed:
.coafile
docker/README.rst
docker/mariadb/deploy.sh
docker/mariadb/deploy_with_existing_persistent_storage.sh
docker/ui/deploy.sh
ui/CHANGELOG.md
ui/README.rst
ui/db-scripts/EcompSdkDMLMySql_2_4_OS.sql
ui/db-scripts/akraino_blueprint_validation_db.sql
ui/db-scripts/examples/initialize_db_example.sql
ui/pom.xml
ui/src/main/java/org/akraino/validation/ui/client/jenkins/JenkinsExecutorClient.java
ui/src/main/java/org/akraino/validation/ui/client/nexus/NexusExecutorClient.java
ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/TestInfoYaml.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/ValidationNexusTestResult.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/WRobotNexusTestResult.java [moved from ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/WrapperRobotTestResult.java with 65% similarity]
ui/src/main/java/org/akraino/validation/ui/conf/ExecutorServiceInitializer.java [moved from ui/src/main/java/org/akraino/validation/ui/conf/UiUtils.java with 72% similarity]
ui/src/main/java/org/akraino/validation/ui/conf/ExternalAppConfig.java
ui/src/main/java/org/akraino/validation/ui/conf/UiInitializer.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/conf/ValidationNexusTestResultsGetter.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/controller/BlueprintController.java
ui/src/main/java/org/akraino/validation/ui/controller/BlueprintInstanceForValidationController.java
ui/src/main/java/org/akraino/validation/ui/controller/JenkinsJobNotificationController.java
ui/src/main/java/org/akraino/validation/ui/controller/ModelsViewsController.java
ui/src/main/java/org/akraino/validation/ui/controller/ResultController.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/controller/SiloController.java [moved from ui/src/main/java/org/akraino/validation/ui/controller/ResultsController.java with 66% similarity]
ui/src/main/java/org/akraino/validation/ui/controller/SubmissionController.java
ui/src/main/java/org/akraino/validation/ui/controller/TimeslotsController.java
ui/src/main/java/org/akraino/validation/ui/dao/LabDAO.java
ui/src/main/java/org/akraino/validation/ui/dao/ValidationTestResultDAO.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/dao/WRobotTestResultDAO.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintDAOImpl.java
ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintInstanceForValidationDAOImpl.java
ui/src/main/java/org/akraino/validation/ui/daoimpl/LabDAOImpl.java
ui/src/main/java/org/akraino/validation/ui/daoimpl/SiloDAOImpl.java
ui/src/main/java/org/akraino/validation/ui/daoimpl/SubmissionDAOImpl.java
ui/src/main/java/org/akraino/validation/ui/daoimpl/TimeslotDAOImpl.java
ui/src/main/java/org/akraino/validation/ui/daoimpl/ValidationTestResultDAOImpl.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/daoimpl/WRobotTestResultDAOImpl.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/data/BlueprintLayer.java
ui/src/main/java/org/akraino/validation/ui/data/JnksJobNotify.java
ui/src/main/java/org/akraino/validation/ui/data/Lab.java
ui/src/main/java/org/akraino/validation/ui/data/SubmissionData.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/entity/LabInfo.java
ui/src/main/java/org/akraino/validation/ui/entity/Submission.java
ui/src/main/java/org/akraino/validation/ui/entity/ValidationDbTestResult.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/entity/WRobotDbTestResult.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/service/BlueprintInstanceForValidationService.java
ui/src/main/java/org/akraino/validation/ui/service/BlueprintService.java
ui/src/main/java/org/akraino/validation/ui/service/DbResultAdapter.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/service/DbSubmissionAdapter.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/service/IntegratedResultService.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/service/JenkinsJobNotificationService.java
ui/src/main/java/org/akraino/validation/ui/service/LabService.java
ui/src/main/java/org/akraino/validation/ui/service/ResultService.java [deleted file]
ui/src/main/java/org/akraino/validation/ui/service/SiloService.java
ui/src/main/java/org/akraino/validation/ui/service/SubmissionService.java [deleted file]
ui/src/main/java/org/akraino/validation/ui/service/TimeslotService.java
ui/src/main/java/org/akraino/validation/ui/service/utils/SubmissionHelper.java
ui/src/main/resources/logback.xml
ui/src/main/resources/music.properties
ui/src/main/resources/portal.properties
ui/src/main/webapp/WEB-INF/conf/system.properties
ui/src/main/webapp/WEB-INF/defs/definitions.xml
ui/src/main/webapp/WEB-INF/jsp/login.jsp
ui/src/main/webapp/WEB-INF/jsp/login_external.jsp
ui/src/main/webapp/WEB-INF/jsp/logout.jsp [new file with mode: 0644]
ui/src/main/webapp/WEB-INF/web.xml
ui/src/main/webapp/app/AECBlueprintValidationUI/App.Services.js [deleted file]
ui/src/main/webapp/app/AECBlueprintValidationUI/CommittedSubmissions/AECCommittedSubmissionsController.js [deleted file]
ui/src/main/webapp/app/AECBlueprintValidationUI/CommittedSubmissions/CommittedSubmissionsTemplate.html [deleted file]
ui/src/main/webapp/app/AECBlueprintValidationUI/GetBySubmissionId/AECGetBySubmissionIdController.js [deleted file]
ui/src/main/webapp/app/AECBlueprintValidationUI/GetBySubmissionId/GetBySubmissionIdTemplate.html [deleted file]
ui/src/main/webapp/app/AECBlueprintValidationUI/GetBySubmissionId/Route.js [deleted file]
ui/src/main/webapp/app/AECBlueprintValidationUI/NewSubmission/NewSubmissionTemplate.html [deleted file]
ui/src/main/webapp/app/BluvalUI/App.Config.js [moved from ui/src/main/webapp/app/AECBlueprintValidationUI/App.Config.js with 84% similarity]
ui/src/main/webapp/app/BluvalUI/App.Services.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissions.Services.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissions.html [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissions.js [moved from ui/src/main/webapp/app/AECBlueprintValidationUI/GetBySubmissionId/AECGetBySubmissionId.js with 84% similarity]
ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissionsController.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissionsTemplate.html [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/Route.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/GetBasedOnDate.html [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/GetBasedOnDate.js [moved from ui/src/main/webapp/app/AECBlueprintValidationUI/CommittedSubmissions/AECCommittedSubmissions.js with 74% similarity]
ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/GetBasedOnDateController.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/GetBasedOnDateTemplate.html [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/Route.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/GetByTimestamp/GetByTimestamp.html [moved from ui/src/main/webapp/app/AECBlueprintValidationUI/CommittedSubmissions/CommittedSubmissions.html with 58% similarity]
ui/src/main/webapp/app/BluvalUI/GetByTimestamp/GetByTimestamp.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/GetByTimestamp/GetByTimestampController.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/GetByTimestamp/GetByTimestampTemplate.html [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/GetByTimestamp/Route.js [moved from ui/src/main/webapp/app/AECBlueprintValidationUI/NewSubmission/Route.js with 80% similarity]
ui/src/main/webapp/app/BluvalUI/GetLastRun/GetLastRun.html [moved from ui/src/main/webapp/app/AECBlueprintValidationUI/NewSubmission/NewSubmission.html with 58% similarity]
ui/src/main/webapp/app/BluvalUI/GetLastRun/GetLastRun.js [moved from ui/src/main/webapp/app/AECBlueprintValidationUI/NewSubmission/AECNewSubmission.js with 84% similarity]
ui/src/main/webapp/app/BluvalUI/GetLastRun/GetLastRunController.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/GetLastRun/GetLastRunTemplate.html [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/GetLastRun/Route.js [moved from ui/src/main/webapp/app/AECBlueprintValidationUI/CommittedSubmissions/Route.js with 78% similarity]
ui/src/main/webapp/app/BluvalUI/GetMostRecent/GetMostRecent.html [moved from ui/src/main/webapp/app/AECBlueprintValidationUI/GetBySubmissionId/GetBySubmissionId.html with 58% similarity]
ui/src/main/webapp/app/BluvalUI/GetMostRecent/GetMostRecent.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/GetMostRecent/GetMostRecentController.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/GetMostRecent/GetMostRecentTemplate.html [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/GetMostRecent/Route.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/NewSubmission/NewSubmission.html [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/NewSubmission/NewSubmission.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/NewSubmission/NewSubmissionController.js [moved from ui/src/main/webapp/app/AECBlueprintValidationUI/NewSubmission/AECNewSubmissionController.js with 74% similarity]
ui/src/main/webapp/app/BluvalUI/NewSubmission/NewSubmissionTemplate.html [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/NewSubmission/Route.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/ValidationResults/Route.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/ValidationResults/TestSuiteResults/TestSuiteResultsController.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/ValidationResults/TestSuiteResults/TestSuiteResultsModal.html [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResults.Services.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResults.html [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResults.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResultsController.js [new file with mode: 0644]
ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResultsTemplate.html [new file with mode: 0644]
ui/src/main/webapp/app/fusion/scripts/DS2-view-models/welcome-content.html

index 206fc17..ba91275 100644 (file)
--- a/.coafile
+++ b/.coafile
@@ -54,7 +54,11 @@ ignore = ui/target/**,
     ui/src/main/java/org/akraino/validation/ui/conf/ExternalAppConfig.java,
     ui/src/main/java/org/akraino/validation/ui/filter/SecurityXssFilter.java,
     ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/**.java,
-    ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/**.java
+    ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/**.java,
+    ui/src/main/java/org/akraino/validation/ui/data/SubmissionData.java,
+    ui/src/main/java/org/akraino/validation/ui/service/DbResultAdapter.java,
+    ui/src/main/java/org/akraino/validation/ui/client/nexus/NexusExecutorClient.java,
+    ui/src/main/java/org/akraino/validation/ui/daoimpl/ValidationTestResultDAOImpl.java
 
 [all.JS]
 bears = ESLintBear,JSComplexityBear
@@ -66,6 +70,11 @@ ignore = ui/src/main/webapp/app/fusion/**,
     ui/src/main/webapp/static/**,
     ui/bin/**,
     ui/target/**,
-    ui/src/main/webapp/app/AECBlueprintValidationUI/NewSubmission/AECNewSubmission.js,
-    ui/src/main/webapp/app/AECBlueprintValidationUI/CommittedSubmissions/AECCommittedSubmissions.js,
-    ui/src/main/webapp/app/AECBlueprintValidationUI/GetBySubmissionId/AECGetBySubmissionId.js
+    ui/src/main/webapp/app/BluvalUI/NewSubmission/NewSubmission.js,
+    ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissions.js,
+    ui/src/main/webapp/app/BluvalUI/GetBySubmissionId/GetBySubmissionId.js,
+    ui/src/main/webapp/app/BluvalUI/GetMostRecent/GetMostRecent.js,
+    ui/src/main/webapp/app/BluvalUI/GetLastRun/GetLastRun.js,
+    ui/src/main/webapp/app/BluvalUI/GetByTimestamp/GetByTimestamp.js,
+    ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/GetBasedOnDate.js,
+    ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResults.js
index 7179bee..581aa37 100644 (file)
@@ -82,7 +82,7 @@ The mariadb container
 Building and pushing the container
 ----------------------------------
 
-To build just the postgresql container, use the command:
+To build just the mariadb container, use the command:
 
 .. code-block:: console
 
@@ -100,6 +100,7 @@ In order for the container to be easily created, the deploy.sh script has been d
 
 CONTAINER_NAME, name of the container, default value is akraino-validation-mariadb
 MARIADB_ROOT_PASSWORD, the desired mariadb root user password, this variable is required
+MARIADB_AKRAINO_PASSWORD, the desired mariadb akraino user password, this variable is required
 UI_ADMIN_PASSWORD, the desired Blueprint Validation UI password for the admin user, this variable is required
 UI_AKRAINO_PASSWORD, the desired Blueprint Validation UI password for the akraino user, this variable is required
 REGISTRY, registry of the mariadb image, default value is akraino
@@ -115,14 +116,13 @@ Example (assuming the default variables have been utilized for building the imag
 .. code-block:: console
 
     cd validation/docker/mariadb
-    ./deploy.sh MARIADB_ROOT_PASSWORD=password UI_ADMIN_PASSWORD=admin UI_AKRAINO_PASSWORD=akraino
+    ./deploy.sh MARIADB_ROOT_PASSWORD=root_password MARIADB_AKRAINO_PASSWORD=akraino_password UI_ADMIN_PASSWORD=admin UI_AKRAINO_PASSWORD=akraino
 
 Also, in order to re-deploy the database (it is assumed that the corresponding mariadb container has been stopped and deleted) while the persistent storage already exists (currently, the directory /var/lib/mariadb of the host is used), a different approach should be used after the image build process.
 
 To this end, another script has been developed, namely deploy_with_existing_storage.sh which easily deploys the container. This script accepts the following items as input parameters:
 
 CONTAINER_NAME, the name of the container, default value is akraino-validation-mariadb
-MARIADB_ROOT_PASSWORD, the desired mariadb root user password, this variable is required
 REGISTRY, the registry of the mariadb image, default value is akraino
 NAME, the name of the mariadb image, default value is validation
 TAG_PRE, the first part of the image version, default value is mariadb
@@ -136,7 +136,7 @@ Example (assuming the default variables have been utilized for building the imag
 .. code-block:: console
 
     cd validation/docker/mariadb
-    ./deploy_with_existing_persistent_storage.sh MARIADB_ROOT_PASSWORD=password
+    ./deploy_with_existing_persistent_storage.sh
 
 More info can be found at the UI README file.
 
@@ -163,13 +163,13 @@ Using the container
 In order for the container to be easily created, the deploy.sh script has been developed. This script accepts the following as input parameters:
 
 CONTAINER_NAME, the name of the contaner, default value is akraino-validation-ui
-DB_CONNECTION_URL, the URL connection with the akraino database of the maridb instance, this variable is required
-MARIADB_ROOT_PASSWORD, the mariadb root user password, this variable is required
+DB_IP_PORT, the IP and port of the maridb instance, this variable is required
+MARIADB_AKRAINO_PASSWORD, the mariadb akraino user password, this variable is required
 REGISTRY, the registry of the mariadb image, default value is akraino
 NAME, the name of the mariadb image, default value is validation
 TAG_PRE, the first part of the image version, default value is ui
 TAG_VER, the last part of the image version, default value is latest
-JENKINS_URL, the URL of the Jenkins instance, this variable is required
+JENKINS_URL, the URL of the Jenkins instance (http or https must be defined), this variable is required
 JENKINS_USERNAME, the Jenkins user name, this variable is required
 JENKINS_USER_PASSWORD, the Jenkins user password, this variable is required
 JENKINS_JOB_NAME, the name of Jenkins job capable of executing the blueprint validation tests, this variable is required
@@ -191,7 +191,7 @@ Example (assuming the default variables have been utilized for building the imag
 .. code-block:: console
 
     cd validation/docker/ui
-    ./deploy.sh DB_CONNECTION_URL=172.17.0.3:3306/akraino MARIADB_ROOT_PASSWORD=password JENKINS_URL=http://192.168.2.2:8080 JENKINS_USERNAME=name JENKINS_USER_PASSWORD=jenkins_pwd JENKINS_JOB_NAME=job1
+    ./deploy.sh DB_IP_PORT=172.17.0.3:3306 MARIADB_AKRAINO_PASSWORD=akraino_password JENKINS_URL=http://192.168.2.2:8080 JENKINS_USERNAME=name JENKINS_USER_PASSWORD=jenkins_pwd JENKINS_JOB_NAME=job1
 
 The kube-conformance container
 ==============================
index fec5a2c..df7bcc6 100755 (executable)
 
 # Use this script if the persistent storage does not exist
 
-# Directory on host in where database data will be stored
-HOST_STORAGE_DIR="/var/lib/mariadb"
+DOCKER_VOLUME_NAME="akraino-validation-mariadb"
 # Container name
 CONTAINER_NAME="akraino-validation-mariadb"
 # Container input variables
 MARIADB_ROOT_PASSWORD=""
+MARIADB_AKRAINO_PASSWORD=""
 UI_ADMIN_PASSWORD=""
 UI_AKRAINO_PASSWORD=""
 # Image data
@@ -41,6 +41,7 @@ do
             TAG_VER)    TAG_VER=${VALUE} ;;
             TAG_PRE)    TAG_PRE=${VALUE} ;;
             MARIADB_ROOT_PASSWORD)    MARIADB_ROOT_PASSWORD=${VALUE} ;;
+            MARIADB_AKRAINO_PASSWORD)    MARIADB_AKRAINO_PASSWORD=${VALUE} ;;
             CONTAINER_NAME)    CONTAINER_NAME=${VALUE} ;;
             MARIADB_HOST_PORT)    MARIADB_HOST_PORT=${VALUE} ;;
             UI_ADMIN_PASSWORD)    UI_ADMIN_PASSWORD=${VALUE} ;;
@@ -55,6 +56,12 @@ if [ -z "$MARIADB_ROOT_PASSWORD" ]
     exit 1
 fi
 
+if [ -z "$MARIADB_AKRAINO_PASSWORD" ]
+  then
+    echo "ERROR: You must specify the mariadb database akraino user password"
+    exit 1
+fi
+
 if [ -z "$UI_ADMIN_PASSWORD" ]
   then
     echo "ERROR: You must specify the password of the UI admin user"
@@ -68,6 +75,7 @@ if [ -z "$UI_AKRAINO_PASSWORD" ]
 fi
 
 IMAGE="$REGISTRY"/"$NAME":"$TAG_PRE"-"$TAG_VER"
-docker run --detach --name $CONTAINER_NAME --publish $MARIADB_HOST_PORT:3306 --volume $HOST_STORAGE_DIR:/var/lib/mysql -v "/$(pwd)/mariadb.conf:/etc/mysql/conf.d/my.cnf" -e MYSQL_ROOT_PASSWORD="$MARIADB_ROOT_PASSWORD" -e UI_ADMIN_PASSWORD="$UI_ADMIN_PASSWORD" -e UI_AKRAINO_PASSWORD="$UI_AKRAINO_PASSWORD" $IMAGE
-sleep 10
+chmod 0444 "/$(pwd)/mariadb.conf"
+docker run --detach --name $CONTAINER_NAME --publish $MARIADB_HOST_PORT:3306 -v $DOCKER_VOLUME_NAME:/var/lib/mysql -v "/$(pwd)/mariadb.conf:/etc/mysql/conf.d/my.cnf" -e MYSQL_ROOT_PASSWORD="$MARIADB_ROOT_PASSWORD" -e MYSQL_DATABASE="akraino" -e MYSQL_USER="akraino" -e MYSQL_PASSWORD="$MARIADB_AKRAINO_PASSWORD" -e UI_ADMIN_PASSWORD="$UI_ADMIN_PASSWORD" -e UI_AKRAINO_PASSWORD="$UI_AKRAINO_PASSWORD" $IMAGE
 docker exec $CONTAINER_NAME /bin/bash -c 'sed -i 's/admin_password/'"$UI_ADMIN_PASSWORD"'/g' /docker-entrypoint-initdb.d/EcompSdkDMLMySql_2_4_OS.sql ; sed -i 's/akraino_password/'"$UI_AKRAINO_PASSWORD"'/g' /docker-entrypoint-initdb.d/EcompSdkDMLMySql_2_4_OS.sql; continue=`ps aux | grep mysql` ; while [ -z "$continue" ]; do continue=`ps aux | grep mysql`; sleep 5; done ; sleep 10 ;'
+sleep 10
index a20be5b..b109300 100755 (executable)
 
 # Use this script if the persistent storage already exists and you want to use its data
 
-# Directory on host in where database data are stored
-HOST_STORAGE_DIR="/var/lib/mariadb"
+DOCKER_VOLUME_NAME="akraino-validation-mariadb"
 # Container name
 CONTAINER_NAME="akraino-validation-mariadb"
-# Container input variables
-MARIADB_ROOT_PASSWORD=""
 # Image data
 REGISTRY=akraino
 NAME=validation
@@ -40,12 +37,10 @@ do
             TAG_PRE)    TAG_PRE=${VALUE} ;;
             CONTAINER_NAME)    CONTAINER_NAME=${VALUE} ;;
             MARIADB_HOST_PORT)    MARIADB_HOST_PORT=${VALUE} ;;
-            MARIADB_ROOT_PASSWORD)    MARIADB_ROOT_PASSWORD=${VALUE} ;;
             *)
     esac
 done
 
 IMAGE="$REGISTRY"/"$NAME":"$TAG_PRE"-"$TAG_VER"
-docker run --detach --name $CONTAINER_NAME --publish $MARIADB_HOST_PORT:3306 --volume $HOST_STORAGE_DIR:/var/lib/mysql -v "/$(pwd)/mariadb.conf:/etc/mysql/conf.d/my.cnf" -e MYSQL_ROOT_PASSWORD="$MARIADB_ROOT_PASSWORD" $IMAGE
+docker run --detach --name $CONTAINER_NAME --publish $MARIADB_HOST_PORT:3306 -v $DOCKER_VOLUME_NAME:/var/lib/mysql -v "/$(pwd)/mariadb.conf:/etc/mysql/conf.d/my.cnf" $IMAGE
 sleep 10
-docker exec $CONTAINER_NAME /bin/bash -c 'rm -rf /docker-entrypoint-initdb.d/*.sql'
index 6b77dd9..c1be674 100755 (executable)
@@ -22,12 +22,12 @@ NAME=validation
 TAG_PRE=ui
 TAG_VER=latest
 # Container input parameters
-MARIADB_ROOT_PASSWORD=""
+MARIADB_AKRAINO_PASSWORD=""
 JENKINS_URL=""
 JENKINS_USERNAME=""
 JENKINS_USER_PASSWORD=""
 JENKINS_JOB_NAME=""
-DB_CONNECTION_URL=""
+DB_IP_PORT=""
 NEXUS_PROXY=""
 JENKINS_PROXY=""
 
@@ -40,12 +40,12 @@ do
             NAME)    NAME=${VALUE} ;;
             TAG_PRE)    TAG_PRE=${VALUE} ;;
             TAG_VER)    TAG_VER=${VALUE} ;;
-            MARIADB_ROOT_PASSWORD)    MARIADB_ROOT_PASSWORD=${VALUE} ;;
+            MARIADB_AKRAINO_PASSWORD)    MARIADB_AKRAINO_PASSWORD=${VALUE} ;;
             JENKINS_URL)    JENKINS_URL=${VALUE} ;;
             JENKINS_USERNAME)    JENKINS_USERNAME=${VALUE} ;;
             JENKINS_USER_PASSWORD)    JENKINS_USER_PASSWORD=${VALUE} ;;
             JENKINS_JOB_NAME)    JENKINS_JOB_NAME=${VALUE} ;;
-            DB_CONNECTION_URL)    DB_CONNECTION_URL=${VALUE} ;;
+            DB_IP_PORT)    DB_IP_PORT=${VALUE} ;;
             CONTAINER_NAME)    CONTAINER_NAME=${VALUE} ;;
             NEXUS_PROXY) NEXUS_PROXY=${VALUE} ;;
             JENKINS_PROXY) JENKINS_PROXY=${VALUE} ;;
@@ -53,15 +53,15 @@ do
     esac
 done
 
-if [ -z "$DB_CONNECTION_URL" ]
+if [ -z "$DB_IP_PORT" ]
   then
-    echo "ERROR: You must specify the database connection url"
+    echo "ERROR: You must specify the database IP and port"
     exit 1
 fi
 
-if [ -z "$MARIADB_ROOT_PASSWORD" ]
+if [ -z "$MARIADB_AKRAINO_PASSWORD" ]
   then
-    echo "ERROR: You must specify the mariadb root user password"
+    echo "ERROR: You must specify the mariadb akraino user password"
     exit 1
 fi
 
@@ -90,5 +90,5 @@ if [ -z "$JENKINS_JOB_NAME" ]
 fi
 
 IMAGE="$REGISTRY"/"$NAME":"$TAG_PRE"-"$TAG_VER"
-docker run --name $CONTAINER_NAME --network="host" -it --rm -e DB_CONNECTION_URL="$DB_CONNECTION_URL" -e MARIADB_ROOT_PASSWORD="$MARIADB_ROOT_PASSWORD" -e JENKINS_URL="$JENKINS_URL" -e JENKINS_USERNAME="$JENKINS_USERNAME" -e JENKINS_USER_PASSWORD="$JENKINS_USER_PASSWORD" -e JENKINS_JOB_NAME="$JENKINS_JOB_NAME" -e NEXUS_PROXY="$NEXUS_PROXY" -e JENKINS_PROXY="$JENKINS_PROXY" $IMAGE
+docker run --detach --name $CONTAINER_NAME --network="host" -e DB_IP_PORT="$DB_IP_PORT" -e MARIADB_AKRAINO_PASSWORD="$MARIADB_AKRAINO_PASSWORD" -e JENKINS_URL="$JENKINS_URL" -e JENKINS_USERNAME="$JENKINS_USERNAME" -e JENKINS_USER_PASSWORD="$JENKINS_USER_PASSWORD" -e JENKINS_JOB_NAME="$JENKINS_JOB_NAME" -e NEXUS_PROXY="$NEXUS_PROXY" -e JENKINS_PROXY="$JENKINS_PROXY" $IMAGE
 sleep 10
index 6f41f59..0e636d2 100644 (file)
@@ -124,3 +124,33 @@ All notable changes to this project will be documented in this file.
 
 ### Removed
 - Unused credentials in music.properties file
+
+## [0.2.0-SNAPSHOT] - 30 August 2019
+### Added
+- Partial loop is supported
+- LAB parameter is now being sent towards Jenkins
+- Logout process is supported
+- Results are retrieved by timestamp, last run and based on date
+- For DB results, a common thread-safe adapter is used
+
+### Changed
+- The common Nexus URL is now also used for full control loop mode.
+- Only the IP and port are needed to be defined regarding DB identification process
+- 'v1' has been added in REST API URLs
+- Small letters are used for all the view names
+- Bug with infinite nested ng-repeat loops fixed
+- The name of war file has been changed from 'AECBlueprintValidationUI' to 'bluvalui'.
+- Bug fixed regarding the display of the overall result.
+- Host verifiers and trust certificates have been moved from clients to 'UiInitializer' spring component.
+- UI docker container is detached when it is deployed
+- README file has been updated to include instructions regarding installation of needed tools for the development mode
+- 200 most recent results are retrieved on each nexus scan loop
+- A common diplay test suite view is used now
+- DB results have been divided in order to support layer as a key
+- DB akraino user is used instead of DB root user
+- test.info.yaml parsing is supported
+- Selection of optional test cases is supported
+- Pagination table is supported for committed submissions
+
+### Removed
+
index eae8f30..8006953 100644 (file)
@@ -31,8 +31,6 @@ In specific, the purpose of the UI is twofold:
 2) Partial control of producing results. In this mode, the UI must be connected with a mariadb instance and the Nexus server where the results are stored.
    Every blueprint owner is responsible of executing tests and storing results in Nexus using his/her own Jenkins instance. The UI only retrieves results from Nexus and displays them.
 
-Currently, the partial control loop is not supported.
-
 In both modes, user authentication, authorization and accounting (AAA) will be supported in order to control access to resources, enforce policies on these resources and audit their usage.
 
 Prerequisites:
@@ -81,6 +79,89 @@ Download the project
 Prerequisites
 ~~~~~~~~~~~~~
 
+- Tools
+
+In order to setup the development environment, the following tools are needed:
+- JDK 1.8
+- Maven
+- docker
+- MySQL client
+
+Execute the commands below in order to install these tools (note that the PROXY_IP and PROXY_PORT variables must be substituted with the ones that are used by the hosting operating system)
+
+If the host is behind a proxy, define this proxy using the following commands:
+
+.. code-block:: console
+    sudo touch /etc/apt/apt.conf.d/proxy.conf
+    sudo sh -c 'echo "Acquire::http::proxy \"http://<PROXY_IP>:<PROXY_PORT>/\";" >> /etc/apt/apt.conf.d/proxy.conf'
+    sudo sh -c 'echo "Acquire::https::proxy \"https://<PROXY_IP>:<PROXY_PORT>/\";" >> /etc/apt/apt.conf.d/proxy.conf'
+    sudo sh -c 'echo "Acquire::ftp::proxy \"ftp://<PROXY_IP>:<PROXY_PORT>/\";" >> /etc/apt/apt.conf.d/proxy.conf'
+    sudo apt-get update
+    export http_proxy=http://<PROXY_IP>:<PROXY_PORT>
+    export https_proxy=http://<PROXY_IP>:<PROXY_PORT>
+
+Install jdk and maven using the following commands:
+
+.. code-block:: console
+    sudo apt install default-jdk
+    sudo apt install maven
+
+If the host is behind a proxy, configure this proxy for maven:
+
+.. code-block:: console
+    nano ~/.m2/settings.xml
+    <Paste the following lines>
+
+    <settings xmlns="http://maven.apache.org/SETTINGS/1.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd">
+     <proxies>
+      <proxy>
+       <active>true</active>
+       <protocol>http</protocol>
+       <host><PROXY_IP></host>
+       <port><PROXY_PORT></port>
+       <nonProxyHosts>127.0.0.1|localhost</nonProxyHosts>
+      </proxy>
+      <proxy>
+       <id>https</id>
+       <active>true</active>
+       <protocol>https</protocol>
+       <host><PROXY_IP></host>
+       <port><PROXY_PORT></port>
+       <nonProxyHosts>127.0.0.1|localhost</nonProxyHosts>
+      </proxy>
+     </proxies>
+    </settings>
+
+    <Save and exit from nano>
+
+Install docker using the following commands:
+
+.. code-block:: console
+    sudo apt install docker.io
+    sudo groupadd docker
+    sudo gpasswd -a $USER docker
+    newgrp docker
+
+If the host is behind a proxy, configure docker to use this proxy:
+
+.. code-block:: console
+    mkdir /etc/systemd/system/docker.service.d
+    sudo nano /etc/systemd/system/docker.service.d/http-proxy.conf
+    <Paste the following lines>
+
+    [Service]
+    Environment="HTTP_PROXY=http://<PROXY_IP>:<PROXY_PORT>/"
+
+    <Save and exit from nano>
+
+    sudo systemctl daemon-reload
+    sudo systemctl restart docker
+
+Install mySQL client:
+
+.. code-block:: console
+    sudo apt install mysql-client
+
 - Database
 
 A mariadb database instance is needed for both modes of the UI with the appropriate databases and tables in order for the back-end system to store and retrieve data.
@@ -91,6 +172,7 @@ Also, a script has been developed, namely validation/docker/mariadb/deploy.sh wh
 
 CONTAINER_NAME, name of the container, default value is akraino-validation-mariadb
 MARIADB_ROOT_PASSWORD, the desired mariadb root user password, this variable is required
+MARIADB_AKRAINO_PASSWORD, the desired mariadb akraino user password, this variable is required
 UI_ADMIN_PASSWORD, the desired Blueprint Validation UI password for the admin user, this variable is required
 UI_AKRAINO_PASSWORD, the desired Blueprint Validation UI password for the akraino user, this variable is required
 REGISTRY, registry of the mariadb image, default value is akraino
@@ -99,19 +181,19 @@ TAG_PRE, first part of the image version, default value is mariadb
 TAG_VER, last part of the image version, default value is latest
 MARIADB_HOST_PORT, port on which mariadb is exposed on host, default value is 3307
 
-Currently, two users are supported for the UI, namely admin (full privileges) and akraino (limited privileges). Their passwords must be defined in the database.
+Currently, two users are supported by the UI, namely admin (full privileges) and akraino (limited privileges). Their passwords must be defined in the database.
 
 In order to build and deploy the image using only the required parameters, the below instructions should be followed:
 
-The mariadb root user password (currently the UI connects to the database using root privileges), the UI admin password and the UI akraino password should be configured using the appropriate variables and the following commands should be executed:
+The mariadb root password, mariadb akraino user password (currently the UI connects to the database using the akraino user), the UI admin password and the UI akraino password should be configured using the appropriate variables and the following commands should be executed:
 
 .. code-block:: console
 
     cd validation/ui
     mvn docker:build -Ddocker.filter=akraino/validation:dev-mariadb-latest
     cd ../docker/mariadb
-    ./deploy.sh TAG_PRE=dev-mariadb MARIADB_ROOT_PASSWORD=<root user password> UI_ADMIN_PASSWORD=<UI admin user password> UI_AKRAINO_PASSWORD=<UI akraino user password>
-    mysql -p<MARIADB_ROOT_PASSWORD> -uroot -h <IP of the mariadb container> < ../../ui/db-scripts/examples/initialize_db_example.sql
+    ./deploy.sh TAG_PRE=dev-mariadb MARIADB_ROOT_PASSWORD=<mariadb root user password> MARIADB_AKRAINO_PASSWORD=<mariadb akraino user password> UI_ADMIN_PASSWORD=<UI admin user password> UI_AKRAINO_PASSWORD=<UI akraino user password>
+    mysql -p<MARIADB_AKRAINO_PASSWORD> -uakraino -h <IP of the mariadb container> < ../../ui/db-scripts/examples/initialize_db_example.sql
 
 In order to retrieve the IP of the mariadb container, the following command should be executed:
 
@@ -121,12 +203,11 @@ In order to retrieve the IP of the mariadb container, the following command shou
 
 Furthermore, the TAG_PRE variable should be defined because the default value is 'mariadb' (note that the 'dev-mariadb' is used for development purposes - look at pom.xml file).
 
-If the database must be re-deployed (it is assumed that the corresponding mariadb container has been stopped and deleted) while the persistent storage already exists (currently, the directory /var/lib/mariadb of the host is used), a different approach should be used after the image build process.
+If the database must be re-deployed (it is assumed that the corresponding mariadb container has been stopped and deleted) while the persistent storage already exists (currently, the 'akraino-validation-mariadb' docker volume is used), a different approach should be used after the image building process.
 
 To this end, another script has been developed, namely validation/docker/mariadb/deploy_with_existing_storage.sh which easily deploys the container. This script accepts the following as input parameters:
 
 CONTAINER_NAME, the name of the container, default value is akraino-validation-mariadb
-MARIADB_ROOT_PASSWORD, the desired mariadb root user password, this variable is required
 REGISTRY, the registry of the mariadb image, default value is akraino
 NAME, the name of the mariadb image, default value is validation
 TAG_PRE, the first part of the image version, default value is mariadb
@@ -135,23 +216,23 @@ MARIADB_HOST_PORT, the port on which mariadb is exposed on host, default value i
 
 In order to deploy the image using only the required parameters and the existing persistent storage, the below instructions should be followed:
 
-The mariadb root user password (currently the UI connects to the database using root privileges) should be configured using the appropriate variable and the following commands should be executed:
+The mariadb root user password should be configured using the appropriate variable and the following commands should be executed:
 
 .. code-block:: console
 
     cd validation/docker/mariadb
-    ./deploy_with_existing_persistent_storage.sh TAG_PRE=dev-mariadb MARIADB_ROOT_PASSWORD=<root user password>
+    ./deploy_with_existing_persistent_storage.sh TAG_PRE=dev-mariadb
 
-Finally, if the database must be re-deployed (it is assumed that the corresponding mariadb container has been stopped and deleted) and the old persistent storage must be deleted, the directory on the host machine where data is stored should be first deleted (note that all database's data will be lost).
+Finally, if the database must be re-deployed (it is assumed that the corresponding mariadb container has been stopped and deleted) and the old persistent storage must be deleted, the used docker volume should be first deleted (note that all database's data will be lost).
 
 To this end, after the image build process, the following commands should be executed:
 
 .. code-block:: console
 
-    sudo rm -rf /var/lib/mariadb
+    docker volume rm akraino-validation-mariadb
     cd validation/docker/mariadb
-    ./deploy.sh TAG_PRE=dev-mariadb MARIADB_ROOT_PASSWORD=<root user password> UI_ADMIN_PASSWORD=<UI admin user password> UI_AKRAINO_PASSWORD=<UI akraino user password>
-    mysql -p<MARIADB_ROOT_PASSWORD> -uroot -h <IP of the mariadb container> < ../../ui/db-scripts/examples/initialize_db_example.sql
+    ./deploy.sh TAG_PRE=dev-mariadb MARIADB_ROOT_PASSWORD=<root user password> MARIADB_AKRAINO_PASSWORD=<mariadb akraino user password> UI_ADMIN_PASSWORD=<UI admin user password> UI_AKRAINO_PASSWORD=<UI akraino user password>
+    mysql -p<MARIADB_AKRAINO_PASSWORD> -uakraino -h <IP of the mariadb container> < ../../ui/db-scripts/examples/initialize_db_example.sql
 
 In the context of the full control loop mode, the following tables must be initialized with appropriate data:
 
@@ -161,7 +242,7 @@ In the context of the full control loop mode, the following tables must be initi
 - blueprint (here every blueprint owner should register the name of the blueprint)
 - blueprint_instance_for_validation (here every blueprint owner should register the blueprint instances for validation, i.e. version, layer and description of a layer)
 
-The following file can be used for initializing the aforementioned data (as it was performed in the above example using the 'mysql -p<MARIADB_ROOT_PASSWORD> -uroot -h <IP of the mariadb container> < ../../ui/db-scripts/examples/initialize_db_example.sql' command):
+The following file can be used for initializing the aforementioned data (as it was performed in the above example using the 'mysql -p<MARIADB_AKRAINO_PASSWORD> -uakraino -h <IP of the mariadb container> < ../../ui/db-scripts/examples/initialize_db_example.sql' command):
 
     db-scripts/examples/initialize_db_example.sql
 
@@ -208,7 +289,7 @@ Then, the following command should be executed:
 
 .. code-block:: console
 
-    mysql -p<MARIADB_ROOT_PASSWORD> -uroot -h <IP of the mariadb container> < ./dbscript.sql
+    mysql -p<MARIADB_AKRAINO_PASSWORD> -uakraino -h <IP of the mariadb container> < ./dbscript.sql
 
 For example, if a user wants to define a new timeslot with the following data:
 
@@ -228,7 +309,7 @@ Then, the following command should be executed:
 
 .. code-block:: console
 
-    mysql -p<MARIADB_ROOT_PASSWORD> -uroot -h <IP of the mariadb container> < ./dbscript.sql
+    mysql -p<MARIADB_AKRAINO_PASSWORD> -uakraino -h <IP of the mariadb container> < ./dbscript.sql
 
 For example, if a user wants to define a new silo with the following data:
 
@@ -248,7 +329,7 @@ Then, the following command should be executed:
 
 .. code-block:: console
 
-    mysql -p<MARIADB_ROOT_PASSWORD> -uroot -h <IP of the mariadb container> < ./dbscript.sql
+    mysql -p<MARIADB_AKRAINO_PASSWORD> -uakraino -h <IP of the mariadb container> < ./dbscript.sql
 
 Furthermore, if a user wants to define a new blueprint, namely "newBlueprint" and a new instance of this blueprint with the following data:
 
@@ -267,7 +348,7 @@ Then, the following command should be executed:
 
 .. code-block:: console
 
-    mysql -p<MARIADB_ROOT_PASSWORD> -uroot -h <IP of the mariadb container> < ./dbscript.sql
+    mysql -p<MARIADB_AKRAINO_PASSWORD> -uakraino -h <IP of the mariadb container> < ./dbscript.sql
 
 The UI will automatically retrieve this new data and display it to the user.
 
@@ -279,18 +360,13 @@ It should be noted that it is not the UI responsibility to deploy a Jenkins inst
 
 Furthermore, this instance must have the following option enabled: "Manage Jenkins -> Configure Global Security -> Prevent Cross Site Request Forgery exploits".
 
-Also, currently, the corresponding Jenkins job should accept the following as input parameters: "SUBMISSION_ID", "BLUEPRINT", "VERSION", "LAYER" and "UI_IP".
+Also, currently, the corresponding Jenkins job should accept the following as input parameters: "SUBMISSION_ID", "BLUEPRINT", "VERSION", "LAYER", "LAB" and "UI_IP".
 The "SUBMISSION_ID" and "UI_IP" parameters (i.e. IP address of the UI host machine-this is needed by the Jenkins instance in order to send back Job completion notification) are created and provided by the back-end part of the UI.
-The "BLUEPRINT", "VERSION" and "LAYER" parameters are configured by the UI user.
+The "BLUEPRINT", "VERSION", "LAYER" and "LAB" parameters are configured by the UI user.
 
 Moreover, as the Jenkins notification plugin (https://wiki.jenkins.io/display/JENKINS/Notification+Plugin) seems to ignore proxy settings, the corresponding Jenkins job must be configured to execute the following commands at the end (Post-build Actions)
 
-.. code-block:: console
-
-    cookie=`curl -v -H "Content-Type: application/x-www-form-urlencoded" -X POST --insecure --silent http://$UI_IP:8080/AECBlueprintValidationUI/login_external -d "loginId=akraino&password=akraino" 2>&1 | grep "Set-Cookie: " | awk -F ':' '{print $2}'`
-    curl -v --cookie $cookie -H "Content-Type: application/json" -X POST --insecure --silent http://$UI_IP:8080/AECBlueprintValidationUI/api/jenkinsJobNotification/ --data '{"submissionId": "'"$SUBMISSION_ID"'" , "name":"'"$JOB_NAME"'", "buildNumber":"'"$BUILD_NUMBER"'"}'
-
-It should be noted that the credentials user=akraino and password=akraino defined in the above commands should be replaced with the credentials of a real UI user. Recall that these credentials are defined in the database.
+TBD
 
 - Nexus server
 
@@ -298,19 +374,17 @@ All the blueprint validation results are stored in Nexus server for both modes o
 
 It should be noted that it is not the UI responsibility to deploy a Nexus server.
 
-In the context of the full control loop, these results must be available in the following url:
+These results must be available in the following url:
 
-    https://nexus.akraino.org/content/sites/logs/<lab_silo>/job/<Jenkins Job name>/<Jenkins job number>/results/<layer>/<name_of_the_test_suite>.
+    https://nexus.akraino.org/content/sites/logs/<lab_silo>/<Blueprint name>/<Blueprint version>/<timestamp>/results/<layer>/<name_of_the_test_suite>
 
-where <lab_silo> is the silo used by a lab for storing results in Nexus (for example 'att-blu-val'), <Jenkins job name> is the Jenkins job name that is triggered by the UI, <Jenkins job number> is the number of the Jenkins job that produced this result, <layer> is the blueprint layer and <name_of_the_test_suite> is the name of the corresponding test suite.
+where <lab_silo> is the silo used by a lab for storing results in Nexus (for example 'att-blu-val'), <Blueprint name> is the name of the blueprint, <Blueprint version> the the blueprint version, <timestamp> is the timestamp used for producinf the results, <layer> is the blueprint layer and <name_of_the_test_suite> is the name of the corresponding test suite.
 
-If multiple test suites are available, multiple test suite names should be created.
+Below, an example URL is illustrated
 
-Moreover, the results should be stored in the 'output.xml' file and placed in the aforementioned URL using the following format:
-
-TBD
+   https://nexus.akraino.org/content/sites/logs/att-blu-val/rec/master/20190611-132818/results/hardware/bios_version/
 
-In the context of partial control, the results must be available in the following url:
+Moreover, the results should be stored in the 'output.xml' file and placed in the aforementioned URL using the following format:
 
 TBD
 
@@ -330,13 +404,13 @@ The pom.xml file supports the building of an appropriate container image using t
 This script accepts the following as input parameters:
 
 CONTAINER_NAME, the name of the contaner, default value is akraino-validation-ui
-DB_CONNECTION_URL, the URL connection with the akraino database of the maridb instance, this variable is required
-MARIADB_ROOT_PASSWORD, the mariadb root user password, this variable is required
+DB_IP_PORT, the IP and port of the maridb instance, this variable is required
+MARIADB_AKRAINO_PASSWORD, the mariadb akraino user password, this variable is required
 REGISTRY, the registry of the mariadb image, default value is akraino
 NAME, the name of the mariadb image, default value is validation
 TAG_PRE, the first part of the image version, default value is ui
 TAG_VER, the last part of the image version, default value is latest
-JENKINS_URL, the URL of the Jenkins instance, this variable is required
+JENKINS_URL, the URL of the Jenkins instance (http or https must be defined), this variable is required
 JENKINS_USERNAME, the Jenkins user name, this variable is required
 JENKINS_USER_PASSWORD, the Jenkins user password, this variable is required
 JENKINS_JOB_NAME, the name of Jenkins job capable of executing the blueprint validation tests, this variable is required
@@ -345,8 +419,8 @@ JENKINS_PROXY, the needed proxy in order for the Jenkins server to be reachable,
 
 In order to build the image using only the required parameters, the following data is needed:
 
-- The mariadb root user password (look at the Database subsection)
-- The URL for connecting to the akraino database of the mariadb
+- The mariadb akraino user password (look at the Database subsection)
+- The IP and port of the mariadb
 - The Jenkins url
 - The Jenkins username and password
 - The name of Jenkins Job
@@ -358,9 +432,9 @@ Then, the following commands can be executed in order to build and deploy the UI
     cd validation/ui
     mvn docker:build -Ddocker.filter=akraino/validation:dev-ui-latest
     cd ../docker/ui
-    ./deploy.sh TAG_PRE=dev-ui DB_CONNECTION_URL=<Url in order to connect to akraino database of the mariadb> MARIADB_ROOT_PASSWORD=<mariadb root password> JENKINS_URL=<http://jenkinsIP:port> JENKINS_USERNAME=<Jenkins user> JENKINS_USER_PASSWORD=<Jenkins password> JENKINS_JOB_NAME=<Jenkins job name>
+    ./deploy.sh TAG_PRE=dev-ui DB_IP_PORT=<IP and port of the mariadb> MARIADB_AKRAINO_PASSWORD=<mariadb akraino password> JENKINS_URL=<http://jenkinsIP:port> JENKINS_USERNAME=<Jenkins user> JENKINS_USER_PASSWORD=<Jenkins password> JENKINS_JOB_NAME=<Jenkins job name>
 
-The content of the DB_CONNECTION_URL can be for example 172.17.0.3:3306/akraino (i.e. IP and port of the database container plus '/akraino').
+The content of the DB_IP_PORT can be for example '172.17.0.3:3306'.
 
 Furthermore, the TAG_PRE variable should be defined as the default value is 'ui' (note that the 'dev-ui' is used for development purposes - look at pom.xml file).
 
@@ -368,7 +442,7 @@ If no proxy exists, the proxy ip and port variables should not be defined.
 
 The UI should be available in the following url:
 
-    http://localhost:8080/AECBlueprintValidationUI
+    http://localhost:8080/bluvalui/
 
 Note that the deployment uses the network host mode, so the 8080 must be available on the host.
 
@@ -378,12 +452,7 @@ TBD
 
 Limitations
 -----------
-- The partial loop mode is not currently supported.
 - The UI has been tested using Chrome and Firefox browsers.
 - The back-end part of the UI does not take into account the start date and time and duration of the configured timeslot. It immediately triggers the corresponding Jenkins Job.
 - Results data manipulation (filtering, graphical representation, indexing in time order, etc) is not supported.
-- Only the following labs are supported: AT&T, Ericsson, Community and Arm.
-- Only the following tabs are functional: 'Committed Submissions', 'Blueprint Validation Results -> Get by submission id'.
-- The UI configures only the "BLUEPRINT", "VERSION", "LAYER", "SUBMISSION_ID" and "UI_IP" input parameters of the Jenkins job.
-- The silos, labs, and the available blueprints and timeslots must be manually configured in the mariadb database.
-- Logout action is not currently supported.
\ No newline at end of file
+- The silos, labs, and the available blueprints and timeslots must be manually configured in the mariadb database.
\ No newline at end of file
index c248b5b..1dc1742 100644 (file)
@@ -26,18 +26,13 @@ INSERT INTO fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD,
 INSERT INTO fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (930, 'Search', 9, 15, 'userProfile', 'menu_admin', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', '/static/fusion/images/search_profile.png');
 INSERT INTO fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (150022, 'Menus', 10, 60, 'admin#/admin_menu_edit', 'menu_admin', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', NULL);
 INSERT INTO fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (150038,'Notebook',5000,135,'samplePage#/notebook','menu_sample','Y',NULL,NULL,NULL,NULL,'APP','N',NULL);
-Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (21, 'New Submission', 1, 10, 'newSubmission', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', 'icon-building-home');
-Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (22, 'Committed Submissions', 1, 10, 'committedSubmissions', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', 'icon-building-home');
+Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (21, 'New Submission', 1, 10, 'newsubmission', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', 'icon-building-home');
+Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (22, 'Committed Submissions', 1, 10, 'committedsubmissions', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', 'icon-building-home');
 Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (23, 'Validation Results', 1, 10, 'report.htm', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', 'icon-misc-piechart');
-Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (24, 'Get by submission id', 23, 10, 'getBySubmissionId', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', '/static/fusion/images/reports.png');
-Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (25, 'Get by blueprint name', 23, 10, '', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', '/static/fusion/images/reports.png');
-Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (26, 'Get by layer', 23, 10, '', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', '/static/fusion/images/reports.png');
-Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (27, 'Get by execution dates', 23, 10, '', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', '/static/fusion/images/reports.png');
-Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (28, 'Get by number of successful runs', 23, 10, '', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', '/static/fusion/images/reports.png');
-Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (29, 'Get by number of successful last runs', 23, 10, '', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', '/static/fusion/images/reports.png');
-Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (30, 'Get by number of failed last runs', 23, 10, '', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', '/static/fusion/images/reports.png');
-Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (31, 'Get all', 23, 10, '', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', '/static/fusion/images/reports.png');
-
+Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (24, 'Get most recent', 23, 10, 'getmostrecent', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', '/static/fusion/images/reports.png');
+Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (25, 'Get by timestamp', 23, 10, 'getbytimestamp', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', '/static/fusion/images/reports.png');
+Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (26, 'Get last run', 23, 10, 'getlastrun', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', '/static/fusion/images/reports.png');
+Insert into fn_menu (MENU_ID, LABEL, PARENT_ID, SORT_ORDER, ACTION, FUNCTION_CD, ACTIVE_YN, SERVLET, QUERY_STRING, EXTERNAL_URL, TARGET, MENU_SET_CD, SEPARATOR_YN, IMAGE_SRC) VALUES (27, 'Get based on dates', 23, 10, 'getbasedondate', 'menu_tab', 'Y', NULL, NULL, NULL, NULL, 'APP', 'N', '/static/fusion/images/reports.png');
 
 -- fn_user
 Insert into fn_user (USER_ID,ORG_ID,MANAGER_ID,FIRST_NAME,MIDDLE_NAME,LAST_NAME,PHONE,FAX,CELLULAR,EMAIL,ADDRESS_ID,ALERT_METHOD_CD,HRID,ORG_USER_ID,ORG_CODE,LOGIN_ID,LOGIN_PWD,LAST_LOGIN_DATE,ACTIVE_YN,CREATED_ID,CREATED_DATE,MODIFIED_ID,MODIFIED_DATE,IS_INTERNAL_YN,ADDRESS_LINE_1,ADDRESS_LINE_2,CITY,STATE_CD,ZIP_CODE,COUNTRY_CD,LOCATION_CLLI,ORG_MANAGER_USERID,COMPANY,DEPARTMENT_NAME,JOB_TITLE,TIMEZONE,DEPARTMENT,BUSINESS_UNIT,BUSINESS_UNIT_NAME,COST_CENTER,FIN_LOC_CODE,SILO_STATUS) values (1,null,null,'admin',null,'User',null,null,null,'admin@email.com',null,null,null,'admin',null,'admin','admin_password',str_to_date('24-OCT-16','%d-%M-%Y'),'Y',null,str_to_date('17-OCT-16','%d-%M-%Y'),1,str_to_date('24-OCT-16','%d-%M-%Y'),'N',null,null,null,'NJ',null,'US',null,null,null,null,null,10,null,null,null,null,null,null);
index 06aa4a8..6b94c2c 100644 (file)
@@ -18,16 +18,18 @@ SET FOREIGN_KEY_CHECKS=1;
 
 use akraino;
 
-DROP TABLE IF EXISTS submission;
 DROP TABLE IF EXISTS blueprint_instance_for_validation;
 DROP TABLE IF EXISTS blueprint;
 DROP TABLE IF EXISTS silo;
 DROP TABLE IF EXISTS timeslot;
 DROP TABLE IF EXISTS lab;
+DROP TABLE IF EXISTS w_robot_test_result;
+DROP TABLE IF EXISTS validation_test_result;
+DROP TABLE IF EXISTS submission;
 
 create table lab (
    id bigint not NULL AUTO_INCREMENT,
-   lab text not NULL,
+   lab text not NULL unique,
    CONSTRAINT id_pk PRIMARY KEY (id)
 );
 
@@ -45,7 +47,7 @@ create table timeslot (
 create table silo (
    id bigint not NULL AUTO_INCREMENT,
    silo text not NULL,
-   lab_id bigint not NULL,
+   lab_id bigint not NULL unique,
    CONSTRAINT id_pk PRIMARY KEY (id),
    CONSTRAINT lab_id_fk2 FOREIGN KEY (lab_id)
       REFERENCES lab (id) MATCH SIMPLE
@@ -69,24 +71,54 @@ CREATE TABLE blueprint_instance_for_validation
    CONSTRAINT id_pk PRIMARY KEY (id),
    CONSTRAINT blueprint_id_fk FOREIGN KEY (blueprint_id)
       REFERENCES blueprint (id) MATCH SIMPLE
-      ON UPDATE NO ACTION ON DELETE NO ACTION
+      ON UPDATE NO ACTION ON DELETE NO ACTION,
+   unique (version, layer, blueprint_id)
 );
 
 CREATE TABLE submission
 (
    id bigint not NULL AUTO_INCREMENT,
    status text not NULL,
-   jenkins_queue_job_item_url text,
-   nexus_result_url text,
-   blueprint_instance_for_validation_id bigint not NULL,
    timeslot_id bigint not NULL,
    CONSTRAINT id_pk PRIMARY KEY (id),
-   CONSTRAINT blueprint_instance_for_validation_id_fk FOREIGN KEY (blueprint_instance_for_validation_id)
-      REFERENCES blueprint_instance_for_validation (id) MATCH SIMPLE
-      ON UPDATE NO ACTION ON DELETE NO ACTION,
    CONSTRAINT timeslot_id_fk FOREIGN KEY (timeslot_id)
       REFERENCES timeslot (id) MATCH SIMPLE
       ON UPDATE NO ACTION ON DELETE NO ACTION
 );
 
+CREATE TABLE validation_test_result
+(
+   id bigint not NULL AUTO_INCREMENT,
+   blueprint_name varchar(20) not NULL,
+   version text not NULL,
+   lab_id bigint not NULL,
+   timestamp text,
+   all_layers boolean,
+   optional boolean,
+   result boolean,
+   submission_id bigint,
+   date_of_storage text,
+   CONSTRAINT id_pk PRIMARY KEY (id),
+   CONSTRAINT lab_id_fk3 FOREIGN KEY (lab_id)
+      REFERENCES lab (id) MATCH SIMPLE
+      ON UPDATE NO ACTION ON DELETE NO ACTION,
+   CONSTRAINT submission_id_fk FOREIGN KEY (submission_id)
+      REFERENCES submission (id) MATCH SIMPLE
+      ON UPDATE NO ACTION ON DELETE NO ACTION,
+   unique (timestamp, lab_id)
+);
+
+CREATE TABLE w_robot_test_result
+(
+   id bigint not NULL AUTO_INCREMENT,
+   layer text not NULL,
+   validation_test_result_id bigint not NULL,
+   robot_test_results LONGTEXT,
+   CONSTRAINT id_pk PRIMARY KEY (id),
+   CONSTRAINT validation_test_result_id_fk FOREIGN KEY (validation_test_result_id)
+      REFERENCES validation_test_result (id) MATCH SIMPLE
+      ON UPDATE NO ACTION ON DELETE NO ACTION,
+   unique (layer, validation_test_result_id)
+);
+
 commit;
index 7902b94..1273ae6 100644 (file)
@@ -25,14 +25,13 @@ insert into timeslot values(1, 'now', null, 1);
 insert into silo values(1, 'att-blu-val', 1);
 
 insert into blueprint (id, blueprint_name) values(1, 'dummy');
-insert into blueprint (id, blueprint_name) values(2, 'Unicycle');
-insert into blueprint (id, blueprint_name) values(3, 'REC');
-
-insert into blueprint_instance_for_validation (id, blueprint_id, version, layer, layer_description) values(1, 1, 'latest', 0, 'Dummy Hardware');  /* 0 Stands for hardware layer */
-insert into blueprint_instance_for_validation (id, blueprint_id, version, layer, layer_description) values(2, 3, 'latest', 0, 'AT&T Hardware'); /* 0 Stands for hardware layer */
-insert into blueprint_instance_for_validation (id, blueprint_id, version, layer, layer_description) values(3, 3, 'latest', 1, 'OS of the AT&T platform'); /* 1 Stands for OS layer */
-insert into blueprint_instance_for_validation (id, blueprint_id, version, layer, layer_description) values(4, 3, 'latest', 2, 'K8s of the AT&T platform'); /* 2 Stands for K8s layer */
-insert into blueprint_instance_for_validation (id, blueprint_id, version, layer, layer_description) values(5, 3, 'latest', 7, 'All layers'); /* 7 Stands for all layers */
-insert into blueprint_instance_for_validation (id, blueprint_id, version, layer, layer_description) values(6, 2, 'latest', 0, 'Unicycle Hardware'); /* 0 Stands for hardware layer */
+insert into blueprint (id, blueprint_name) values(2, 'unicycle');
+insert into blueprint (id, blueprint_name) values(3, 'rec');
+
+insert into blueprint_instance_for_validation (id, blueprint_id, version, layer, layer_description) values(1, 1, 'master', 0, 'Dummy Hardware');  /* 0 Stands for hardware layer */
+insert into blueprint_instance_for_validation (id, blueprint_id, version, layer, layer_description) values(2, 3, 'master', 0, 'AT&T Hardware'); /* 0 Stands for hardware layer */
+insert into blueprint_instance_for_validation (id, blueprint_id, version, layer, layer_description) values(3, 3, 'master', 1, 'OS of the AT&T platform'); /* 1 Stands for OS layer */
+insert into blueprint_instance_for_validation (id, blueprint_id, version, layer, layer_description) values(4, 3, 'master', 2, 'K8s of the AT&T platform'); /* 2 Stands for K8s layer */
+insert into blueprint_instance_for_validation (id, blueprint_id, version, layer, layer_description) values(6, 2, 'master', 0, 'Unicycle Hardware'); /* 0 Stands for hardware layer */
 
 commit;
index e4736ef..f3f0c97 100644 (file)
@@ -14,8 +14,8 @@
 
     <groupId>org.akraino.validation</groupId>
     <artifactId>ui</artifactId>
-    <version>0.1.0-SNAPSHOT</version>
-    <name>AECBlueprintValidationUI Maven Webapp</name>
+    <version>0.2.0-SNAPSHOT</version>
+    <name>Bluval UI Maven Webapp</name>
     <packaging>war</packaging>
 
     <properties>
@@ -64,7 +64,7 @@
 
     <build>
         <!-- The war file name carries no version number -->
-        <finalName>AECBlueprintValidationUI</finalName>
+        <finalName>bluvalui</finalName>
 
         <plugins>
             <plugin>
                 </configuration>
             </plugin>
 
-            <!-- Currently, the docker-maven-plugin is used only for the development mode -->
+            <!-- Currently, the docker-maven-plugin is used only for the
+                development mode -->
             <plugin>
                 <groupId>io.fabric8</groupId>
                 <artifactId>docker-maven-plugin</artifactId>
             <artifactId>commons-httpclient</artifactId>
             <version>${commons-httpclient.version}</version>
         </dependency>
-
     </dependencies>
 </project>
index 6c80c24..f4b97a6 100644 (file)
@@ -23,19 +23,9 @@ import java.net.Proxy;
 import java.net.URL;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
 import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
 
 import javax.annotation.Nonnull;
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
 import javax.ws.rs.core.MultivaluedMap;
 
 import org.akraino.validation.ui.client.jenkins.resources.CrumbResponse;
@@ -44,6 +34,7 @@ import org.akraino.validation.ui.client.jenkins.resources.Parameters;
 import org.akraino.validation.ui.client.jenkins.resources.QueueJobItem;
 import org.apache.commons.httpclient.HttpException;
 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.springframework.stereotype.Service;
 
 import com.sun.jersey.api.client.Client;
 import com.sun.jersey.api.client.ClientHandlerException;
@@ -54,15 +45,14 @@ import com.sun.jersey.api.client.config.ClientConfig;
 import com.sun.jersey.api.client.config.DefaultClientConfig;
 import com.sun.jersey.api.client.filter.HTTPBasicAuthFilter;
 import com.sun.jersey.api.json.JSONConfiguration;
-import com.sun.jersey.client.urlconnection.HTTPSProperties;
 import com.sun.jersey.client.urlconnection.HttpURLConnectionFactory;
 import com.sun.jersey.client.urlconnection.URLConnectionClientHandler;
 
+@Service
 public final class JenkinsExecutorClient {
 
     private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(JenkinsExecutorClient.class);
 
-    private static final List<JenkinsExecutorClient> JENKINS_CLIENTS = new ArrayList<>();
     private static final Object LOCK = new Object();
     private final Client client;
 
@@ -70,13 +60,10 @@ public final class JenkinsExecutorClient {
     private final String password;
     private final String baseurl;
 
-    private final HostnameVerifier hostnameVerifier;
-    private final TrustManager[] trustAll;
-
-    private JenkinsExecutorClient(String newUser, String newPassword, String newBaseurl) {
-        this.user = newUser;
-        this.password = newPassword;
-        this.baseurl = newBaseurl;
+    public JenkinsExecutorClient() {
+        this.baseurl = System.getenv("JENKINS_URL");
+        this.user = System.getenv("JENKINS_USERNAME");
+        this.password = System.getenv("JENKINS_USER_PASSWORD");
         ClientConfig clientConfig = new DefaultClientConfig();
         clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
         this.client = new Client(new URLConnectionClientHandler(new HttpURLConnectionFactory() {
@@ -97,44 +84,6 @@ public final class JenkinsExecutorClient {
             }
         }), clientConfig);
         this.client.addFilter(new HTTPBasicAuthFilter(user, password));
-        // Create all-trusting host name verifier
-        hostnameVerifier = new HostnameVerifier() {
-            @Override
-            public boolean verify(String hostname, SSLSession session) {
-                return true;
-            }
-        };
-        // Create a trust manager that does not validate certificate chains
-        trustAll = new TrustManager[] {new X509TrustManager() {
-            @Override
-            public X509Certificate[] getAcceptedIssuers() {
-                return null; // Not relevant.
-            }
-
-            @Override
-            public void checkClientTrusted(X509Certificate[] certs, String authType) {
-                // Do nothing. Just allow them all.
-            }
-
-            @Override
-            public void checkServerTrusted(X509Certificate[] certs, String authType) {
-                // Do nothing. Just allow them all.
-            }
-        }};
-    }
-
-    public static synchronized JenkinsExecutorClient getInstance(@Nonnull String newUser, @Nonnull String newPassword,
-            @Nonnull String newBaseurl) throws MalformedURLException {
-        new URL(newBaseurl);
-        for (JenkinsExecutorClient client : JENKINS_CLIENTS) {
-            if (client.getBaseUrl().equals(newBaseurl) && client.getUser().equals(newUser)
-                    && client.getPassword().equals(newPassword)) {
-                return client;
-            }
-        }
-        JenkinsExecutorClient client = new JenkinsExecutorClient(newUser, newPassword, newBaseurl);
-        JENKINS_CLIENTS.add(client);
-        return client;
     }
 
     public String getUser() {
@@ -150,7 +99,7 @@ public final class JenkinsExecutorClient {
     }
 
     public QueueJobItem getQueueJobItem(URL queueJobItemUrl) throws HttpException, ClientHandlerException,
-            UniformInterfaceException, KeyManagementException, NoSuchAlgorithmException {
+    UniformInterfaceException, KeyManagementException, NoSuchAlgorithmException {
         synchronized (LOCK) {
             LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying to get a Jenkins resource");
             String crumb = this.getCrumb();
@@ -159,29 +108,17 @@ public final class JenkinsExecutorClient {
             LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of get: " + webResource.getURI().toString());
             WebResource.Builder builder = webResource.getRequestBuilder();
             builder.header("Jenkins-Crumb", crumb);
-            ClientResponse response =
-                    builder.accept("application/json").type("application/json").get(ClientResponse.class);
+            ClientResponse response = builder.accept("application/json").type("application/json")
+                    .get(ClientResponse.class);
             if (response.getStatus() != 200) {
                 throw new HttpException("Get on Jenkins failed. HTTP error code : " + response.getStatus()
-                        + " and message: " + response.getEntity(String.class));
+                + " and message: " + response.getEntity(String.class));
             }
             LOGGER.info(EELFLoggerDelegate.applicationLogger, "Get of Jenkins resource succeeded");
             return response.getEntity(QueueJobItem.class);
         }
     }
 
-    /**
-     *
-     * @param jobName
-     * @param parameters
-     * @return The URL of the corresponding Jenkins queue job item
-     * @throws UniformInterfaceException
-     * @throws ClientHandlerException
-     * @throws HttpException
-     * @throws MalformedURLException
-     * @throws NoSuchAlgorithmException
-     * @throws KeyManagementException
-     */
     public URL postJobWithQueryParams(@Nonnull String jobName, @Nonnull Parameters parameters)
             throws HttpException, ClientHandlerException, UniformInterfaceException, MalformedURLException,
             KeyManagementException, NoSuchAlgorithmException {
@@ -194,15 +131,15 @@ public final class JenkinsExecutorClient {
                 queryParams = queryParams + parameter.getName() + "=" + parameter.getValue() + "&";
             }
             queryParams = queryParams.substring(0, queryParams.length() - 1);
-            WebResource webResource =
-                    this.client.resource(this.getBaseUrl() + "/job/" + jobName + "/buildWithParameters" + queryParams);
+            WebResource webResource = this.client
+                    .resource(this.getBaseUrl() + "/job/" + jobName + "/buildWithParameters" + queryParams);
             LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of post: " + webResource.getURI().toString());
             WebResource.Builder builder = webResource.getRequestBuilder();
             builder.header("Jenkins-Crumb", crumb);
             ClientResponse response = builder.type("application/json").post(ClientResponse.class, String.class);
             if (response.getStatus() != 200 && response.getStatus() != 201) {
                 throw new HttpException("Post of Jenkins job failed. HTTP error code : " + response.getStatus()
-                        + " and message: " + response.getEntity(String.class));
+                + " and message: " + response.getEntity(String.class));
             }
             LOGGER.info(EELFLoggerDelegate.applicationLogger, "Jenkins job has been successfully triggered");
             URL buildQueueUrl = null;
@@ -219,32 +156,19 @@ public final class JenkinsExecutorClient {
     }
 
     private String getCrumb() throws HttpException, ClientHandlerException, UniformInterfaceException,
-            KeyManagementException, NoSuchAlgorithmException {
+    KeyManagementException, NoSuchAlgorithmException {
         LOGGER.info(EELFLoggerDelegate.applicationLogger, "Attempting to get the crumb");
-        setProperties();
         String crumbUri = baseurl + "/crumbIssuer/api/json";
         WebResource webResource = this.client.resource(crumbUri);
-        ClientResponse response =
-                webResource.accept("application/json").type("application/json").get(ClientResponse.class);
+        ClientResponse response = webResource.accept("application/json").type("application/json")
+                .get(ClientResponse.class);
         if (response.getStatus() == 201 || response.getStatus() == 200) {
             CrumbResponse crumbResponse = response.getEntity(CrumbResponse.class);
             LOGGER.info(EELFLoggerDelegate.applicationLogger, "Successful crumb retrieval");
             return crumbResponse.getCrumb();
         }
         throw new HttpException("Get crumb attempt towards Jenkins failed. HTTP error code: " + response.getStatus()
-                + " and message: " + response.getEntity(String.class));
-    }
-
-    private void setProperties() throws NoSuchAlgorithmException, KeyManagementException {
-        SSLContext sslContext = SSLContext.getInstance("SSL");
-        sslContext.init(null, this.trustAll, new java.security.SecureRandom());
-        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
-        // Install the all-trusting host verifier
-        HttpsURLConnection.setDefaultHostnameVerifier(this.hostnameVerifier);
-        DefaultClientConfig config = new DefaultClientConfig();
-        Map<String, Object> properties = config.getProperties();
-        HTTPSProperties httpsProperties = new HTTPSProperties((str, sslSession) -> true, sslContext);
-        properties.put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, httpsProperties);
+        + " and message: " + response.getEntity(String.class));
     }
 
 }
index 7ee7239..30206bf 100644 (file)
@@ -22,20 +22,24 @@ import java.net.Proxy;
 import java.net.URL;
 import java.security.KeyManagementException;
 import java.security.NoSuchAlgorithmException;
-import java.security.cert.X509Certificate;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
+import java.util.Locale;
 
-import javax.net.ssl.HostnameVerifier;
-import javax.net.ssl.HttpsURLConnection;
-import javax.net.ssl.SSLContext;
-import javax.net.ssl.SSLSession;
-import javax.net.ssl.TrustManager;
-import javax.net.ssl.X509TrustManager;
+import javax.annotation.Nonnull;
 
 import org.akraino.validation.ui.client.nexus.resources.RobotTestResult;
-import org.akraino.validation.ui.client.nexus.resources.WrapperRobotTestResult;
+import org.akraino.validation.ui.client.nexus.resources.Status;
+import org.akraino.validation.ui.client.nexus.resources.TestInfoYaml;
+import org.akraino.validation.ui.client.nexus.resources.ValidationNexusTestResult;
+import org.akraino.validation.ui.client.nexus.resources.WRobotNexusTestResult;
 import org.akraino.validation.ui.data.BlueprintLayer;
 import org.apache.commons.httpclient.HttpException;
 import org.json.JSONObject;
@@ -44,12 +48,16 @@ import org.jsoup.Jsoup;
 import org.jsoup.nodes.Document;
 import org.jsoup.nodes.Element;
 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.portalsdk.core.onboarding.util.PortalApiProperties;
+import org.onap.portalsdk.core.web.support.UserUtils;
+import org.springframework.stereotype.Service;
 
 import com.fasterxml.jackson.annotation.JsonInclude.Include;
 import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.databind.DeserializationFeature;
 import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
 import com.sun.jersey.api.client.Client;
 import com.sun.jersey.api.client.ClientHandlerException;
 import com.sun.jersey.api.client.ClientResponse;
@@ -58,21 +66,19 @@ import com.sun.jersey.api.client.WebResource;
 import com.sun.jersey.api.client.config.ClientConfig;
 import com.sun.jersey.api.client.config.DefaultClientConfig;
 import com.sun.jersey.api.json.JSONConfiguration;
-import com.sun.jersey.client.urlconnection.HTTPSProperties;
 import com.sun.jersey.client.urlconnection.HttpURLConnectionFactory;
 import com.sun.jersey.client.urlconnection.URLConnectionClientHandler;
 
+@Service
 public final class NexusExecutorClient {
 
     private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(NexusExecutorClient.class);
 
     private final Client client;
     private final String baseurl;
-    private final HostnameVerifier hostnameVerifier;
-    private final TrustManager[] trustAll;
 
-    public NexusExecutorClient(String newBaseurl) {
-        this.baseurl = newBaseurl;
+    public NexusExecutorClient() {
+        this.baseurl = PortalApiProperties.getProperty("nexus_url");
         ClientConfig clientConfig = new DefaultClientConfig();
         clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
         this.client = new Client(new URLConnectionClientHandler(new HttpURLConnectionFactory() {
@@ -81,10 +87,10 @@ public final class NexusExecutorClient {
             @Override
             public HttpURLConnection getHttpURLConnection(URL url) throws IOException {
                 try {
-                    String proxyIp =
-                            System.getenv("NEXUS_PROXY").substring(0, System.getenv("NEXUS_PROXY").lastIndexOf(":"));
-                    String proxyPort =
-                            System.getenv("NEXUS_PROXY").substring(System.getenv("NEXUS_PROXY").lastIndexOf(":") + 1);
+                    String proxyIp = System.getenv("NEXUS_PROXY").substring(0,
+                            System.getenv("NEXUS_PROXY").lastIndexOf(":"));
+                    String proxyPort = System.getenv("NEXUS_PROXY")
+                            .substring(System.getenv("NEXUS_PROXY").lastIndexOf(":") + 1);
                     proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyIp, Integer.parseInt(proxyPort)));
                     return (HttpURLConnection) url.openConnection(proxy);
                 } catch (Exception ex) {
@@ -92,42 +98,289 @@ public final class NexusExecutorClient {
                 }
             }
         }), clientConfig);
-        // Create all-trusting host name verifier
-        hostnameVerifier = new HostnameVerifier() {
-            @Override
-            public boolean verify(String hostname, SSLSession session) {
-                return true;
+    }
+
+    public String getBaseUrl() {
+        return this.baseurl;
+    }
+
+    public List<String> getResource(String endpoint)
+            throws ClientHandlerException, UniformInterfaceException, JsonParseException, JsonMappingException,
+            IOException, KeyManagementException, NoSuchAlgorithmException, ParseException {
+        List<String> resources = new ArrayList<String>();
+        String nexusUrl = this.baseurl;
+        if (endpoint != null) {
+            nexusUrl = this.baseurl + "/" + endpoint;
+        }
+        LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying to get nexus resource: " + nexusUrl);
+        WebResource webResource = this.client.resource(nexusUrl + "/");
+        LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of get: " + webResource.getURI().toString());
+        ClientResponse response = webResource.get(ClientResponse.class);
+        if (response.getStatus() != 200) {
+            throw new HttpException("Could not retrieve nexus resource " + nexusUrl + ". HTTP error code : "
+                    + response.getStatus() + " and message: " + response.getEntity(String.class));
+        }
+        Document document = Jsoup.parse(response.getEntity(String.class));
+        List<Element> elements = document.getElementsByTag("body").get(0).getElementsByTag("table").get(0)
+                .getElementsByTag("tbody").get(0).getElementsByTag("tr");
+        for (int i = 2; i < elements.size(); i++) {
+            String resource = elements.get(i).getElementsByTag("td").get(0).getElementsByTag("a").get(0).text();
+            resource = resource.substring(0, resource.length() - 1);
+            resources.add(resource);
+        }
+        return resources;
+    }
+
+    public List<String> getResource(@Nonnull String endpoint1, @Nonnull String endpoint2)
+            throws ClientHandlerException, UniformInterfaceException, JsonParseException, JsonMappingException,
+            IOException, KeyManagementException, NoSuchAlgorithmException, ParseException {
+        String endpoint = endpoint1 + "/" + endpoint2;
+        return this.getResource(endpoint);
+    }
+
+    public List<String> getResource(@Nonnull String endpoint1, @Nonnull String endpoint2, @Nonnull String endpoint3)
+            throws ClientHandlerException, UniformInterfaceException, JsonParseException, JsonMappingException,
+            IOException, KeyManagementException, NoSuchAlgorithmException, ParseException {
+        String endpoint = endpoint1 + "/" + endpoint2 + "/" + endpoint3;
+        return this.getResource(endpoint);
+    }
+
+    public ValidationNexusTestResult getResult(@Nonnull String name, @Nonnull String version, @Nonnull String siloText,
+            @Nonnull String timestamp)
+                    throws ClientHandlerException, UniformInterfaceException, JsonParseException, JsonMappingException,
+                    IOException, KeyManagementException, NoSuchAlgorithmException, ParseException, NullPointerException {
+        String nexusUrl = this.baseurl + "/" + siloText + "/" + name + "/" + version;
+        LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying to get validation nexus test result");
+        WebResource webResource = this.client.resource(nexusUrl + "/");
+        LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of get: " + webResource.getURI().toString());
+        ClientResponse response = webResource.get(ClientResponse.class);
+        if (response.getStatus() != 200) {
+            throw new HttpException("Could not retrieve validation nexus test result. HTTP error code : "
+                    + response.getStatus() + " and message: " + response.getEntity(String.class));
+        }
+        Document document = Jsoup.parse(response.getEntity(String.class));
+        List<Element> elements = document.getElementsByTag("body").get(0).getElementsByTag("table").get(0)
+                .getElementsByTag("tbody").get(0).getElementsByTag("tr");
+        Element element = findElementByTimestamp(elements.subList(2, elements.size()), timestamp);
+        if (element == null) {
+            return null;
+        }
+        ValidationNexusTestResult vNexusResult = new ValidationNexusTestResult();
+        vNexusResult.setBlueprintName(name);
+        vNexusResult.setSilo(siloText);
+        vNexusResult.setVersion(version);
+        vNexusResult.setTimestamp(timestamp);
+        String lastModified = element.getElementsByTag("td").get(1).text();
+        vNexusResult.setDateOfStorage(lastModified);
+        TestInfoYaml testInfo = getTestInfo(webResource.getURI().toString() + timestamp);
+        if (testInfo != null) {
+            if (testInfo.gettest_info().getLayer().equals("all")) {
+                vNexusResult.setAllLayers(true);
+            } else {
+                vNexusResult.setAllLayers(false);
             }
-        };
-        // Create a trust manager that does not validate certificate chains
-        trustAll = new TrustManager[] {new X509TrustManager() {
-            @Override
-            public X509Certificate[] getAcceptedIssuers() {
-                return null; // Not relevant.
+            vNexusResult.setOptional(testInfo.gettest_info().getOptional());
+        }
+        List<WRobotNexusTestResult> wTestResults = getWRobotTestResults(name, version, siloText, timestamp);
+        vNexusResult.setwRobotNexusTestResults(wTestResults);
+        vNexusResult.setResult(determineResult(wTestResults));
+        return vNexusResult;
+    }
+
+    public List<ValidationNexusTestResult> getResults(@Nonnull String name, @Nonnull String version,
+            @Nonnull String siloText, int noOfLastElements)
+                    throws ClientHandlerException, UniformInterfaceException, JsonParseException, JsonMappingException,
+                    IOException, KeyManagementException, NoSuchAlgorithmException, ParseException {
+        String nexusUrl = this.baseurl + "/" + siloText + "/" + name + "/" + version;
+        LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying to get validation Nexus test results");
+        WebResource webResource = this.client.resource(nexusUrl + "/");
+        LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of get: " + webResource.getURI().toString());
+        ClientResponse response = webResource.get(ClientResponse.class);
+        if (response.getStatus() != 200) {
+            throw new HttpException("Could not retrieve validation Nexus test results. HTTP error code : "
+                    + response.getStatus() + " and message: " + response.getEntity(String.class));
+        }
+        List<ValidationNexusTestResult> vNexusResults = new ArrayList<ValidationNexusTestResult>();
+        Document document = Jsoup.parse(response.getEntity(String.class));
+        List<Element> elements = document.getElementsByTag("body").get(0).getElementsByTag("table").get(0)
+                .getElementsByTag("tbody").get(0).getElementsByTag("tr");
+        elements = findLastElementsByDate(elements.subList(2, elements.size()), noOfLastElements);
+        for (int i = 0; i < elements.size(); i++) {
+            try {
+                String timestamp = elements.get(i).getElementsByTag("td").get(0).getElementsByTag("a").get(0).text();
+                timestamp = timestamp.substring(0, timestamp.length() - 1);
+                ValidationNexusTestResult vNexusResult = this.getResult(name, version, siloText, timestamp);
+                vNexusResults.add(vNexusResult);
+            } catch (HttpException ex) {
+                LOGGER.warn(EELFLoggerDelegate.auditLogger, "Exception occured while retrieving timestamp results");
+                continue;
             }
+        }
+        return vNexusResults;
+    }
 
-            @Override
-            public void checkClientTrusted(X509Certificate[] certs, String authType) {
-                // Do nothing. Just allow them all.
+    public List<ValidationNexusTestResult> getResults(@Nonnull String name, @Nonnull String version,
+            @Nonnull String siloText, @Nonnull Date date)
+                    throws ClientHandlerException, UniformInterfaceException, JsonParseException, JsonMappingException,
+                    IOException, KeyManagementException, NoSuchAlgorithmException, ParseException, NullPointerException {
+        String nexusUrl = this.baseurl + "/" + siloText + "/" + name + "/" + version;
+        LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying to get validation Nexus results based on date");
+        WebResource webResource = this.client.resource(nexusUrl + "/");
+        LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of get: " + webResource.getURI().toString());
+        ClientResponse response = webResource.get(ClientResponse.class);
+        if (response.getStatus() != 200) {
+            throw new HttpException("Could not retrieve validation Nexus results based on date. HTTP error code : "
+                    + response.getStatus() + " and message: " + response.getEntity(String.class));
+        }
+        List<ValidationNexusTestResult> vNexusResults = new ArrayList<ValidationNexusTestResult>();
+        Document document = Jsoup.parse(response.getEntity(String.class));
+        List<Element> elements = document.getElementsByTag("body").get(0).getElementsByTag("table").get(0)
+                .getElementsByTag("tbody").get(0).getElementsByTag("tr");
+        elements = findElementsBasedOnDate(elements.subList(2, elements.size()), date);
+        for (int i = 0; i < elements.size(); i++) {
+            try {
+                String timestamp = elements.get(i).getElementsByTag("td").get(0).getElementsByTag("a").get(0).text();
+                timestamp = timestamp.substring(0, timestamp.length() - 1);
+                ValidationNexusTestResult vNexusResult = this.getResult(name, version, siloText, timestamp);
+                vNexusResults.add(vNexusResult);
+            } catch (HttpException ex) {
+                LOGGER.warn(EELFLoggerDelegate.auditLogger, "Exception occured while retrieving timestamp results");
+                continue;
             }
+        }
+        return vNexusResults;
+    }
 
+    public ValidationNexusTestResult getLastResultBasedOnOutcome(@Nonnull String name, @Nonnull String version,
+            @Nonnull String siloText, List<BlueprintLayer> layers, Boolean optional, boolean outcome)
+                    throws ClientHandlerException, UniformInterfaceException, JsonParseException, JsonMappingException,
+                    IOException, KeyManagementException, NoSuchAlgorithmException, ParseException, NullPointerException {
+        String nexusUrl = this.baseurl + "/" + siloText + "/" + name + "/" + version;
+        LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying to get last result based on outcome");
+        WebResource webResource = this.client.resource(nexusUrl + "/");
+        LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of get: " + webResource.getURI().toString());
+        ClientResponse response = webResource.get(ClientResponse.class);
+        if (response.getStatus() != 200) {
+            throw new HttpException("Could not retrieve last result based on outcome from Nexus. HTTP error code : "
+                    + response.getStatus() + " and message: " + response.getEntity(String.class));
+        }
+        Document document = Jsoup.parse(response.getEntity(String.class));
+        List<Element> elements = document.getElementsByTag("body").get(0).getElementsByTag("table").get(0)
+                .getElementsByTag("tbody").get(0).getElementsByTag("tr");
+        elements = elements.subList(2, elements.size());
+        if (elements.size() < 1) {
+            return null;
+        }
+        DateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
+        Collections.sort(elements, new Comparator<Element>() {
             @Override
-            public void checkServerTrusted(X509Certificate[] certs, String authType) {
-                // Do nothing. Just allow them all.
+            public int compare(Element element1, Element element2) {
+                try {
+                    return dateFormat.parse(element2.getElementsByTag("td").get(1).text())
+                            .compareTo(dateFormat.parse(element1.getElementsByTag("td").get(1).text()));
+                } catch (ParseException e) {
+                    LOGGER.error(EELFLoggerDelegate.errorLogger,
+                            "Error when parsing date. " + UserUtils.getStackTrace(e));
+                    return 0;
+                }
+            }
+        });
+        for (Element element : elements) {
+            try {
+                String elementTimestamp = element.getElementsByTag("td").get(0).getElementsByTag("a").get(0).text();
+                elementTimestamp = elementTimestamp.substring(0, elementTimestamp.length() - 1);
+                ValidationNexusTestResult vNexusResult = this.getResult(name, version, siloText, elementTimestamp);
+                if (vNexusResult.getResult() != outcome) {
+                    continue;
+                }
+                if (optional != null && vNexusResult.getOptional() != optional) {
+                    continue;
+                }
+                if (layers != null) {
+                    List<BlueprintLayer> storedLayers = new ArrayList<BlueprintLayer>();
+                    for (WRobotNexusTestResult wRobot : vNexusResult.getwRobotNexusTestResults()) {
+                        storedLayers.add(wRobot.getBlueprintLayer());
+                    }
+                    if (!new HashSet<>(storedLayers).equals(new HashSet<>(layers))) {
+                        continue;
+                    }
+                }
+                return vNexusResult;
+            } catch (HttpException ex) {
+                LOGGER.warn(EELFLoggerDelegate.auditLogger,
+                        "Error when trying to retrieve results. " + UserUtils.getStackTrace(ex));
+                continue;
             }
-        }};
+        }
+        return null;
     }
 
-    public String getBaseUrl() {
-        return this.baseurl;
+    public ValidationNexusTestResult getLastResultBasedOnOutcome(@Nonnull String name, @Nonnull String version,
+            @Nonnull String siloText, Boolean allLayers, Boolean optional, boolean outcome)
+                    throws ClientHandlerException, UniformInterfaceException, JsonParseException, JsonMappingException,
+                    IOException, KeyManagementException, NoSuchAlgorithmException, ParseException, NullPointerException {
+        String nexusUrl = this.baseurl + "/" + siloText + "/" + name + "/" + version;
+        LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying to get last result based on outcome");
+        WebResource webResource = this.client.resource(nexusUrl + "/");
+        LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of get: " + webResource.getURI().toString());
+        ClientResponse response = webResource.get(ClientResponse.class);
+        if (response.getStatus() != 200) {
+            throw new HttpException("Could not retrieve last result based on outcome from Nexus. HTTP error code : "
+                    + response.getStatus() + " and message: " + response.getEntity(String.class));
+        }
+        Document document = Jsoup.parse(response.getEntity(String.class));
+        List<Element> elements = document.getElementsByTag("body").get(0).getElementsByTag("table").get(0)
+                .getElementsByTag("tbody").get(0).getElementsByTag("tr");
+        elements = elements.subList(2, elements.size());
+        if (elements.size() < 1) {
+            return null;
+        }
+        DateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
+        Collections.sort(elements, new Comparator<Element>() {
+            @Override
+            public int compare(Element element1, Element element2) {
+                try {
+                    return dateFormat.parse(element2.getElementsByTag("td").get(1).text())
+                            .compareTo(dateFormat.parse(element1.getElementsByTag("td").get(1).text()));
+                } catch (ParseException e) {
+                    LOGGER.error(EELFLoggerDelegate.errorLogger,
+                            "Error when parsing date. " + UserUtils.getStackTrace(e));
+                    return 0;
+                }
+            }
+        });
+        for (Element element : elements) {
+            try {
+                String elementTimestamp = element.getElementsByTag("td").get(0).getElementsByTag("a").get(0).text();
+                elementTimestamp = elementTimestamp.substring(0, elementTimestamp.length() - 1);
+                ValidationNexusTestResult vNexusResult = this.getResult(name, version, siloText, elementTimestamp);
+                if (vNexusResult.getResult() != outcome) {
+                    continue;
+                }
+                if (optional != null && vNexusResult.getOptional() != optional) {
+                    continue;
+                }
+                if (allLayers != null && vNexusResult.getAllLayers() != allLayers) {
+                    continue;
+                }
+                return vNexusResult;
+            } catch (HttpException ex) {
+                LOGGER.warn(EELFLoggerDelegate.auditLogger,
+                        "Error when trying to retrieve results. " + UserUtils.getStackTrace(ex));
+                continue;
+            }
+        }
+        return null;
     }
 
-    public List<WrapperRobotTestResult> getRobotTestResults() throws ClientHandlerException, UniformInterfaceException,
-            JsonParseException, JsonMappingException, IOException, KeyManagementException, NoSuchAlgorithmException {
-        List<WrapperRobotTestResult> listOfwrappers = new ArrayList<WrapperRobotTestResult>();
+    public List<WRobotNexusTestResult> getWRobotTestResults(@Nonnull String name, @Nonnull String version,
+            @Nonnull String siloText, @Nonnull String timestamp)
+                    throws ClientHandlerException, UniformInterfaceException, JsonParseException, JsonMappingException,
+                    IOException, KeyManagementException, NoSuchAlgorithmException {
+        String nexusUrl = this.baseurl + "/" + siloText + "/" + name + "/" + version + "/" + timestamp + "/results";
+        List<WRobotNexusTestResult> listOfwrappers = new ArrayList<WRobotNexusTestResult>();
         LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying to get the blueprint layers");
-        setProperties();
-        WebResource webResource = this.client.resource(this.baseurl + "/");
+        WebResource webResource = this.client.resource(nexusUrl + "/");
         LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of get: " + webResource.getURI().toString());
         ClientResponse response = webResource.get(ClientResponse.class);
         if (response.getStatus() != 200) {
@@ -135,31 +388,38 @@ public final class NexusExecutorClient {
                     + response.getStatus() + " and message: " + response.getEntity(String.class));
         }
         Document document = Jsoup.parse(response.getEntity(String.class));
-        List<Element> elements =
-                document.getElementsByTag("body").get(0).getElementsByTag("table").get(0).getElementsByTag("tr");
+        List<Element> elements = document.getElementsByTag("body").get(0).getElementsByTag("table").get(0)
+                .getElementsByTag("tr");
         for (int i = 2; i < elements.size(); i++) {
-            String layer = elements.get(i).getElementsByTag("td").get(0).getElementsByTag("a").get(0).text();
-            layer = layer.substring(0, layer.length() - 1);
-            List<RobotTestResult> robotTestResults = getResultsOfALayer(this.baseurl + "/" + layer);
-            WrapperRobotTestResult wrapper = new WrapperRobotTestResult();
-            wrapper.setBlueprintLayer(BlueprintLayer.valueOf(layer.substring(0, 1).toUpperCase() + layer.substring(1)));
-            wrapper.setRobotTestResults(robotTestResults);
-            listOfwrappers.add(wrapper);
+            try {
+                String layer = elements.get(i).getElementsByTag("td").get(0).getElementsByTag("a").get(0).text();
+                layer = layer.substring(0, layer.length() - 1);
+                if (layer.contains("test")) {
+                    continue;
+                }
+                List<RobotTestResult> robotTestResults = getRobotTestResults(nexusUrl + "/" + layer);
+                WRobotNexusTestResult wrapper = new WRobotNexusTestResult();
+                wrapper.setBlueprintLayer(BlueprintLayer.valueOf(layer));
+                wrapper.setRobotTestResults(robotTestResults);
+                listOfwrappers.add(wrapper);
+            } catch (HttpException | IllegalArgumentException ex) {
+                LOGGER.warn(EELFLoggerDelegate.auditLogger, "Exception occured while retrieving robot results");
+                continue;
+            }
         }
         return listOfwrappers;
     }
 
-    private List<RobotTestResult> getResultsOfALayer(String resultsUrl)
+    private List<RobotTestResult> getRobotTestResults(String resultsUrl)
             throws ClientHandlerException, UniformInterfaceException, JsonParseException, JsonMappingException,
             IOException, KeyManagementException, NoSuchAlgorithmException {
-        List<RobotTestResult> robotTestResults = new ArrayList<RobotTestResult>();
-        LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying to get Robot Test Results");
-        setProperties();
+        List<RobotTestResult> rTestResults = new ArrayList<RobotTestResult>();
+        LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying to get test suites results");
         WebResource webResource = this.client.resource(resultsUrl + "/");
         LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of get: " + webResource.getURI().toString());
         ClientResponse response = webResource.get(ClientResponse.class);
         if (response.getStatus() != 200) {
-            throw new HttpException("Could not retrieve robot test results from Nexus. HTTP error code : "
+            throw new HttpException("Could not retrieve test suites results from Nexus. HTTP error code : "
                     + response.getStatus() + " and message: " + response.getEntity(String.class));
         }
         Document document = Jsoup.parse(response.getEntity(String.class));
@@ -172,7 +432,7 @@ public final class NexusExecutorClient {
             LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of get: " + webResource.getURI().toString());
             response = webResource.get(ClientResponse.class);
             if (response.getStatus() != 200) {
-                throw new HttpException("Could not retrieve robot test result from Nexus. HTTP error code : "
+                throw new HttpException("Could not retrieve test suite result from Nexus. HTTP error code : "
                         + response.getStatus() + " and message: " + response.getEntity(String.class));
             }
             String result = response.getEntity(String.class);
@@ -183,21 +443,86 @@ public final class NexusExecutorClient {
             mapper.setSerializationInclusion(Include.NON_NULL);
             RobotTestResult robotTestResult = mapper.readValue(xmlJSONObj.toString(), RobotTestResult.class);
             robotTestResult.setName(testSuiteName);
-            robotTestResults.add(robotTestResult);
+            rTestResults.add(robotTestResult);
+        }
+        return rTestResults;
+    }
+
+    private boolean determineResult(List<WRobotNexusTestResult> wTestResults) {
+        boolean result = true;
+        for (WRobotNexusTestResult wTestResult : wTestResults) {
+            for (RobotTestResult robotTestResult : wTestResult.getRobotTestResults()) {
+                for (Status status : robotTestResult.getRobot().getStatistics().getTotal().getStat()) {
+                    if (status.getContent().trim().equals("All Tests") && status.getFail() > 0) {
+                        result = false;
+                    }
+                }
+            }
+        }
+        return result;
+    }
+
+    private List<Element> findLastElementsByDate(List<Element> elements, int noOfLastElements) {
+        if (elements.size() <= noOfLastElements) {
+            return elements;
         }
-        return robotTestResults;
+        DateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
+        Collections.sort(elements, new Comparator<Element>() {
+            @Override
+            public int compare(Element element1, Element element2) {
+                try {
+                    return dateFormat.parse(element2.getElementsByTag("td").get(1).text())
+                            .compareTo(dateFormat.parse(element1.getElementsByTag("td").get(1).text()));
+                } catch (ParseException e) {
+                    LOGGER.error(EELFLoggerDelegate.errorLogger,
+                            "Error when parsing date. " + UserUtils.getStackTrace(e));
+                    return 0;
+                }
+            }
+        });
+        return elements.subList(0, noOfLastElements);
     }
 
-    private void setProperties() throws NoSuchAlgorithmException, KeyManagementException {
-        SSLContext sslContext = SSLContext.getInstance("SSL");
-        sslContext.init(null, this.trustAll, new java.security.SecureRandom());
-        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
-        // Install the all-trusting host verifier
-        HttpsURLConnection.setDefaultHostnameVerifier(this.hostnameVerifier);
-        DefaultClientConfig config = new DefaultClientConfig();
-        Map<String, Object> properties = config.getProperties();
-        HTTPSProperties httpsProperties = new HTTPSProperties((str, sslSession) -> true, sslContext);
-        properties.put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, httpsProperties);
+    private Element findElementByTimestamp(List<Element> elements, String timestamp) {
+        for (Element element : elements) {
+            String elementTimestamp = element.getElementsByTag("td").get(0).getElementsByTag("a").get(0).text();
+            elementTimestamp = elementTimestamp.substring(0, elementTimestamp.length() - 1);
+            if (elementTimestamp.equals(timestamp)) {
+                return element;
+            }
+        }
+        return null;
     }
 
+    private List<Element> findElementsBasedOnDate(List<Element> elements, Date date) throws ParseException {
+        DateFormat formatTime = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
+        DateFormat formatNoTime = new SimpleDateFormat("EEE MMM dd zzz yyyy", Locale.US);
+        List<Element> desiredElements = new ArrayList<Element>();
+        for (Element element : elements) {
+            String lastModified = element.getElementsByTag("td").get(1).text();
+            if (formatNoTime.format(formatTime.parse(lastModified)).compareTo(formatNoTime.format(date)) == 0) {
+                desiredElements.add(element);
+            }
+        }
+        return desiredElements;
+    }
+
+    private TestInfoYaml getTestInfo(String timestampUrl) throws JsonParseException, JsonMappingException, IOException {
+        LOGGER.info(EELFLoggerDelegate.applicationLogger, "Trying to get test info");
+        WebResource webResource = this.client.resource(timestampUrl + "/results/test_info.yaml");
+        LOGGER.debug(EELFLoggerDelegate.debugLogger, "Request URI of get: " + webResource.getURI().toString());
+        ClientResponse response = webResource.get(ClientResponse.class);
+        if (response.getStatus() != 200) {
+            return null;
+        }
+        String testInfo = response.getEntity(String.class);
+        ObjectMapper yamlReader = new ObjectMapper(new YAMLFactory());
+        Object obj = yamlReader.readValue(testInfo, Object.class);
+        ObjectMapper mapper = new ObjectMapper();
+        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+        mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
+        mapper.setSerializationInclusion(Include.NON_NULL);
+        ObjectMapper jsonWriter = new ObjectMapper();
+        return mapper.readValue(jsonWriter.writeValueAsString(obj), TestInfoYaml.class);
+    }
 }
diff --git a/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/TestInfoYaml.java b/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/TestInfoYaml.java
new file mode 100644 (file)
index 0000000..94500ef
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.akraino.validation.ui.client.nexus.resources;
+
+import org.codehaus.jackson.annotate.JsonIgnoreProperties;
+import org.codehaus.jackson.annotate.JsonProperty;
+import org.codehaus.jackson.map.annotate.JsonSerialize;
+
+@JsonIgnoreProperties(ignoreUnknown = true)
+@JsonSerialize(include = JsonSerialize.Inclusion.NON_NULL)
+public class TestInfoYaml {
+
+    @JsonProperty("test_info")
+    private test_info test_info;
+
+    public TestInfoYaml() {
+
+    }
+
+    public test_info gettest_info() {
+        return this.test_info;
+    }
+
+    public void settest_info(test_info test_info) {
+        this.test_info = test_info;
+    }
+
+    public class test_info {
+
+        @JsonProperty("layer")
+        private String layer;
+
+        @JsonProperty("optional")
+        private Boolean optional;
+
+        public test_info() {
+
+        }
+
+        public String getLayer() {
+            return this.layer;
+        }
+
+        public void setLayer(String layer) {
+            this.layer = layer;
+        }
+
+        public Boolean getOptional() {
+            return this.optional;
+        }
+
+        public void setOptional(Boolean optional) {
+            this.optional = optional;
+        }
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/ValidationNexusTestResult.java b/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/ValidationNexusTestResult.java
new file mode 100644 (file)
index 0000000..59a3592
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.akraino.validation.ui.client.nexus.resources;
+
+import java.util.List;
+
+public class ValidationNexusTestResult {
+
+    private int resultId;
+
+    private String blueprintName;
+
+    private String version;
+
+    private String silo;
+
+    private Boolean allLayers;
+
+    private Boolean optional;
+
+    private boolean result;
+
+    private String dateOfStorage;
+
+    private String timestamp;
+
+    private String submissionId;
+
+    private List<WRobotNexusTestResult> wRobotNexusTestResults;
+
+    public ValidationNexusTestResult() {
+
+    }
+
+    public Integer getResultId() {
+        return this.resultId;
+    }
+
+    public void setResultId(Integer resultId) {
+        this.resultId = resultId;
+    }
+
+    public String getBlueprintName() {
+        return this.blueprintName;
+    }
+
+    public void setBlueprintName(String blueprintName) {
+        this.blueprintName = blueprintName;
+    }
+
+    public String getVersion() {
+        return this.version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getSilo() {
+        return this.silo;
+    }
+
+    public void setSilo(String silo) {
+        this.silo = silo;
+    }
+
+    public Boolean getAllLayers() {
+        return this.allLayers;
+    }
+
+    public void setAllLayers(Boolean allLayers) {
+        this.allLayers = allLayers;
+    }
+
+    public Boolean getOptional() {
+        return this.optional;
+    }
+
+    public void setOptional(Boolean optional) {
+        this.optional = optional;
+    }
+
+    public boolean getResult() {
+        return this.result;
+    }
+
+    public void setResult(boolean result) {
+        this.result = result;
+    }
+
+    public String getDateOfStorage() {
+        return this.dateOfStorage;
+    }
+
+    public void setDateOfStorage(String dateOfStorage) {
+        this.dateOfStorage = dateOfStorage;
+    }
+
+    public String getTimestamp() {
+        return this.timestamp;
+    }
+
+    public void setTimestamp(String timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public String getSubmissionId() {
+        return this.submissionId;
+    }
+
+    public void setSubmissionId(String submissionId) {
+        this.submissionId = submissionId;
+    }
+
+    public List<WRobotNexusTestResult> getwRobotNexusTestResults() {
+        return this.wRobotNexusTestResults;
+    }
+
+    public void setwRobotNexusTestResults(List<WRobotNexusTestResult> wRobotNexusTestResults) {
+        this.wRobotNexusTestResults = wRobotNexusTestResults;
+    }
+
+}
@@ -19,30 +19,30 @@ import java.util.List;
 
 import org.akraino.validation.ui.data.BlueprintLayer;
 
-public class WrapperRobotTestResult {
+public class WRobotNexusTestResult {
 
-    private BlueprintLayer layer;
+    private BlueprintLayer blueprintLayer;
 
-    private List<RobotTestResult> testResults;
+    private List<RobotTestResult> robotTestResult;
 
-    public WrapperRobotTestResult() {
+    public WRobotNexusTestResult() {
 
     }
 
     public BlueprintLayer getBlueprintLayer() {
-        return this.layer;
+        return this.blueprintLayer;
     }
 
-    public void setBlueprintLayer(BlueprintLayer layer) {
-        this.layer = layer;
+    public void setBlueprintLayer(BlueprintLayer blueprintLayer) {
+        this.blueprintLayer = blueprintLayer;
     }
 
     public List<RobotTestResult> getRobotTestResults() {
-        return this.testResults;
+        return this.robotTestResult;
     }
 
-    public void setRobotTestResults(List<RobotTestResult> testResults) {
-        this.testResults = testResults;
+    public void setRobotTestResults(List<RobotTestResult> robotTestResult) {
+        this.robotTestResult = robotTestResult;
     }
 
 }
@@ -22,23 +22,30 @@ import java.util.concurrent.PriorityBlockingQueue;
 import java.util.concurrent.ThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
-public class UiUtils {
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class ExecutorServiceInitializer {
 
     private static final int QUEUE_CAPACITY = 500;
-    private static final int EXECUTOR_SIZE = 20; // the number of threads to keep in the pool, even if
+    private static final int EXECUTOR_SIZE = 30; // the number of threads to keep in the pool, even if
     // they are idle, unless allowCoreThreadTimeOut is
     // set
-    private static final int EXECUTOR_MAX_SIZE = 20; // the maximum number of threads to allow in the pool
-    private static final int KEEPALIVE_TIME = 20; // when the number of threads is greater than the
+    private static final int EXECUTOR_MAX_SIZE = 30; // the maximum number of threads to allow in the pool
+    private static final int KEEPALIVE_TIME = 30; // when the number of threads is greater than the
     // core, this is the maximum time that excess idle
     // threads will wait for new tasks before
     // terminating.
-    private static final PriorityBlockingQueue<Runnable> BLOCKING_QUEUE =
-            new PriorityBlockingQueue<Runnable>(QUEUE_CAPACITY, new CFRunnableComparator());
-    public static ExecutorService executorService =
-            new ThreadPoolExecutor(EXECUTOR_SIZE, EXECUTOR_MAX_SIZE, KEEPALIVE_TIME, TimeUnit.SECONDS, BLOCKING_QUEUE);
+    private static final PriorityBlockingQueue<Runnable> BLOCKING_QUEUE = new PriorityBlockingQueue<Runnable>(
+            QUEUE_CAPACITY, new CFRunnableComparator());
+    private static ExecutorService executorService = new ThreadPoolExecutor(EXECUTOR_SIZE, EXECUTOR_MAX_SIZE,
+            KEEPALIVE_TIME, TimeUnit.SECONDS, BLOCKING_QUEUE);
 
-    public static final String NEXUS_URL = "https://nexus.akraino.org/content/sites/logs";
+    @Bean(name = "executorService")
+    public ExecutorService getExecutorService() {
+        return this.executorService;
+    }
 
     private static class CFRunnableComparator implements Comparator<Runnable> {
         @Override
index bb139f6..3317260 100644 (file)
@@ -31,6 +31,7 @@ import org.onap.portalsdk.core.logging.format.AppMessagesEnum;
 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
 import org.onap.portalsdk.core.objectcache.AbstractCacheManager;
 import org.onap.portalsdk.core.onboarding.util.CipherUtil;
+import org.onap.portalsdk.core.onboarding.util.PortalApiProperties;
 import org.onap.portalsdk.core.service.DataAccessService;
 import org.onap.portalsdk.core.util.CacheManager;
 import org.onap.portalsdk.core.util.SystemProperties;
@@ -54,12 +55,12 @@ import com.mchange.v2.c3p0.ComboPooledDataSource;
 
 @Configuration
 @EnableWebMvc
-@ComponentScan(basePackages = {"org.akraino", "org.onap"})
-@PropertySource(value = {"${container.classpath:}/WEB-INF/conf/app/test.properties"}, ignoreResourceNotFound = true)
+@ComponentScan(basePackages = { "org.akraino", "org.onap" })
+@PropertySource(value = { "${container.classpath:}/WEB-INF/conf/app/test.properties" }, ignoreResourceNotFound = true)
 @Profile("src")
 @EnableAsync
 @EnableScheduling
-@Import({MusicSessionConfig.class})
+@Import({ MusicSessionConfig.class })
 public class ExternalAppConfig extends AppConfig implements Configurable {
 
     private RegistryAdapter schedulerRegistryAdapter;
@@ -112,9 +113,10 @@ public class ExternalAppConfig extends AppConfig implements Configurable {
         ComboPooledDataSource dataSource = new ComboPooledDataSource();
         try {
             dataSource.setDriverClass(SystemProperties.getProperty(SystemProperties.DB_DRIVER));
-            dataSource.setJdbcUrl("jdbc:mariadb://" + System.getenv("DB_CONNECTION_URL"));
+            dataSource.setJdbcUrl("jdbc:mariadb://" + System.getenv("DB_IP_PORT") + "/"
+                    + PortalApiProperties.getProperty("akraino_database_name"));
             dataSource.setUser(SystemProperties.getProperty(SystemProperties.DB_USERNAME));
-            String password = System.getenv("MARIADB_ROOT_PASSWORD");
+            String password = System.getenv("MARIADB_AKRAINO_PASSWORD");
             if (SystemProperties.containsProperty(SystemProperties.DB_ENCRYPT_FLAG)) {
                 String encryptFlag = SystemProperties.getProperty(SystemProperties.DB_ENCRYPT_FLAG);
                 if (encryptFlag != null && encryptFlag.equalsIgnoreCase("true")) {
@@ -123,9 +125,9 @@ public class ExternalAppConfig extends AppConfig implements Configurable {
             }
             dataSource.setPassword(password);
             dataSource
-                    .setMinPoolSize(Integer.parseInt(SystemProperties.getProperty(SystemProperties.DB_MIN_POOL_SIZE)));
+            .setMinPoolSize(Integer.parseInt(SystemProperties.getProperty(SystemProperties.DB_MIN_POOL_SIZE)));
             dataSource
-                    .setMaxPoolSize(Integer.parseInt(SystemProperties.getProperty(SystemProperties.DB_MAX_POOL_SIZE)));
+            .setMaxPoolSize(Integer.parseInt(SystemProperties.getProperty(SystemProperties.DB_MAX_POOL_SIZE)));
             dataSource.setIdleConnectionTestPeriod(
                     Integer.parseInt(SystemProperties.getProperty(SystemProperties.IDLE_CONNECTION_TEST_PERIOD)));
             dataSource.setTestConnectionOnCheckout(getConnectionOnCheckout());
@@ -134,11 +136,11 @@ public class ExternalAppConfig extends AppConfig implements Configurable {
             LOGGER.error(EELFLoggerDelegate.errorLogger,
                     "Error initializing database, verify database settings in properties file: "
                             + UserUtils.getStackTrace(e),
-                    AlarmSeverityEnum.CRITICAL);
+                            AlarmSeverityEnum.CRITICAL);
             LOGGER.error(EELFLoggerDelegate.debugLogger,
                     "Error initializing database, verify database settings in properties file: "
                             + UserUtils.getStackTrace(e),
-                    AlarmSeverityEnum.CRITICAL);
+                            AlarmSeverityEnum.CRITICAL);
             // Raise an alarm that opening a connection to the database failed.
             LOGGER.logEcompError(AppMessagesEnum.BeDaoSystemError);
             throw e;
@@ -161,13 +163,13 @@ public class ExternalAppConfig extends AppConfig implements Configurable {
 
     /**
      * Adds request interceptors to the specified registry by calling
-     * {@link AppConfig#addInterceptors(InterceptorRegistry)}, but excludes
-     * certain paths from the session timeout interceptor.
+     * {@link AppConfig#addInterceptors(InterceptorRegistry)}, but excludes certain
+     * paths from the session timeout interceptor.
      */
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
         super.setExcludeUrlPathsForSessionTimeout("/login_external", "*/login_external.htm", "login", "/login.htm",
-                "/api*", "/single_signon.htm", "/single_signon");
+                "/api*", "/single_signon.htm", "/single_signon", "logout", "/logout.htm");
         super.addInterceptors(registry);
     }
 
@@ -182,8 +184,8 @@ public class ExternalAppConfig extends AppConfig implements Configurable {
     }
 
     /**
-     * Creates and returns a new instance of a {@link SchedulerFactoryBean}
-     * and populates it with triggers.
+     * Creates and returns a new instance of a {@link SchedulerFactoryBean} and
+     * populates it with triggers.
      *
      * @return New instance of {@link SchedulerFactoryBean}
      * @throws Exception
@@ -214,9 +216,8 @@ public class ExternalAppConfig extends AppConfig implements Configurable {
     }
 
     /**
-     * Gets the value of the property
-     * {@link SystemProperties#PREFERRED_TEST_QUERY}; defaults to "Select 1"
-     * if the property is not defined.
+     * Gets the value of the property {@link SystemProperties#PREFERRED_TEST_QUERY};
+     * defaults to "Select 1" if the property is not defined.
      *
      * @return String value that is a SQL query
      */
@@ -237,8 +238,8 @@ public class ExternalAppConfig extends AppConfig implements Configurable {
 
     /**
      * Gets the value of the property
-     * {@link SystemProperties#TEST_CONNECTION_ON_CHECKOUT}; defaults to true
-     * if the property is not defined.
+     * {@link SystemProperties#TEST_CONNECTION_ON_CHECKOUT}; defaults to true if the
+     * property is not defined.
      *
      * @return Boolean value
      */
@@ -246,8 +247,8 @@ public class ExternalAppConfig extends AppConfig implements Configurable {
         // Default to true, always test connection
         boolean testConnectionOnCheckout = true;
         if (SystemProperties.containsProperty(SystemProperties.TEST_CONNECTION_ON_CHECKOUT)) {
-            testConnectionOnCheckout =
-                    Boolean.valueOf(SystemProperties.getProperty(SystemProperties.TEST_CONNECTION_ON_CHECKOUT));
+            testConnectionOnCheckout = Boolean
+                    .valueOf(SystemProperties.getProperty(SystemProperties.TEST_CONNECTION_ON_CHECKOUT));
             LOGGER.debug(EELFLoggerDelegate.debugLogger, "getConnectionOnCheckout: property key {} value is {}",
                     SystemProperties.TEST_CONNECTION_ON_CHECKOUT, testConnectionOnCheckout);
         } else {
diff --git a/ui/src/main/java/org/akraino/validation/ui/conf/UiInitializer.java b/ui/src/main/java/org/akraino/validation/ui/conf/UiInitializer.java
new file mode 100644 (file)
index 0000000..febafe1
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.akraino.validation.ui.conf;
+
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.security.cert.X509Certificate;
+import java.util.Map;
+
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.context.event.EventListener;
+import org.springframework.stereotype.Component;
+
+import com.sun.jersey.api.client.config.DefaultClientConfig;
+import com.sun.jersey.client.urlconnection.HTTPSProperties;
+
+@Component
+public class UiInitializer {
+
+    // Create all-trusting host name verifier
+    private final HostnameVerifier hostnameVerifier = new HostnameVerifier() {
+        @Override
+        public boolean verify(String hostname, SSLSession session) {
+            return true;
+        }
+    };
+    // Create a trust manager that does not validate certificate chains
+    private final TrustManager[] trustAll = new TrustManager[] { new X509TrustManager() {
+        @Override
+        public X509Certificate[] getAcceptedIssuers() {
+            return null; // Not relevant.
+        }
+
+        @Override
+        public void checkClientTrusted(X509Certificate[] certs, String authType) {
+            // Do nothing. Just allow them all.
+        }
+
+        @Override
+        public void checkServerTrusted(X509Certificate[] certs, String authType) {
+            // Do nothing. Just allow them all.
+        }
+    } };
+
+    @EventListener(ContextRefreshedEvent.class)
+    public void setHttpProperties() throws NoSuchAlgorithmException, KeyManagementException {
+        SSLContext sslContext = SSLContext.getInstance("SSL");
+        sslContext.init(null, this.trustAll, new java.security.SecureRandom());
+        HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
+        // Install the all-trusting host verifier
+        HttpsURLConnection.setDefaultHostnameVerifier(this.hostnameVerifier);
+        DefaultClientConfig config = new DefaultClientConfig();
+        Map<String, Object> properties = config.getProperties();
+        HTTPSProperties httpsProperties = new HTTPSProperties((str, sslSession) -> true, sslContext);
+        properties.put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES, httpsProperties);
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/conf/ValidationNexusTestResultsGetter.java b/ui/src/main/java/org/akraino/validation/ui/conf/ValidationNexusTestResultsGetter.java
new file mode 100644 (file)
index 0000000..769549a
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.akraino.validation.ui.conf;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+
+import org.akraino.validation.ui.client.nexus.resources.ValidationNexusTestResult;
+import org.akraino.validation.ui.data.Lab;
+import org.akraino.validation.ui.service.DbResultAdapter;
+import org.akraino.validation.ui.service.IntegratedResultService;
+import org.akraino.validation.ui.service.utils.PrioritySupplier;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.portalsdk.core.onboarding.util.PortalApiProperties;
+import org.onap.portalsdk.core.web.support.UserUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ValidationNexusTestResultsGetter implements ApplicationListener<ContextRefreshedEvent> {
+
+    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate
+            .getLogger(ValidationNexusTestResultsGetter.class);
+
+    @Autowired
+    IntegratedResultService integratedService;
+
+    @Autowired
+    DbResultAdapter dbAdapter;
+
+    @Override
+    public void onApplicationEvent(final ContextRefreshedEvent event) {
+        ApplicationContext context = new AnnotationConfigApplicationContext(ExecutorServiceInitializer.class);
+        ExecutorService service = (ExecutorService) context.getBean("executorService");
+        ValidationNexusTestResultsGetterExecution task = new ValidationNexusTestResultsGetterExecution();
+        CompletableFuture<List<List<ValidationNexusTestResult>>> completableFuture = CompletableFuture
+                .supplyAsync(new PrioritySupplier<>(1, task::execute), service);
+        completableFuture.thenAcceptAsync(results -> this.callbackNotify(results));
+    }
+
+    private void callbackNotify(List<List<ValidationNexusTestResult>> results) {
+        try {
+            for (List<ValidationNexusTestResult> result : results) {
+
+                LOGGER.debug(EELFLoggerDelegate.debugLogger,
+                        "Validation test results retrieved from nexus with size : " + result.size());
+                dbAdapter.deleteUnreferencedEntries(result);
+                dbAdapter.storeResultInDb(result);
+            }
+            Thread.sleep(Integer.valueOf(PortalApiProperties.getProperty("thread_sleep")));
+        } catch (Exception e) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger,
+                    "Error in callback notification. " + UserUtils.getStackTrace(e));
+        }
+        // Trigger the next retrieval of results
+        ApplicationContext context = new AnnotationConfigApplicationContext(ExecutorServiceInitializer.class);
+        ExecutorService service = (ExecutorService) context.getBean("executorService");
+        ValidationNexusTestResultsGetterExecution task = new ValidationNexusTestResultsGetterExecution();
+        CompletableFuture<List<List<ValidationNexusTestResult>>> completableFuture = CompletableFuture
+                .supplyAsync(new PrioritySupplier<>(1, task::execute), service);
+        completableFuture.thenAcceptAsync(newResults -> this.callbackNotify(newResults));
+    }
+
+    private class ValidationNexusTestResultsGetterExecution {
+
+        public ValidationNexusTestResultsGetterExecution() {
+        }
+
+        public List<List<ValidationNexusTestResult>> execute() {
+            List<List<ValidationNexusTestResult>> results = new ArrayList<List<ValidationNexusTestResult>>();
+            try {
+                for (Lab lab : integratedService.getLabsFromNexus()) {
+                    for (String blueprintName : integratedService.getBlueprintNamesOfLabFromNexus(lab)) {
+                        for (String version : integratedService.getBlueprintVersionsFromNexus(blueprintName, lab)) {
+                            LOGGER.debug(EELFLoggerDelegate.debugLogger,
+                                    "Trying to retrieve validation test result from nexus for: blueprint name: "
+                                            + blueprintName + ", version: " + version + " and lab: " + lab.name());
+                            results.add(integratedService.getResultsFromNexus(blueprintName, version, lab,
+                                    Integer.valueOf(PortalApiProperties.getProperty("no_last_timestamps"))));
+                        }
+                    }
+                }
+            } catch (Exception e) {
+                LOGGER.error(EELFLoggerDelegate.errorLogger,
+                        "Error when retrieving Nexus results. " + UserUtils.getStackTrace(e));
+            }
+            return results;
+        }
+    }
+
+}
index fdc6449..091738a 100644 (file)
@@ -31,7 +31,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 
 @Controller
-@RequestMapping("/api/blueprint")
+@RequestMapping("/api/v1/blueprint")
 public class BlueprintController extends RestrictedBaseController {
 
     private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(BlueprintController.class);
index 749fb75..ab2afd2 100644 (file)
@@ -31,11 +31,11 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 
 @Controller
-@RequestMapping("/api/blueprintInstanceForValidation")
+@RequestMapping("/api/v1/blueprintinstanceforvalidation")
 public class BlueprintInstanceForValidationController extends RestrictedBaseController {
 
-    private static final EELFLoggerDelegate LOGGER =
-            EELFLoggerDelegate.getLogger(BlueprintInstanceForValidationController.class);
+    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate
+            .getLogger(BlueprintInstanceForValidationController.class);
 
     @Autowired
     BlueprintInstanceForValidationService service;
@@ -44,7 +44,7 @@ public class BlueprintInstanceForValidationController extends RestrictedBaseCont
         super();
     }
 
-    @RequestMapping(value = {"/"}, method = RequestMethod.GET)
+    @RequestMapping(value = { "/" }, method = RequestMethod.GET)
     public ResponseEntity<List<BlueprintInstanceForValidation>> getBlueprintInstancesForValidation() {
         try {
             return new ResponseEntity<>(service.getBlueprintInstancesForValidation(), HttpStatus.OK);
index 79bedb1..35cea69 100644 (file)
@@ -29,20 +29,20 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 
 @Controller
-@RequestMapping("/api/jenkinsJobNotification")
+@RequestMapping("/api/v1/jenkinsjobnotification")
 public class JenkinsJobNotificationController extends RestrictedBaseController {
 
     @Autowired
     JenkinsJobNotificationService service;
 
-    private static final EELFLoggerDelegate LOGGER =
-            EELFLoggerDelegate.getLogger(JenkinsJobNotificationController.class);
+    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate
+            .getLogger(JenkinsJobNotificationController.class);
 
     public JenkinsJobNotificationController() {
         super();
     }
 
-    @RequestMapping(value = {"/"}, method = RequestMethod.POST)
+    @RequestMapping(value = { "/" }, method = RequestMethod.POST)
     public ResponseEntity<Void> handle(@RequestBody JnksJobNotify jnksJobNotify) {
         try {
             service.handle(jnksJobNotify);
index 430f169..cc9cec2 100644 (file)
@@ -16,6 +16,9 @@
 
 package org.akraino.validation.ui.controller;
 
+import java.util.HashMap;
+import java.util.Map;
+
 import javax.servlet.http.HttpServletRequest;
 
 import org.onap.portalsdk.core.controller.RestrictedBaseController;
@@ -32,21 +35,52 @@ public class ModelsViewsController extends RestrictedBaseController {
         super();
     }
 
-    @RequestMapping(value = {"/newSubmission"}, method = RequestMethod.GET)
+    @RequestMapping(value = { "/newsubmission" }, method = RequestMethod.GET)
     public ModelAndView newSubmission(HttpServletRequest request) {
         final String defaultViewName = null;
         return new ModelAndView(defaultViewName);
     }
 
-    @RequestMapping(value = {"/committedSubmissions"}, method = RequestMethod.GET)
+    @RequestMapping(value = { "/committedsubmissions" }, method = RequestMethod.GET)
     public ModelAndView committedSubmissions(HttpServletRequest request) {
         final String defaultViewName = null;
         return new ModelAndView(defaultViewName);
     }
 
-    @RequestMapping(value = {"/getBySubmissionId"}, method = RequestMethod.GET)
-    public ModelAndView getBySubmissionId(HttpServletRequest request) {
+    @RequestMapping(value = { "/getmostrecent" }, method = RequestMethod.GET)
+    public ModelAndView getMostrecent(HttpServletRequest request) {
+        final String defaultViewName = null;
+        return new ModelAndView(defaultViewName);
+    }
+
+    @RequestMapping(value = { "/getbytimestamp" }, method = RequestMethod.GET)
+    public ModelAndView getByTimestamp(HttpServletRequest request) {
+        final String defaultViewName = null;
+        return new ModelAndView(defaultViewName);
+    }
+
+    @RequestMapping(value = { "/getlastrun" }, method = RequestMethod.GET)
+    public ModelAndView getLastRun(HttpServletRequest request) {
+        final String defaultViewName = null;
+        return new ModelAndView(defaultViewName);
+    }
+
+    @RequestMapping(value = { "/getbasedondate" }, method = RequestMethod.GET)
+    public ModelAndView getBasedOnDate(HttpServletRequest request) {
+        final String defaultViewName = null;
+        return new ModelAndView(defaultViewName);
+    }
+
+    @RequestMapping(value = { "/validationresults" }, method = RequestMethod.GET)
+    public ModelAndView validationResults(HttpServletRequest request) {
         final String defaultViewName = null;
         return new ModelAndView(defaultViewName);
     }
+
+    @RequestMapping(value = { "/logout.htm" }, method = RequestMethod.GET)
+    public ModelAndView login() {
+        Map<String, Object> model = new HashMap<>();
+        return new ModelAndView("logout", "model", model);
+    }
+
 }
diff --git a/ui/src/main/java/org/akraino/validation/ui/controller/ResultController.java b/ui/src/main/java/org/akraino/validation/ui/controller/ResultController.java
new file mode 100644 (file)
index 0000000..f9c205a
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.akraino.validation.ui.controller;
+
+import java.text.DateFormat;
+import java.text.SimpleDateFormat;
+import java.util.List;
+import java.util.Set;
+
+import org.akraino.validation.ui.client.nexus.resources.ValidationNexusTestResult;
+import org.akraino.validation.ui.data.BlueprintLayer;
+import org.akraino.validation.ui.data.Lab;
+import org.akraino.validation.ui.service.DbResultAdapter;
+import org.akraino.validation.ui.service.IntegratedResultService;
+import org.onap.portalsdk.core.controller.RestrictedBaseController;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.portalsdk.core.web.support.UserUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestMethod;
+
+@Controller
+@RequestMapping("/api/v1/results")
+public class ResultController extends RestrictedBaseController {
+
+    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(ResultController.class);
+
+    @Autowired
+    IntegratedResultService resultService;
+
+    @Autowired
+    DbResultAdapter dbAdapter;
+
+    public ResultController() {
+        super();
+    }
+
+    @RequestMapping(value = { "/getlabs/" }, method = RequestMethod.GET)
+    public ResponseEntity<Set<Lab>> getLabs() {
+        try {
+            return new ResponseEntity<>(resultService.getLabsFromDb(), HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger, "Error when retrieving labs. " + UserUtils.getStackTrace(e));
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+    @RequestMapping(value = { "/getblueprintnamesoflab/{lab}" }, method = RequestMethod.GET)
+    public ResponseEntity<Set<String>> getBlueprintNamesOfLab(@PathVariable("lab") Lab lab) {
+        try {
+            return new ResponseEntity<>(resultService.getBlueprintNamesOfLabFromDb(lab), HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger,
+                    "Error when retrieving blueprint names of a lab. " + UserUtils.getStackTrace(e));
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+    @RequestMapping(value = { "/getblueprintversions/{name}/{lab}" }, method = RequestMethod.GET)
+    public ResponseEntity<Set<String>> getBlueprintVersions(@PathVariable("name") String name,
+            @PathVariable("lab") Lab lab) {
+        try {
+            return new ResponseEntity<>(resultService.getBlueprintVersionsFromDb(name, lab), HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger,
+                    "Error when retrieving blueprint versions. " + UserUtils.getStackTrace(e));
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+    @RequestMapping(value = { "/getbysubmissionid/{id}" }, method = RequestMethod.GET)
+    public ResponseEntity<ValidationNexusTestResult> getBySubmissionId(@PathVariable("id") String submissionId) {
+        try {
+            return new ResponseEntity<>(resultService.getResults(submissionId), HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger,
+                    "Error when retrieving results using submission id. " + UserUtils.getStackTrace(e));
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+    @RequestMapping(value = { "/getmostrecent/{name}/{version}/{lab}" }, method = RequestMethod.GET)
+    public ResponseEntity<List<ValidationNexusTestResult>> getMostRecent(@PathVariable("name") String name,
+            @PathVariable("version") String version, @PathVariable("lab") Lab lab) {
+        try {
+            return new ResponseEntity<>(dbAdapter.readResultFromDb(name, version, lab, null, null, null, null),
+                    HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger,
+                    "Error when retrieving most recent results. " + UserUtils.getStackTrace(e));
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+    @RequestMapping(value = { "/getbytimestamp/{lab}/{name}/{version}/{timestamp}" }, method = RequestMethod.GET)
+    public ResponseEntity<ValidationNexusTestResult> getByTimestamp(@PathVariable("lab") Lab lab,
+            @PathVariable("name") String name, @PathVariable("version") String version,
+            @PathVariable("timestamp") String timestamp) {
+        try {
+            return new ResponseEntity<>(resultService.getResult(name, version, lab, timestamp), HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger,
+                    "Error when retrieving results using timestamp data. " + UserUtils.getStackTrace(e));
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+    @RequestMapping(value = {
+    "/getlastrun/{lab}/{name}/{version}/{allLayers}/{optional}/{outcome}" }, method = RequestMethod.GET)
+    public ResponseEntity<ValidationNexusTestResult> getLastRun(@PathVariable("lab") Lab lab,
+            @PathVariable("name") String name, @PathVariable("version") String version,
+            @PathVariable("allLayers") Boolean allLayers, @PathVariable("optional") Boolean optional,
+            @PathVariable("outcome") boolean outcome) {
+        try {
+            return new ResponseEntity<>(
+                    resultService.getLastResultBasedOnOutcome(name, version, lab, allLayers, optional, outcome),
+                    HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger,
+                    "Error when retrieving last result. " + UserUtils.getStackTrace(e));
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+    @RequestMapping(value = {
+    "/getlastrunoflayers/{lab}/{name}/{version}/{layers}/{optional}/{outcome}" }, method = RequestMethod.GET)
+    public ResponseEntity<ValidationNexusTestResult> getLastRunOfLayers(@PathVariable("lab") Lab lab,
+            @PathVariable("name") String name, @PathVariable("version") String version,
+            @PathVariable("layers") List<BlueprintLayer> layers, @PathVariable("optional") Boolean optional,
+            @PathVariable("outcome") boolean outcome) {
+        try {
+            return new ResponseEntity<>(
+                    resultService.getLastResultBasedOnOutcome(name, version, lab, layers, optional, outcome),
+                    HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger,
+                    "Error when retrieving last result. " + UserUtils.getStackTrace(e));
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+    @RequestMapping(value = { "/getbasedondate/{lab}/{name}/{version}/{date}" }, method = RequestMethod.GET)
+    public ResponseEntity<List<ValidationNexusTestResult>> getBasedOnDate(@PathVariable("lab") Lab lab,
+            @PathVariable("name") String name, @PathVariable("version") String version,
+            @PathVariable("date") String date) {
+        try {
+            DateFormat dateFormat = new SimpleDateFormat("MM-dd-yyyy");
+            return new ResponseEntity<>(
+                    resultService.getBasedOnDateFromNexus(name, version, lab, dateFormat.parse(date)), HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger,
+                    "Error when retrieving results based on date. " + UserUtils.getStackTrace(e));
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+}
  * implied. See the License for the specific language governing
  * permissions and limitations under the License.
  */
+
 package org.akraino.validation.ui.controller;
 
 import java.util.List;
 
-import org.akraino.validation.ui.client.nexus.resources.WrapperRobotTestResult;
-import org.akraino.validation.ui.service.ResultService;
+import org.akraino.validation.ui.entity.LabSilo;
+import org.akraino.validation.ui.service.SiloService;
 import org.onap.portalsdk.core.controller.RestrictedBaseController;
 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
 import org.onap.portalsdk.core.web.support.UserUtils;
@@ -26,32 +27,30 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Controller;
-import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 
 @Controller
-@RequestMapping("/api/results")
-public class ResultsController extends RestrictedBaseController {
+@RequestMapping("/api/v1/silo")
+public class SiloController extends RestrictedBaseController {
 
-    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(ResultsController.class);
+    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(SiloController.class);
 
     @Autowired
-    ResultService service;
+    SiloService service;
 
-    public ResultsController() {
+    public SiloController() {
         super();
     }
 
-    @RequestMapping(value = {"/getBySubmissionId/{id}"}, method = RequestMethod.GET)
-    public ResponseEntity<List<WrapperRobotTestResult>> getByBlueprintId(@PathVariable("id") String submissionId) {
+    @RequestMapping(value = { "/" }, method = RequestMethod.GET)
+    public ResponseEntity<List<LabSilo>> getSilos() {
         try {
-            return new ResponseEntity<>(service.getRobotTestResults(submissionId), HttpStatus.OK);
+            return new ResponseEntity<>(service.getSilos(), HttpStatus.OK);
         } catch (Exception e) {
             LOGGER.error(EELFLoggerDelegate.errorLogger,
-                    "Error when retrieving results. " + UserUtils.getStackTrace(e));
+                    "Error when trying to get lab silos. " + UserUtils.getStackTrace(e));
         }
         return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
     }
-
 }
index fb6f8e0..49215b1 100644 (file)
@@ -17,8 +17,8 @@ package org.akraino.validation.ui.controller;
 
 import java.util.List;
 
-import org.akraino.validation.ui.entity.Submission;
-import org.akraino.validation.ui.service.SubmissionService;
+import org.akraino.validation.ui.data.SubmissionData;
+import org.akraino.validation.ui.service.DbSubmissionAdapter;
 import org.onap.portalsdk.core.controller.RestrictedBaseController;
 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
 import org.onap.portalsdk.core.web.support.UserUtils;
@@ -26,16 +26,17 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.HttpStatus;
 import org.springframework.http.ResponseEntity;
 import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PathVariable;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 
 @Controller
-@RequestMapping("/api/submission")
+@RequestMapping("/api/v1/submission")
 public class SubmissionController extends RestrictedBaseController {
 
     @Autowired
-    SubmissionService service;
+    DbSubmissionAdapter service;
 
     private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(SubmissionController.class);
 
@@ -43,20 +44,30 @@ public class SubmissionController extends RestrictedBaseController {
         super();
     }
 
-    @RequestMapping(value = {"/"}, method = RequestMethod.GET)
-    public ResponseEntity<List<Submission>> getSubmissions() {
+    @RequestMapping(value = { "/" }, method = RequestMethod.GET)
+    public ResponseEntity<List<SubmissionData>> getSubmissions() {
         try {
-            return new ResponseEntity<>(service.getSubmissions(), HttpStatus.OK);
+            return new ResponseEntity<>(service.getSubmissionDatas(), HttpStatus.OK);
         } catch (Exception e) {
             LOGGER.error(EELFLoggerDelegate.errorLogger, "Get of submissions failed. " + UserUtils.getStackTrace(e));
         }
         return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
     }
 
-    @RequestMapping(value = {"/"}, method = RequestMethod.POST)
-    public ResponseEntity<Submission> postSubmission(@RequestBody Submission newSubmission) {
+    @RequestMapping(value = { "/{id}" }, method = RequestMethod.GET)
+    public ResponseEntity<SubmissionData> getSubmission(@PathVariable("id") String submissionId) {
         try {
-            return new ResponseEntity<>(service.saveSubmission(newSubmission), HttpStatus.OK);
+            return new ResponseEntity<>(service.getSubmissionData(submissionId), HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger, "Get of submission failed. " + UserUtils.getStackTrace(e));
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+    @RequestMapping(value = { "/" }, method = RequestMethod.POST)
+    public ResponseEntity<SubmissionData> postSubmission(@RequestBody SubmissionData submissionData) {
+        try {
+            return new ResponseEntity<>(service.saveSubmission(submissionData), HttpStatus.OK);
         } catch (Exception e) {
             LOGGER.error(EELFLoggerDelegate.errorLogger, "Post of submission failed. " + UserUtils.getStackTrace(e));
         }
index 0f4f8d1..f82c273 100644 (file)
@@ -31,7 +31,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 
 @Controller
-@RequestMapping("/api/timeslots")
+@RequestMapping("/api/v1/timeslots")
 public class TimeslotsController extends RestrictedBaseController {
 
     private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(TimeslotsController.class);
@@ -43,7 +43,7 @@ public class TimeslotsController extends RestrictedBaseController {
         super();
     }
 
-    @RequestMapping(value = {"/"}, method = RequestMethod.GET)
+    @RequestMapping(value = { "/" }, method = RequestMethod.GET)
     public ResponseEntity<List<Timeslot>> getTimeSlots() {
         try {
             return new ResponseEntity<>(service.getTimeslots(), HttpStatus.OK);
index 918c73f..6929f5f 100644 (file)
@@ -17,6 +17,7 @@ package org.akraino.validation.ui.dao;
 
 import java.util.List;
 
+import org.akraino.validation.ui.data.Lab;
 import org.akraino.validation.ui.entity.LabInfo;
 
 public interface LabDAO {
@@ -29,6 +30,8 @@ public interface LabDAO {
 
     LabInfo getLab(Integer labId);
 
+    LabInfo getLab(Lab lab);
+
     void deleteLab(LabInfo lab);
 
     void deleteAll();
diff --git a/ui/src/main/java/org/akraino/validation/ui/dao/ValidationTestResultDAO.java b/ui/src/main/java/org/akraino/validation/ui/dao/ValidationTestResultDAO.java
new file mode 100644 (file)
index 0000000..6325606
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.akraino.validation.ui.dao;
+
+import java.util.List;
+
+import org.akraino.validation.ui.entity.LabInfo;
+import org.akraino.validation.ui.entity.Submission;
+import org.akraino.validation.ui.entity.ValidationDbTestResult;
+
+public interface ValidationTestResultDAO {
+
+    void saveOrUpdate(ValidationDbTestResult vResult);
+
+    void merge(ValidationDbTestResult vResult);
+
+    List<ValidationDbTestResult> getValidationTestResults();
+
+    ValidationDbTestResult getValidationTestResult(Integer resultId);
+
+    List<ValidationDbTestResult> getValidationTestResults(String blueprintName, String version, LabInfo labInfo,
+            Boolean allLayers, Boolean optional, Boolean outcome);
+
+    ValidationDbTestResult getValidationTestResult(LabInfo labInfo, String timestamp);
+
+    ValidationDbTestResult getValidationTestResult(Submission submission);
+
+    void deleteValidationTestResult(LabInfo labInfo, String timestamp);
+
+    void deleteValidationTestResult(ValidationDbTestResult vResult);
+
+    void deleteAll();
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/dao/WRobotTestResultDAO.java b/ui/src/main/java/org/akraino/validation/ui/dao/WRobotTestResultDAO.java
new file mode 100644 (file)
index 0000000..e4a72b8
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.akraino.validation.ui.dao;
+
+import java.util.List;
+
+import org.akraino.validation.ui.entity.ValidationDbTestResult;
+import org.akraino.validation.ui.entity.WRobotDbTestResult;
+
+public interface WRobotTestResultDAO {
+
+    void saveOrUpdate(WRobotDbTestResult wResult);
+
+    void merge(WRobotDbTestResult wResult);
+
+    List<WRobotDbTestResult> getWRobotTestResults();
+
+    WRobotDbTestResult getWRobotTestResult(Integer wRobotResultId);
+
+    WRobotDbTestResult getWRobotTestResult(String layer, ValidationDbTestResult vResult);
+
+    List<WRobotDbTestResult> getWRobotTestResult(ValidationDbTestResult vResult);
+
+    void deleteWRobotTestResult(Integer wRobotResultId);
+
+    void deleteAll();
+
+}
index 771c327..a349bcf 100644 (file)
@@ -17,6 +17,8 @@ package org.akraino.validation.ui.daoimpl;
 
 import java.util.List;
 
+import javax.annotation.Nonnull;
+
 import org.akraino.validation.ui.dao.BlueprintDAO;
 import org.akraino.validation.ui.entity.Blueprint;
 import org.hibernate.Criteria;
@@ -46,30 +48,34 @@ public class BlueprintDAOImpl implements BlueprintDAO {
     }
 
     @Override
-    public Blueprint getBlueprint(Integer blueprintId) {
+    public Blueprint getBlueprint(@Nonnull Integer blueprintId) {
         Criteria criteria = getSession().createCriteria(Blueprint.class);
         criteria.add(Restrictions.eq("id", String.valueOf(blueprintId)));
         return criteria.list() == null ? null : (Blueprint) criteria.list().get(0);
     }
 
     @Override
-    public void saveOrUpdate(Blueprint blueprint) {
+    public void saveOrUpdate(@Nonnull Blueprint blueprint) {
         getSession().saveOrUpdate(blueprint);
+        getSession().flush();
     }
 
     @Override
-    public void merge(Blueprint blueprint) {
+    public void merge(@Nonnull Blueprint blueprint) {
         getSession().merge(blueprint);
+        getSession().flush();
     }
 
     @Override
-    public void deleteBlueprint(Blueprint blueprint) {
+    public void deleteBlueprint(@Nonnull Blueprint blueprint) {
         getSession().delete(blueprint);
+        getSession().flush();
     }
 
     @Override
     public void deleteAll() {
         if (getSession().createQuery("delete from Blueprint").executeUpdate() > 0) {
+            getSession().flush();
             LOGGER.info(EELFLoggerDelegate.applicationLogger, "All blueprint entries are cleaned up");
         }
     }
index 7c51b69..515f747 100644 (file)
@@ -17,6 +17,8 @@ package org.akraino.validation.ui.daoimpl;
 
 import java.util.List;
 
+import javax.annotation.Nonnull;
+
 import org.akraino.validation.ui.dao.BlueprintInstanceForValidationDAO;
 import org.akraino.validation.ui.entity.BlueprintInstanceForValidation;
 import org.hibernate.Criteria;
@@ -30,8 +32,8 @@ import org.springframework.stereotype.Repository;
 @Repository
 public class BlueprintInstanceForValidationDAOImpl implements BlueprintInstanceForValidationDAO {
 
-    private static final EELFLoggerDelegate LOGGER =
-            EELFLoggerDelegate.getLogger(BlueprintInstanceForValidationDAOImpl.class);
+    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate
+            .getLogger(BlueprintInstanceForValidationDAOImpl.class);
 
     @Autowired
     private SessionFactory sessionFactory;
@@ -47,25 +49,28 @@ public class BlueprintInstanceForValidationDAOImpl implements BlueprintInstanceF
     }
 
     @Override
-    public BlueprintInstanceForValidation getBlueprintInstanceForValidation(Integer instId) {
+    public BlueprintInstanceForValidation getBlueprintInstanceForValidation(@Nonnull Integer instId) {
         Criteria criteria = getSession().createCriteria(BlueprintInstanceForValidation.class);
         criteria.add(Restrictions.eq("id", String.valueOf(instId)));
         return criteria.list() == null ? null : (BlueprintInstanceForValidation) criteria.list().get(0);
     }
 
     @Override
-    public void saveOrUpdate(BlueprintInstanceForValidation blueprintInst) {
+    public void saveOrUpdate(@Nonnull BlueprintInstanceForValidation blueprintInst) {
         getSession().saveOrUpdate(blueprintInst);
+        getSession().flush();
     }
 
     @Override
-    public void merge(BlueprintInstanceForValidation blueprintInst) {
+    public void merge(@Nonnull BlueprintInstanceForValidation blueprintInst) {
         getSession().merge(blueprintInst);
+        getSession().flush();
     }
 
     @Override
-    public void deleteBlueprintInstanceForValidation(BlueprintInstanceForValidation blueprintInst) {
+    public void deleteBlueprintInstanceForValidation(@Nonnull BlueprintInstanceForValidation blueprintInst) {
         getSession().delete(blueprintInst);
+        getSession().flush();
     }
 
     @Override
@@ -73,6 +78,7 @@ public class BlueprintInstanceForValidationDAOImpl implements BlueprintInstanceF
         if (getSession().createQuery("delete from BlueprintInstanceForValidation").executeUpdate() > 0) {
             LOGGER.info(EELFLoggerDelegate.applicationLogger,
                     "All blueprint instances for validation entries are cleaned up");
+            getSession().flush();
         }
     }
 
index 3a383da..36512ab 100644 (file)
@@ -17,7 +17,10 @@ package org.akraino.validation.ui.daoimpl;
 
 import java.util.List;
 
+import javax.annotation.Nonnull;
+
 import org.akraino.validation.ui.dao.LabDAO;
+import org.akraino.validation.ui.data.Lab;
 import org.akraino.validation.ui.entity.LabInfo;
 import org.hibernate.Criteria;
 import org.hibernate.Session;
@@ -46,31 +49,42 @@ public class LabDAOImpl implements LabDAO {
     }
 
     @Override
-    public LabInfo getLab(Integer labId) {
+    public LabInfo getLab(@Nonnull Integer labId) {
         Criteria criteria = getSession().createCriteria(LabInfo.class);
         criteria.add(Restrictions.eq("id", String.valueOf(labId)));
         return criteria.list() == null ? null : (LabInfo) criteria.list().get(0);
     }
 
     @Override
-    public void saveOrUpdate(LabInfo lab) {
+    public LabInfo getLab(@Nonnull Lab lab) {
+        Criteria criteria = getSession().createCriteria(LabInfo.class);
+        criteria.add(Restrictions.eq("lab", lab));
+        return criteria.list() == null ? null : (LabInfo) criteria.list().get(0);
+    }
+
+    @Override
+    public void saveOrUpdate(@Nonnull LabInfo lab) {
         getSession().saveOrUpdate(lab);
+        getSession().flush();
     }
 
     @Override
-    public void merge(LabInfo lab) {
+    public void merge(@Nonnull LabInfo lab) {
         getSession().merge(lab);
+        getSession().flush();
     }
 
     @Override
-    public void deleteLab(LabInfo lab) {
+    public void deleteLab(@Nonnull LabInfo lab) {
         getSession().delete(lab);
+        getSession().flush();
     }
 
     @Override
     public void deleteAll() {
         if (getSession().createQuery("delete from Lab").executeUpdate() > 0) {
             LOGGER.info(EELFLoggerDelegate.applicationLogger, "All lab entries are cleaned up");
+            getSession().flush();
         }
     }
 
index 3a347bd..8d3dffd 100644 (file)
@@ -17,6 +17,8 @@ package org.akraino.validation.ui.daoimpl;
 
 import java.util.List;
 
+import javax.annotation.Nonnull;
+
 import org.akraino.validation.ui.dao.SiloDAO;
 import org.akraino.validation.ui.entity.LabSilo;
 import org.hibernate.Criteria;
@@ -46,31 +48,35 @@ public class SiloDAOImpl implements SiloDAO {
     }
 
     @Override
-    public LabSilo getSilo(Integer siloId) {
+    public LabSilo getSilo(@Nonnull Integer siloId) {
         Criteria criteria = getSession().createCriteria(LabSilo.class);
         criteria.add(Restrictions.eq("id", String.valueOf(siloId)));
         return criteria.list() == null ? null : (LabSilo) criteria.list().get(0);
     }
 
     @Override
-    public void saveOrUpdate(LabSilo silo) {
+    public void saveOrUpdate(@Nonnull LabSilo silo) {
         getSession().saveOrUpdate(silo);
+        getSession().flush();
     }
 
     @Override
-    public void merge(LabSilo silo) {
+    public void merge(@Nonnull LabSilo silo) {
         getSession().merge(silo);
+        getSession().flush();
     }
 
     @Override
-    public void deleteSilo(LabSilo silo) {
+    public void deleteSilo(@Nonnull LabSilo silo) {
         getSession().delete(silo);
+        getSession().flush();
     }
 
     @Override
     public void deleteAll() {
         if (getSession().createQuery("delete from Silo").executeUpdate() > 0) {
             LOGGER.info(EELFLoggerDelegate.applicationLogger, "All silo entries are cleaned up");
+            getSession().flush();
         }
     }
 
index 7edab42..73e6e42 100644 (file)
@@ -17,6 +17,8 @@ package org.akraino.validation.ui.daoimpl;
 
 import java.util.List;
 
+import javax.annotation.Nonnull;
+
 import org.akraino.validation.ui.dao.SubmissionDAO;
 import org.akraino.validation.ui.entity.Submission;
 import org.hibernate.Criteria;
@@ -46,36 +48,41 @@ public class SubmissionDAOImpl implements SubmissionDAO {
     }
 
     @Override
-    public Submission getSubmission(Integer submissionId) {
+    public Submission getSubmission(@Nonnull Integer submissionId) {
         Criteria criteria = getSession().createCriteria(Submission.class);
         criteria.add(Restrictions.eq("id", submissionId));
         return criteria.list() == null || criteria.list().size() < 1 ? null : (Submission) criteria.list().get(0);
     }
 
     @Override
-    public void saveOrUpdate(Submission submission) {
+    public void saveOrUpdate(@Nonnull Submission submission) {
         getSession().saveOrUpdate(submission);
+        getSession().flush();
     }
 
     @Override
-    public void merge(Submission submission) {
+    public void merge(@Nonnull Submission submission) {
         getSession().merge(submission);
+        getSession().flush();
     }
 
     @Override
-    public void deleteSubmission(Submission submission) {
+    public void deleteSubmission(@Nonnull Submission submission) {
         getSession().delete(submission);
+        getSession().flush();
     }
 
     @Override
-    public void deleteSubmission(Integer submissionId) {
+    public void deleteSubmission(@Nonnull Integer submissionId) {
         getSession().delete(this.getSubmission(submissionId));
+        getSession().flush();
     }
 
     @Override
     public void deleteAll() {
         if (getSession().createQuery("delete from Submission").executeUpdate() > 0) {
             LOGGER.info(EELFLoggerDelegate.applicationLogger, "All submission entries are cleaned up");
+            getSession().flush();
         }
     }
 
index a6cd925..f155944 100644 (file)
@@ -17,6 +17,8 @@ package org.akraino.validation.ui.daoimpl;
 
 import java.util.List;
 
+import javax.annotation.Nonnull;
+
 import org.akraino.validation.ui.dao.TimeslotDAO;
 import org.akraino.validation.ui.entity.Timeslot;
 import org.hibernate.Criteria;
@@ -46,31 +48,35 @@ public class TimeslotDAOImpl implements TimeslotDAO {
     }
 
     @Override
-    public Timeslot getTimeslot(Integer timeslotId) {
+    public Timeslot getTimeslot(@Nonnull Integer timeslotId) {
         Criteria criteria = getSession().createCriteria(Timeslot.class);
         criteria.add(Restrictions.eq("id", String.valueOf(timeslotId)));
         return criteria.list() == null ? null : (Timeslot) criteria.list().get(0);
     }
 
     @Override
-    public void saveOrUpdate(Timeslot timeslot) {
+    public void saveOrUpdate(@Nonnull Timeslot timeslot) {
         getSession().saveOrUpdate(timeslot);
+        getSession().flush();
     }
 
     @Override
-    public void merge(Timeslot timeslot) {
+    public void merge(@Nonnull Timeslot timeslot) {
         getSession().merge(timeslot);
+        getSession().flush();
     }
 
     @Override
-    public void deleteTimeslot(Timeslot timeslot) {
+    public void deleteTimeslot(@Nonnull Timeslot timeslot) {
         getSession().delete(timeslot);
+        getSession().flush();
     }
 
     @Override
     public void deleteAll() {
         if (getSession().createQuery("delete from Timeslot").executeUpdate() > 0) {
             LOGGER.info(EELFLoggerDelegate.applicationLogger, "All timeslot entries are cleaned up");
+            getSession().flush();
         }
     }
 
diff --git a/ui/src/main/java/org/akraino/validation/ui/daoimpl/ValidationTestResultDAOImpl.java b/ui/src/main/java/org/akraino/validation/ui/daoimpl/ValidationTestResultDAOImpl.java
new file mode 100644 (file)
index 0000000..ab5e180
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.akraino.validation.ui.daoimpl;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.akraino.validation.ui.dao.ValidationTestResultDAO;
+import org.akraino.validation.ui.entity.LabInfo;
+import org.akraino.validation.ui.entity.Submission;
+import org.akraino.validation.ui.entity.ValidationDbTestResult;
+import org.hibernate.Criteria;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.criterion.Restrictions;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class ValidationTestResultDAOImpl implements ValidationTestResultDAO {
+
+    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(ValidationTestResultDAOImpl.class);
+
+    @Autowired
+    private SessionFactory sessionFactory;
+
+    protected Session getSession() {
+        return sessionFactory.getCurrentSession();
+    }
+
+    @Override
+    public List<ValidationDbTestResult> getValidationTestResults() {
+        Criteria criteria = getSession().createCriteria(ValidationDbTestResult.class);
+        return criteria.list();
+    }
+
+    @Override
+    public ValidationDbTestResult getValidationTestResult(@Nonnull Integer resultId) {
+        Criteria criteria = getSession().createCriteria(ValidationDbTestResult.class);
+        criteria.add(Restrictions.eq("id", String.valueOf(resultId)));
+        return criteria.list() == null ? null : (ValidationDbTestResult) criteria.list().get(0);
+    }
+
+    @Override
+    public List<ValidationDbTestResult> getValidationTestResults(String blueprintName, String version, LabInfo labInfo,
+            Boolean allLayers, Boolean optional, Boolean outcome) {
+        Criteria criteria = getSession().createCriteria(ValidationDbTestResult.class);
+        if (blueprintName != null) {
+            criteria.add(Restrictions.eq("blueprintName", String.valueOf(blueprintName)));
+        }
+        if (version != null) {
+            criteria.add(Restrictions.eq("version", String.valueOf(version)));
+        }
+        if (labInfo != null) {
+            criteria.add(Restrictions.eq("lab", labInfo));
+        }
+        if (allLayers != null) {
+            criteria.add(Restrictions.eq("allLayers", allLayers));
+        }
+        if (optional != null) {
+            criteria.add(Restrictions.eq("optional", optional));
+        }
+        if (outcome != null) {
+            criteria.add(Restrictions.eq("result", outcome));
+        }
+        return criteria.list() == null || criteria.list().size() == 0 ? null
+                : (List<ValidationDbTestResult>) criteria.list();
+    }
+
+    @Override
+    public ValidationDbTestResult getValidationTestResult(LabInfo labInfo, String timestamp) {
+        Criteria criteria = getSession().createCriteria(ValidationDbTestResult.class);
+        if (labInfo != null) {
+            criteria.add(Restrictions.eq("lab", labInfo));
+        }
+        if (timestamp != null) {
+            criteria.add(Restrictions.eq("timestamp", timestamp));
+        }
+        return criteria.list() == null || criteria.list().size() == 0 ? null
+                : (ValidationDbTestResult) criteria.list().get(0);
+    }
+
+    @Override
+    public ValidationDbTestResult getValidationTestResult(@Nonnull Submission submission) {
+        Criteria criteria = getSession().createCriteria(ValidationDbTestResult.class);
+        criteria.add(Restrictions.eq("submission", submission));
+        return criteria.list() == null || criteria.list().size() == 0 ? null
+                : (ValidationDbTestResult) criteria.list().get(0);
+    }
+
+    @Override
+    public void saveOrUpdate(@Nonnull ValidationDbTestResult vResult) {
+        getSession().saveOrUpdate(vResult);
+        getSession().flush();
+    }
+
+    @Override
+    public void merge(@Nonnull ValidationDbTestResult vResult) {
+        getSession().merge(vResult);
+        getSession().flush();
+    }
+
+    @Override
+    public void deleteValidationTestResult(@Nonnull ValidationDbTestResult vResult) {
+        getSession().delete(vResult);
+        getSession().flush();
+    }
+
+    @Override
+    public void deleteValidationTestResult(@Nonnull LabInfo labInfo, @Nonnull String timestamp) {
+        Criteria criteria = getSession().createCriteria(ValidationDbTestResult.class);
+        criteria.add(Restrictions.eq("lab", labInfo));
+        criteria.add(Restrictions.eq("timestamp", timestamp));
+        if (criteria.list() == null || criteria.list().size() == 0) {
+            return;
+        }
+        getSession().delete(criteria.list().get(0));
+        getSession().flush();
+    }
+
+    @Override
+    public void deleteAll() {
+        if (getSession().createQuery("delete from ValidationTestResult").executeUpdate() > 0) {
+            LOGGER.info(EELFLoggerDelegate.applicationLogger, "All validation test results are cleaned up");
+            getSession().flush();
+        }
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/daoimpl/WRobotTestResultDAOImpl.java b/ui/src/main/java/org/akraino/validation/ui/daoimpl/WRobotTestResultDAOImpl.java
new file mode 100644 (file)
index 0000000..6c7a4c1
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.akraino.validation.ui.daoimpl;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.akraino.validation.ui.dao.WRobotTestResultDAO;
+import org.akraino.validation.ui.entity.ValidationDbTestResult;
+import org.akraino.validation.ui.entity.WRobotDbTestResult;
+import org.hibernate.Criteria;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.criterion.Restrictions;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class WRobotTestResultDAOImpl implements WRobotTestResultDAO {
+
+    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(WRobotTestResultDAOImpl.class);
+
+    @Autowired
+    private SessionFactory sessionFactory;
+
+    protected Session getSession() {
+        return sessionFactory.getCurrentSession();
+    }
+
+    @Override
+    public List<WRobotDbTestResult> getWRobotTestResults() {
+        Criteria criteria = getSession().createCriteria(WRobotDbTestResult.class);
+        return criteria.list();
+    }
+
+    @Override
+    public WRobotDbTestResult getWRobotTestResult(@Nonnull Integer wRobotResultId) {
+        Criteria criteria = getSession().createCriteria(WRobotDbTestResult.class);
+        criteria.add(Restrictions.eq("id", wRobotResultId));
+        return criteria.list() == null || criteria.list().size() < 1 ? null
+                : (WRobotDbTestResult) criteria.list().get(0);
+    }
+
+    @Override
+    public List<WRobotDbTestResult> getWRobotTestResult(@Nonnull ValidationDbTestResult vResult) {
+        Criteria criteria = getSession().createCriteria(WRobotDbTestResult.class);
+        criteria.add(Restrictions.eq("vResult", vResult));
+        return criteria.list() == null || criteria.list().size() == 0 ? null
+                : (List<WRobotDbTestResult>) criteria.list();
+    }
+
+    @Override
+    public WRobotDbTestResult getWRobotTestResult(@Nonnull String layer, @Nonnull ValidationDbTestResult vResult) {
+        Criteria criteria = getSession().createCriteria(WRobotDbTestResult.class);
+        criteria.add(Restrictions.eq("layer", layer));
+        criteria.add(Restrictions.eq("vResult", vResult));
+        return criteria.list() == null || criteria.list().size() < 1 ? null
+                : (WRobotDbTestResult) criteria.list().get(0);
+    }
+
+    @Override
+    public void saveOrUpdate(@Nonnull WRobotDbTestResult wResult) {
+        getSession().saveOrUpdate(wResult);
+        getSession().flush();
+    }
+
+    @Override
+    public void merge(@Nonnull WRobotDbTestResult wResult) {
+        getSession().merge(wResult);
+        getSession().flush();
+    }
+
+    @Override
+    public void deleteWRobotTestResult(@Nonnull Integer wRobotResultId) {
+        getSession().delete(this.getWRobotTestResult(wRobotResultId));
+        getSession().flush();
+    }
+
+    @Override
+    public void deleteAll() {
+        if (getSession().createQuery("delete from WRobotTestResult").executeUpdate() > 0) {
+            LOGGER.info(EELFLoggerDelegate.applicationLogger, "All wrapper robot test results are cleaned up");
+            getSession().flush();
+        }
+    }
+
+}
index 9c57c04..6a67943 100644 (file)
@@ -16,5 +16,5 @@
 package org.akraino.validation.ui.data;
 
 public enum BlueprintLayer {
-    Hardware, Os, K8s, Kubeless, OpenStack, VNF, Application, All
+    hardware, os, k8s, kubeless, openstack, vnf, application, networking
 }
index f72a307..ec86bda 100644 (file)
@@ -32,6 +32,9 @@ public class JnksJobNotify {
     @JsonProperty("submissionId")
     private Integer submissionId;
 
+    @JsonProperty("timestamp")
+    private String timestamp;
+
     public JnksJobNotify() {
 
     }
@@ -60,4 +63,12 @@ public class JnksJobNotify {
         this.submissionId = submissionId;
     }
 
+    public String getTimestamp() {
+        return this.timestamp;
+    }
+
+    public void setTimeStamp(String timestamp) {
+        this.timestamp = timestamp;
+    }
+
 }
index ae84d8e..c25d240 100644 (file)
@@ -16,5 +16,5 @@
 package org.akraino.validation.ui.data;
 
 public enum Lab {
-    ATT, Ericsson, Community, Arm
+    att, ericsson, community, arm
 }
diff --git a/ui/src/main/java/org/akraino/validation/ui/data/SubmissionData.java b/ui/src/main/java/org/akraino/validation/ui/data/SubmissionData.java
new file mode 100644 (file)
index 0000000..d5b8223
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.akraino.validation.ui.data;
+
+import org.akraino.validation.ui.client.nexus.resources.ValidationNexusTestResult;
+import org.akraino.validation.ui.entity.Timeslot;
+
+public class SubmissionData {
+
+    private int submissionId;
+
+    private SubmissionStatus status;
+
+    private Timeslot timeslot;
+
+    private ValidationNexusTestResult validationNexusTestResult;
+
+    public SubmissionData() {
+
+    }
+
+    public int getSubmissionId() {
+        return this.submissionId;
+    }
+
+    public void setSubmissionId(int submissionId) {
+        this.submissionId = submissionId;
+    }
+
+    public SubmissionStatus getStatus() {
+        return this.status;
+    }
+
+    public void setStatus(SubmissionStatus status) {
+        this.status = status;
+    }
+
+    public Timeslot getTimeslot() {
+        return this.timeslot;
+    }
+
+    public void setTimeslot(Timeslot timeslot) {
+        this.timeslot = timeslot;
+    }
+
+    public ValidationNexusTestResult getValidationNexusTestResult() {
+        return this.validationNexusTestResult;
+    }
+
+    public void setValidationNexusTestResult(ValidationNexusTestResult validationNexusTestResult) {
+        this.validationNexusTestResult = validationNexusTestResult;
+    }
+}
index f046ce4..0d4801a 100644 (file)
@@ -24,6 +24,8 @@ import javax.persistence.GenerationType;
 import javax.persistence.Id;
 import javax.persistence.Table;
 
+import org.akraino.validation.ui.data.Lab;
+
 @Entity
 @Table(name = "lab")
 public class LabInfo implements Serializable {
@@ -39,7 +41,7 @@ public class LabInfo implements Serializable {
     private int labId;
 
     @Column(name = "lab")
-    private org.akraino.validation.ui.data.Lab lab;
+    private Lab lab;
 
     public int getLabId() {
         return labId;
@@ -49,11 +51,11 @@ public class LabInfo implements Serializable {
         this.labId = labId;
     }
 
-    public org.akraino.validation.ui.data.Lab getLab() {
+    public Lab getLab() {
         return lab;
     }
 
-    public void setLab(org.akraino.validation.ui.data.Lab lab) {
+    public void setLab(Lab lab) {
         this.lab = lab;
     }
 }
index 797343f..bdbe535 100644 (file)
@@ -45,16 +45,6 @@ public class Submission implements Serializable {
     @Column(name = "status")
     private SubmissionStatus status;
 
-    @Column(name = "jenkins_queue_job_item_url")
-    private String jnksJobUrl;
-
-    @Column(name = "nexus_result_url")
-    private String nexusResultUrl;
-
-    @ManyToOne
-    @JoinColumn(name = "blueprint_instance_for_validation_id")
-    private BlueprintInstanceForValidation blueprintInst;
-
     @ManyToOne
     @JoinColumn(name = "timeslot_id")
     private Timeslot timeslot;
@@ -75,31 +65,6 @@ public class Submission implements Serializable {
         this.status = submissionStatus;
     }
 
-    public String getJenkinsQueueJobItemUrl() {
-        return this.jnksJobUrl;
-    }
-
-    public void setJnksQueueJobItemUrl(String url) {
-        this.jnksJobUrl = url;
-    }
-
-    public String getNexusResultUrl() {
-        return this.nexusResultUrl;
-    }
-
-    public void setNexusResultUrl(String nexusResultUrl) {
-        this.nexusResultUrl = nexusResultUrl;
-    }
-
-    public void setBlueprintInstanceForValidation(BlueprintInstanceForValidation blueprintInst) {
-        this.blueprintInst = blueprintInst;
-    }
-
-    public BlueprintInstanceForValidation getBlueprintInstanceForValidation() {
-        return this.blueprintInst;
-    }
-
-
     public void setTimeslot(Timeslot timeslot) {
         this.timeslot = timeslot;
     }
@@ -108,5 +73,4 @@ public class Submission implements Serializable {
         return this.timeslot;
     }
 
-
 }
diff --git a/ui/src/main/java/org/akraino/validation/ui/entity/ValidationDbTestResult.java b/ui/src/main/java/org/akraino/validation/ui/entity/ValidationDbTestResult.java
new file mode 100644 (file)
index 0000000..6a447eb
--- /dev/null
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.akraino.validation.ui.entity;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.OneToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "validation_test_result")
+public class ValidationDbTestResult implements Serializable {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private int resultId;
+
+    @Column(name = "blueprint_name")
+    private String blueprintName;
+
+    @Column(name = "version")
+    private String version;
+
+    @ManyToOne
+    @JoinColumn(name = "lab_id")
+    private LabInfo lab;
+
+    @Column(name = "timestamp")
+    private String timestamp;
+
+    @Column(name = "all_layers")
+    private Boolean allLayers;
+
+    @Column(name = "optional")
+    private Boolean optional;
+
+    @Column(name = "result")
+    private Boolean result;
+
+    @Column(name = "date_of_storage")
+    private String dateStorage;
+
+    @OneToOne
+    @JoinColumn(name = "submission_id")
+    private Submission submission;
+
+    public int getResultId() {
+        return resultId;
+    }
+
+    public void setResultId(int resultId) {
+        this.resultId = resultId;
+    }
+
+    public String getBlueprintName() {
+        return blueprintName;
+    }
+
+    public void setBlueprintName(String blueprintName) {
+        this.blueprintName = blueprintName;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public Boolean getAllLayers() {
+        return allLayers;
+    }
+
+    public void setAllLayers(Boolean allLayers) {
+        this.allLayers = allLayers;
+    }
+
+    public Boolean getOptional() {
+        return optional;
+    }
+
+    public void setOptional(Boolean optional) {
+        this.optional = optional;
+    }
+
+    public LabInfo getLab() {
+        return lab;
+    }
+
+    public void setLab(LabInfo lab) {
+        this.lab = lab;
+    }
+
+    public String getTimestamp() {
+        return timestamp;
+    }
+
+    public void setTimestamp(String timestamp) {
+        this.timestamp = timestamp;
+    }
+
+    public Boolean getResult() {
+        return result;
+    }
+
+    public void setResult(Boolean result) {
+        this.result = result;
+    }
+
+    public String getDateStorage() {
+        return dateStorage;
+    }
+
+    public void setDateStorage(String dateStorage) {
+        this.dateStorage = dateStorage;
+    }
+
+    public Submission getSubmission() {
+        return this.submission;
+    }
+
+    public void setSubmission(Submission submission) {
+        this.submission = submission;
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/entity/WRobotDbTestResult.java b/ui/src/main/java/org/akraino/validation/ui/entity/WRobotDbTestResult.java
new file mode 100644 (file)
index 0000000..282a83e
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.akraino.validation.ui.entity;
+
+import java.io.Serializable;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.JoinColumn;
+import javax.persistence.ManyToOne;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "w_robot_test_result")
+public class WRobotDbTestResult implements Serializable {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private int wRobotResultId;
+
+    @Column(name = "layer")
+    private String layer;
+
+    @ManyToOne
+    @JoinColumn(name = "validation_test_result_id")
+    private ValidationDbTestResult vResult;
+
+    @Column(name = "robot_test_results")
+    private String rResults;
+
+    public int getWRobotResultId() {
+        return wRobotResultId;
+    }
+
+    public void setWRobotResultId(int wRobotResultId) {
+        this.wRobotResultId = wRobotResultId;
+    }
+
+    public String getLayer() {
+        return layer;
+    }
+
+    public void setLayer(String layer) {
+        this.layer = layer;
+    }
+
+    public ValidationDbTestResult getValidationTestResult() {
+        return vResult;
+    }
+
+    public void setValidationTestResult(ValidationDbTestResult vResult) {
+        this.vResult = vResult;
+    }
+
+    public String getRobotTestResults() {
+        return rResults;
+    }
+
+    public void setRobotTestResults(String rResults) {
+        this.rResults = rResults;
+    }
+
+}
index d786d09..707d686 100644 (file)
@@ -31,15 +31,11 @@ public class BlueprintInstanceForValidationService {
     private BlueprintInstanceForValidationDAO dao;
 
     public void saveBlueprintInstance(BlueprintInstanceForValidation blueprintIns) {
-
         dao.saveOrUpdate(blueprintIns);
-
     }
 
     public List<BlueprintInstanceForValidation> getBlueprintInstancesForValidation() {
-
         return dao.getBlueprintInstancesForValidation();
-
     }
 
     public void deleteAll() {
index ddc0219..37e2c0b 100644 (file)
@@ -31,15 +31,11 @@ public class BlueprintService {
     private BlueprintDAO blueprintDAO;
 
     public void saveBlueprint(Blueprint blueprint) {
-
         blueprintDAO.saveOrUpdate(blueprint);
-
     }
 
     public List<Blueprint> getBlueprints() {
-
         return blueprintDAO.getBlueprints();
-
     }
 
     public void deleteAll() {
diff --git a/ui/src/main/java/org/akraino/validation/ui/service/DbResultAdapter.java b/ui/src/main/java/org/akraino/validation/ui/service/DbResultAdapter.java
new file mode 100644 (file)
index 0000000..7e8687f
--- /dev/null
@@ -0,0 +1,510 @@
+package org.akraino.validation.ui.service;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+
+import javax.annotation.Nonnull;
+
+import org.akraino.validation.ui.client.nexus.resources.RobotTestResult;
+import org.akraino.validation.ui.client.nexus.resources.ValidationNexusTestResult;
+import org.akraino.validation.ui.client.nexus.resources.WRobotNexusTestResult;
+import org.akraino.validation.ui.dao.ValidationTestResultDAO;
+import org.akraino.validation.ui.dao.WRobotTestResultDAO;
+import org.akraino.validation.ui.data.BlueprintLayer;
+import org.akraino.validation.ui.data.JnksJobNotify;
+import org.akraino.validation.ui.data.Lab;
+import org.akraino.validation.ui.data.SubmissionData;
+import org.akraino.validation.ui.entity.LabInfo;
+import org.akraino.validation.ui.entity.LabSilo;
+import org.akraino.validation.ui.entity.Submission;
+import org.akraino.validation.ui.entity.ValidationDbTestResult;
+import org.akraino.validation.ui.entity.WRobotDbTestResult;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.portalsdk.core.web.support.UserUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+@Service
+@Transactional
+public class DbResultAdapter {
+
+    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(DbResultAdapter.class);
+    private static final Object LOCK = new Object();
+
+    @Autowired
+    LabService labService;
+
+    @Autowired
+    private ValidationTestResultDAO vTestResultDAO;
+
+    @Autowired
+    private WRobotTestResultDAO wRobotDAO;
+
+    @Autowired
+    private SiloService siloService;
+
+    @Autowired
+    DbSubmissionAdapter subService;
+
+    public void associateSubmissionWithValidationResult(SubmissionData submissionData)
+            throws JsonParseException, JsonMappingException, IOException {
+        synchronized (LOCK) {
+            ValidationDbTestResult vDbTestResult = this
+                    .convertValidationNexusToDb(submissionData.getValidationNexusTestResult());
+            Submission submission = new Submission();
+            submission.setSubmissionId(submissionData.getSubmissionId());
+            vDbTestResult.setSubmission(submission);
+            vTestResultDAO.saveOrUpdate(vDbTestResult);
+            List<WRobotDbTestResult> vRobotDbResults = this.convertWRobotNexusResultsToDb(
+                    submissionData.getValidationNexusTestResult().getwRobotNexusTestResults());
+            if (vRobotDbResults != null) {
+                for (WRobotDbTestResult vRobotDbResult : vRobotDbResults) {
+                    vRobotDbResult.setValidationTestResult(vDbTestResult);
+                    wRobotDAO.saveOrUpdate(vRobotDbResult);
+                }
+            }
+        }
+    }
+
+    public void storeResultInDb(List<ValidationNexusTestResult> vNexusResults) {
+        synchronized (LOCK) {
+            if (vNexusResults == null || vNexusResults.size() < 1) {
+                return;
+            }
+            for (ValidationNexusTestResult vNexusResult : vNexusResults) {
+                if (!checkValidityOfValidationNexusTestResult(vNexusResult)) {
+                    continue;
+                }
+                LabInfo labInfo = null;
+                for (LabSilo silo : siloService.getSilos()) {
+                    if (silo.getSilo().equals(vNexusResult.getSilo())) {
+                        labInfo = silo.getLab();
+                    }
+                }
+                ValidationDbTestResult vDbResult = vTestResultDAO.getValidationTestResult(labInfo,
+                        vNexusResult.getTimestamp());
+                if (vDbResult == null) {
+                    vDbResult = new ValidationDbTestResult();
+                    vDbResult.setLab(labInfo);
+                    vDbResult.setTimestamp(vNexusResult.getTimestamp());
+                    vDbResult.setBlueprintName(vNexusResult.getBlueprintName());
+                    vDbResult.setVersion(vNexusResult.getVersion());
+                    vDbResult.setAllLayers(vNexusResult.getAllLayers());
+                    vDbResult.setOptional(vNexusResult.getOptional());
+                }
+                vDbResult.setResult(vNexusResult.getResult());
+                vDbResult.setDateStorage(vNexusResult.getDateOfStorage());
+                LOGGER.debug(EELFLoggerDelegate.debugLogger,
+                        "Storing validation test result with keys: blueprint name: " + vNexusResult.getBlueprintName()
+                        + ", version: " + vNexusResult.getVersion() + ", lab: " + vNexusResult.getSilo()
+                        + ", timestamp: " + vNexusResult.getTimestamp());
+                vTestResultDAO.saveOrUpdate(vDbResult);
+                List<org.akraino.validation.ui.entity.WRobotDbTestResult> wRobotDbResults = wRobotDAO
+                        .getWRobotTestResult(vDbResult);
+                if (wRobotDbResults == null) {
+                    // Store the new wrapper robot rest results in db
+                    for (WRobotNexusTestResult wNexusResult : vNexusResult.getwRobotNexusTestResults()) {
+                        WRobotDbTestResult wRobotDbResult = new WRobotDbTestResult();
+                        wRobotDbResult.setLayer(wNexusResult.getBlueprintLayer().name());
+                        wRobotDbResult.setValidationTestResult(vDbResult);
+                        ObjectMapper mapper = new ObjectMapper();
+                        try {
+                            wRobotDbResult
+                            .setRobotTestResults(mapper.writeValueAsString(wNexusResult.getRobotTestResults()));
+                        } catch (JsonProcessingException e) {
+                            LOGGER.error(EELFLoggerDelegate.errorLogger,
+                                    "Error while converting POJO to string. " + UserUtils.getStackTrace(e));
+                            continue;
+                        }
+                        wRobotDAO.saveOrUpdate(wRobotDbResult);
+                    }
+                } else if (vDbResult.getSubmission() != null) {
+                    // update validation result related to submission
+                    for (WRobotNexusTestResult wNexusResult : vNexusResult.getwRobotNexusTestResults()) {
+                        WRobotDbTestResult wRobotDbResult = wRobotDAO
+                                .getWRobotTestResult(wNexusResult.getBlueprintLayer().name(), vDbResult);
+                        ObjectMapper mapper = new ObjectMapper();
+                        try {
+                            wRobotDbResult
+                            .setRobotTestResults(mapper.writeValueAsString(wNexusResult.getRobotTestResults()));
+                        } catch (JsonProcessingException e) {
+                            LOGGER.error(EELFLoggerDelegate.errorLogger,
+                                    "Error while converting POJO to string. " + UserUtils.getStackTrace(e));
+                            continue;
+                        }
+                        wRobotDAO.saveOrUpdate(wRobotDbResult);
+                    }
+                }
+            }
+        }
+    }
+
+    public void updateTimestamp(JnksJobNotify jnksJobNotify) {
+        synchronized (LOCK) {
+            if (!checkValidityOfJenkinsNotification(jnksJobNotify)) {
+                return;
+            }
+            ValidationDbTestResult vDbSubmission = vTestResultDAO
+                    .getValidationTestResult(subService.getSubmission(String.valueOf(jnksJobNotify.getSubmissionId())));
+            ValidationDbTestResult vDbTimestamp = vTestResultDAO.getValidationTestResult(vDbSubmission.getLab(),
+                    jnksJobNotify.getTimestamp());
+            if (vDbTimestamp == null) {
+                vDbSubmission.setTimestamp(jnksJobNotify.getTimestamp());
+                vTestResultDAO.saveOrUpdate(vDbSubmission);
+                return;
+            }
+            // Delete the wrobot results associated with submission validation result
+            List<WRobotDbTestResult> wRobotResults = wRobotDAO.getWRobotTestResult(vDbSubmission);
+            if (wRobotResults != null && wRobotResults.size() > 0) {
+                for (WRobotDbTestResult wRobotResult : wRobotResults) {
+                    wRobotDAO.deleteWRobotTestResult(wRobotResult.getWRobotResultId());
+                }
+            }
+            // Change the timestamp wrobot results to point to submission validation result
+            wRobotResults = wRobotDAO.getWRobotTestResult(vDbTimestamp);
+            if (wRobotResults != null && wRobotResults.size() > 0) {
+                for (WRobotDbTestResult wRobotResult : wRobotResults) {
+                    wRobotResult.setValidationTestResult(vDbSubmission);
+                    wRobotDAO.saveOrUpdate(wRobotResult);
+                }
+            }
+            vTestResultDAO.deleteValidationTestResult(vDbTimestamp);
+            // Now vDbSubmission can be updated
+            vDbSubmission.setDateStorage(vDbTimestamp.getDateStorage());
+            vDbSubmission.setResult(vDbTimestamp.getResult());
+            vDbSubmission.setTimestamp(vDbTimestamp.getTimestamp());
+            vTestResultDAO.saveOrUpdate(vDbSubmission);
+        }
+    }
+
+    public List<ValidationNexusTestResult> readResultFromDb(String blueprintName, String version, Lab lab,
+            List<BlueprintLayer> layers, Boolean allLayers, Boolean optional, Boolean outcome)
+                    throws JsonParseException, JsonMappingException, IOException {
+        synchronized (LOCK) {
+            LabInfo actualLabInfo = labService.getLab(lab);
+            List<ValidationDbTestResult> vDbResults = vTestResultDAO.getValidationTestResults(blueprintName, version,
+                    actualLabInfo, allLayers, optional, outcome);
+            if (vDbResults == null || vDbResults.size() < 1) {
+                return null;
+            }
+            List<ValidationNexusTestResult> vNexusResults = new ArrayList<ValidationNexusTestResult>();
+            for (ValidationDbTestResult vDbResult : vDbResults) {
+                if (layers != null && layers.size() > 0) {
+                    List<BlueprintLayer> storedLayers = new ArrayList<BlueprintLayer>();
+                    List<WRobotDbTestResult> wDbResults = wRobotDAO.getWRobotTestResult(vDbResult);
+                    if (wDbResults == null || wDbResults.size() < 1) {
+                        continue;
+                    }
+                    for (WRobotDbTestResult wRobot : wDbResults) {
+                        storedLayers.add(BlueprintLayer.valueOf(wRobot.getLayer()));
+                    }
+                    if (!new HashSet<>(storedLayers).equals(new HashSet<>(layers))) {
+                        continue;
+                    }
+                }
+                vNexusResults.add(convertValidationDbToNexus(vDbResult));
+            }
+            return vNexusResults;
+        }
+    }
+
+    public ValidationNexusTestResult readResultFromDb(@Nonnull Lab lab, @Nonnull String timestamp)
+            throws JsonParseException, JsonMappingException, IOException {
+        synchronized (LOCK) {
+            LabInfo actualLabInfo = labService.getLab(lab);
+            ValidationDbTestResult vDbResult = vTestResultDAO.getValidationTestResult(actualLabInfo, timestamp);
+            if (vDbResult == null) {
+                return null;
+            }
+            return convertValidationDbToNexus(vDbResult);
+        }
+    }
+
+    public ValidationNexusTestResult readResultFromDb(@Nonnull String submissionId)
+            throws JsonParseException, JsonMappingException, IOException {
+        synchronized (LOCK) {
+            ValidationDbTestResult vDbResult = vTestResultDAO
+                    .getValidationTestResult(subService.getSubmission(submissionId));
+            if (vDbResult == null) {
+                return null;
+            }
+            return convertValidationDbToNexus(vDbResult);
+        }
+    }
+
+    public void deleteUnreferencedEntries(List<ValidationNexusTestResult> vNexusResults) {
+        synchronized (LOCK) {
+            if (vNexusResults == null || vNexusResults.size() < 1) {
+                return;
+            }
+            LabInfo labInfo = null;
+            for (LabSilo silo : siloService.getSilos()) {
+                if (silo.getSilo().equals(vNexusResults.get(0).getSilo())) {
+                    labInfo = silo.getLab();
+                }
+            }
+            if (labInfo == null) {
+                return;
+            }
+            List<ValidationDbTestResult> vDbResults = vTestResultDAO.getValidationTestResults(
+                    vNexusResults.get(0).getBlueprintName(), vNexusResults.get(0).getVersion(), labInfo, null, null,
+                    null);
+            if (vDbResults == null || vDbResults.size() < 1) {
+                return;
+            }
+            for (ValidationDbTestResult vDbResult : vDbResults) {
+                if (vDbResult.getSubmission() != null) {
+                    continue;
+                }
+                boolean deletion = true;
+                String dbTimestamp = vDbResult.getTimestamp();
+                LabInfo dbLabInfo = vDbResult.getLab();
+                for (ValidationNexusTestResult vNexusResult : vNexusResults) {
+                    LabInfo nexusLabInfo = null;
+                    for (LabSilo silo : siloService.getSilos()) {
+                        if (silo.getSilo().equals(vNexusResult.getSilo())) {
+                            nexusLabInfo = silo.getLab();
+                        }
+                    }
+                    if (nexusLabInfo == null) {
+                        continue;
+                    }
+                    if (vNexusResult.getTimestamp().equals(dbTimestamp) && nexusLabInfo.equals(dbLabInfo)) {
+                        deletion = false;
+                        break;
+                    }
+                }
+                if (deletion) {
+                    LOGGER.debug(EELFLoggerDelegate.debugLogger,
+                            "Deleting unreferenced validation result with id: " + vDbResult.getResultId());
+                    // Delete old associated wrapper robot rest results from db
+                    for (WRobotDbTestResult wRobotDbResult : wRobotDAO.getWRobotTestResult(vDbResult)) {
+                        wRobotDAO.deleteWRobotTestResult(wRobotDbResult.getWRobotResultId());
+                    }
+                    vTestResultDAO.deleteValidationTestResult(vDbResult);
+                }
+            }
+
+        }
+    }
+
+    public List<ValidationDbTestResult> getValidationTestResults() {
+        synchronized (LOCK) {
+            return vTestResultDAO.getValidationTestResults();
+        }
+    }
+
+    public ValidationDbTestResult getValidationTestResult(Integer resultId) {
+        synchronized (LOCK) {
+            return vTestResultDAO.getValidationTestResult(resultId);
+        }
+    }
+
+    public List<ValidationDbTestResult> getValidationTestResults(String blueprintName, String version, LabInfo labInfo,
+            Boolean allLayers, Boolean optional, Boolean outcome) {
+        synchronized (LOCK) {
+            return vTestResultDAO.getValidationTestResults(blueprintName, version, labInfo, allLayers, optional,
+                    outcome);
+        }
+    }
+
+    public ValidationDbTestResult getValidationTestResult(LabInfo labInfo, String timestamp) {
+        synchronized (LOCK) {
+            return vTestResultDAO.getValidationTestResult(labInfo, timestamp);
+        }
+    }
+
+    public ValidationDbTestResult getValidationTestResult(@Nonnull Submission submission) {
+        synchronized (LOCK) {
+            return vTestResultDAO.getValidationTestResult(submission);
+        }
+    }
+
+    public List<WRobotDbTestResult> getWRobotTestResults() {
+        synchronized (LOCK) {
+            return wRobotDAO.getWRobotTestResults();
+        }
+    }
+
+    public WRobotDbTestResult getWRobotTestResult(Integer wRobotResultId) {
+        synchronized (LOCK) {
+            return wRobotDAO.getWRobotTestResult(wRobotResultId);
+        }
+    }
+
+    public List<WRobotDbTestResult> getWRobotTestResult(ValidationDbTestResult vResult) {
+        synchronized (LOCK) {
+            return wRobotDAO.getWRobotTestResult(vResult);
+        }
+    }
+
+    private ValidationNexusTestResult convertValidationDbToNexus(ValidationDbTestResult vDbResult)
+            throws JsonParseException, JsonMappingException, IOException {
+        ValidationNexusTestResult vNexusResult = new ValidationNexusTestResult();
+        vNexusResult.setResultId(vDbResult.getResultId());
+        vNexusResult.setBlueprintName(vDbResult.getBlueprintName());
+        vNexusResult.setVersion(vDbResult.getVersion());
+        vNexusResult.setAllLayers(vDbResult.getAllLayers());
+        vNexusResult.setDateOfStorage(vDbResult.getDateStorage());
+        vNexusResult.setOptional(vDbResult.getOptional());
+        vNexusResult.setResult(vDbResult.getResult());
+        String siloText = null;
+        for (LabSilo silo : siloService.getSilos()) {
+            if (silo.getLab().getLab().equals(vDbResult.getLab().getLab())) {
+                siloText = silo.getSilo();
+            }
+        }
+        if (siloText == null) {
+            throw new IllegalArgumentException("Lab does not exist: " + vDbResult.getLab().toString());
+        }
+        vNexusResult.setSilo(siloText);
+        vNexusResult.setTimestamp(vDbResult.getTimestamp());
+        if (vDbResult.getSubmission() != null) {
+            vNexusResult.setSubmissionId(String.valueOf(vDbResult.getSubmission().getSubmissionId()));
+        }
+        List<WRobotNexusTestResult> wNexusResults = new ArrayList<WRobotNexusTestResult>();
+        List<WRobotDbTestResult> wDbResults = wRobotDAO.getWRobotTestResult(vDbResult);
+        if (wDbResults != null && wDbResults.size() > 0) {
+            for (WRobotDbTestResult wRobot : wDbResults) {
+                WRobotNexusTestResult wNexusResult = new WRobotNexusTestResult();
+                wNexusResult.setBlueprintLayer(BlueprintLayer.valueOf(wRobot.getLayer()));
+                if (wRobot.getRobotTestResults() != null) {
+                    ObjectMapper mapper = new ObjectMapper();
+                    wNexusResult.setRobotTestResults(
+                            mapper.readValue(wRobot.getRobotTestResults(), new TypeReference<List<RobotTestResult>>() {
+                            }));
+                }
+                wNexusResults.add(wNexusResult);
+            }
+            vNexusResult.setwRobotNexusTestResults(wNexusResults);
+        }
+        return vNexusResult;
+    }
+
+    private ValidationDbTestResult convertValidationNexusToDb(ValidationNexusTestResult vNexusResult)
+            throws JsonParseException, JsonMappingException, IOException {
+        LabInfo labInfo = null;
+        for (LabSilo silo : siloService.getSilos()) {
+            if (silo.getSilo().equals(vNexusResult.getSilo())) {
+                labInfo = silo.getLab();
+            }
+        }
+        if (labInfo == null) {
+            return null;
+        }
+        ValidationDbTestResult vDbResult = new ValidationDbTestResult();
+        vDbResult.setBlueprintName(vNexusResult.getBlueprintName());
+        vDbResult.setVersion(vNexusResult.getVersion());
+        vDbResult.setLab(labInfo);
+        vDbResult.setOptional(vNexusResult.getOptional());
+        vDbResult.setAllLayers(vNexusResult.getAllLayers());
+        vDbResult.setDateStorage(vNexusResult.getDateOfStorage());
+        vDbResult.setResult(vNexusResult.getResult());
+        vDbResult.setTimestamp(vNexusResult.getTimestamp());
+        return vDbResult;
+    }
+
+    private List<WRobotDbTestResult> convertWRobotNexusResultsToDb(List<WRobotNexusTestResult> wRobotNexusResults) {
+        if (wRobotNexusResults == null || wRobotNexusResults.size() < 1) {
+            return null;
+        }
+        List<WRobotDbTestResult> wDbResults = new ArrayList<WRobotDbTestResult>();
+        for (WRobotNexusTestResult wRobotNexusResult : wRobotNexusResults) {
+            WRobotDbTestResult wDbResult = new WRobotDbTestResult();
+            if (wRobotNexusResult.getBlueprintLayer() != null) {
+                wDbResult.setLayer(wRobotNexusResult.getBlueprintLayer().toString());
+            }
+            ObjectMapper mapper = new ObjectMapper();
+            if (wRobotNexusResult.getRobotTestResults() != null && wRobotNexusResult.getRobotTestResults().size() > 0) {
+                try {
+                    wDbResult.setRobotTestResults(mapper.writeValueAsString(wRobotNexusResult.getRobotTestResults()));
+                } catch (JsonProcessingException e) {
+                    LOGGER.error(EELFLoggerDelegate.errorLogger,
+                            "Error while converting POJO to string. " + UserUtils.getStackTrace(e));
+                    continue;
+                }
+            }
+            wDbResults.add(wDbResult);
+        }
+        return wDbResults;
+    }
+
+    private boolean checkValidityOfValidationNexusTestResult(ValidationNexusTestResult vNexusResult) {
+        LabInfo labInfo = null;
+        for (LabSilo silo : siloService.getSilos()) {
+            if (silo.getSilo().equals(vNexusResult.getSilo())) {
+                labInfo = silo.getLab();
+            }
+        }
+        if (labInfo == null) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger, "No lab Info found for silo. " + vNexusResult.getSilo());
+            return false;
+        }
+        ValidationDbTestResult vDbResult = vTestResultDAO.getValidationTestResult(labInfo, vNexusResult.getTimestamp());
+        if (vDbResult != null) {
+            // Be elastic for allLayers and optional
+            if (!vDbResult.getBlueprintName().equals(vNexusResult.getBlueprintName())
+                    || !vDbResult.getVersion().equals(vNexusResult.getVersion()) || !vDbResult.getLab().equals(labInfo)
+                    || !vDbResult.getTimestamp().equals(vNexusResult.getTimestamp())) {
+                LOGGER.error(EELFLoggerDelegate.errorLogger,
+                        "Nexus has different data for blueprint : " + vDbResult.getBlueprintName() + ", version: "
+                                + vDbResult.getVersion() + " and lab: " + vDbResult.getLab().getLab().name());
+                return false;
+            }
+        }
+        List<org.akraino.validation.ui.entity.WRobotDbTestResult> wRobotDbResults = wRobotDAO
+                .getWRobotTestResult(vDbResult);
+        if (wRobotDbResults != null) {
+            if (vDbResult.getSubmission() != null) {
+                for (WRobotNexusTestResult wNexusResult : vNexusResult.getwRobotNexusTestResults()) {
+                    WRobotDbTestResult wRobotDbResult = wRobotDAO
+                            .getWRobotTestResult(wNexusResult.getBlueprintLayer().name(), vDbResult);
+                    if (wRobotDbResult == null) {
+                        LOGGER.error(EELFLoggerDelegate.errorLogger,
+                                "Nexus has different layer results for submission id: "
+                                        + vDbResult.getSubmission().getSubmissionId());
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
+    private boolean checkValidityOfJenkinsNotification(JnksJobNotify jnksJobNotify) {
+        ValidationDbTestResult vDbSubmission = vTestResultDAO
+                .getValidationTestResult(subService.getSubmission(String.valueOf(jnksJobNotify.getSubmissionId())));
+        if (vDbSubmission == null) {
+            return false;
+        }
+        ValidationDbTestResult vDbTimestamp = vTestResultDAO.getValidationTestResult(vDbSubmission.getLab(),
+                jnksJobNotify.getTimestamp());
+        if (vDbTimestamp == null) {
+            return true;
+        }
+        if (vDbTimestamp.equals(vDbSubmission) || (vDbTimestamp.getSubmission() != null
+                && !jnksJobNotify.getSubmissionId().equals(vDbTimestamp.getSubmission().getSubmissionId()))) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger, "Received same timestamp: " + jnksJobNotify.getTimestamp()
+            + " from nexus for submission id: " + jnksJobNotify.getSubmissionId());
+            return false;
+        }
+        // Be elastic for allLayers and optional
+        if (!vDbSubmission.getBlueprintName().equals(vDbTimestamp.getBlueprintName())
+                || !vDbSubmission.getVersion().equals(vDbTimestamp.getVersion())
+                || !vDbSubmission.getLab().equals(vDbTimestamp.getLab())) {
+            LOGGER.error(EELFLoggerDelegate.errorLogger, "No consistency exists in database records.");
+            return false;
+        }
+        return true;
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/service/DbSubmissionAdapter.java b/ui/src/main/java/org/akraino/validation/ui/service/DbSubmissionAdapter.java
new file mode 100644 (file)
index 0000000..977e89d
--- /dev/null
@@ -0,0 +1,218 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.akraino.validation.ui.service;
+
+import java.io.IOException;
+import java.net.DatagramSocket;
+import java.net.InetAddress;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ExecutorService;
+
+import org.akraino.validation.ui.client.jenkins.JenkinsExecutorClient;
+import org.akraino.validation.ui.client.jenkins.resources.Parameter;
+import org.akraino.validation.ui.client.jenkins.resources.Parameters;
+import org.akraino.validation.ui.conf.ExecutorServiceInitializer;
+import org.akraino.validation.ui.dao.SubmissionDAO;
+import org.akraino.validation.ui.data.SubmissionData;
+import org.akraino.validation.ui.data.SubmissionStatus;
+import org.akraino.validation.ui.entity.LabSilo;
+import org.akraino.validation.ui.entity.Submission;
+import org.akraino.validation.ui.service.utils.PrioritySupplier;
+import org.akraino.validation.ui.service.utils.SubmissionHelper;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.portalsdk.core.web.support.UserUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.annotation.AnnotationConfigApplicationContext;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+
+@Service
+@Transactional
+public class DbSubmissionAdapter {
+
+    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(DbSubmissionAdapter.class);
+
+    @Autowired
+    private SubmissionDAO submissionDAO;
+
+    @Autowired
+    private SubmissionHelper submissionHelper;
+
+    @Autowired
+    private JenkinsExecutorClient jenkinsService;
+
+    @Autowired
+    private DbResultAdapter dbAdapter;
+
+    @Autowired
+    SiloService siloService;
+
+    public SubmissionData saveSubmission(SubmissionData submissionData)
+            throws JsonParseException, JsonMappingException, IOException {
+        Submission submission = new Submission();
+        submission.setSubmissionStatus(SubmissionStatus.Submitted);
+        submission.setTimeslot(submissionData.getTimeslot());
+        submissionDAO.saveOrUpdate(submission);
+        submissionData.setSubmissionId(submission.getSubmissionId());
+        String siloText = null;
+        for (LabSilo silo : siloService.getSilos()) {
+            if (silo.getLab().getLab().equals(submissionData.getTimeslot().getLab().getLab())) {
+                siloText = silo.getSilo();
+            }
+        }
+        if (siloText == null) {
+            throw new IllegalArgumentException(
+                    "Lab does not exist: " + submissionData.getTimeslot().getLab().toString());
+        }
+        submissionData.getValidationNexusTestResult().setSilo(siloText);
+        dbAdapter.associateSubmissionWithValidationResult(submissionData);
+        ApplicationContext context = new AnnotationConfigApplicationContext(ExecutorServiceInitializer.class);
+        ExecutorService service = (ExecutorService) context.getBean("executorService");
+        JenkinsTriggerSubmissionJob task = new JenkinsTriggerSubmissionJob(submissionData);
+        CompletableFuture<SubmissionData> completableFuture = CompletableFuture
+                .supplyAsync(new PrioritySupplier<>(1, task::execute), service);
+        completableFuture.thenAcceptAsync(result -> this.callbackNotify(result));
+        submissionData.setSubmissionId(submission.getSubmissionId());
+        return submissionData;
+    }
+
+    public List<Submission> getSubmissions() {
+        return submissionDAO.getSubmissions();
+    }
+
+    public List<SubmissionData> getSubmissionDatas() throws JsonParseException, JsonMappingException, IOException {
+        List<Submission> submissions = submissionDAO.getSubmissions();
+        if (submissions == null || submissions.size() < 1) {
+            return null;
+        }
+        List<SubmissionData> datas = new ArrayList<SubmissionData>();
+        for (Submission submission : submissions) {
+            SubmissionData submissionData = new SubmissionData();
+            submissionData.setStatus(submission.getSubmissionStatus());
+            submissionData.setSubmissionId(submission.getSubmissionId());
+            submissionData.setTimeslot(submission.getTimeslot());
+            submissionData.setValidationNexusTestResult(
+                    dbAdapter.readResultFromDb(String.valueOf(submission.getSubmissionId())));
+            datas.add(submissionData);
+        }
+        return datas;
+    }
+
+    public SubmissionData getSubmissionData(String submissionId)
+            throws JsonParseException, JsonMappingException, IOException {
+        Submission submission = submissionDAO.getSubmission(Integer.valueOf(submissionId));
+        if (submission == null) {
+            return null;
+        }
+        SubmissionData submissionData = new SubmissionData();
+        submissionData.setStatus(submission.getSubmissionStatus());
+        submissionData.setSubmissionId(submission.getSubmissionId());
+        submissionData.setTimeslot(submission.getTimeslot());
+        submissionData.setValidationNexusTestResult(dbAdapter.readResultFromDb(submissionId));
+        return submissionData;
+    }
+
+    public Submission getSubmission(String submissionId) {
+        return submissionDAO.getSubmission(Integer.valueOf(submissionId));
+    }
+
+    public void deleteSubmission(Integer submissionId) {
+        submissionDAO.deleteSubmission(submissionId);
+    }
+
+    public void deleteAll() {
+        submissionDAO.deleteAll();
+    }
+
+    private void callbackNotify(SubmissionData submissionData) {
+        if (submissionData == null) {
+            return;
+        }
+        Submission submission = submissionHelper.getSubmission(submissionData.getSubmissionId());
+        submission.setSubmissionStatus(SubmissionStatus.Running);
+        submissionHelper.saveSubmission(submission);
+    }
+
+    private class JenkinsTriggerSubmissionJob {
+
+        private SubmissionData submissionData;
+
+        public JenkinsTriggerSubmissionJob(SubmissionData submissionData) {
+            this.submissionData = submissionData;
+        }
+
+        public SubmissionData execute() {
+            try (final DatagramSocket socket = new DatagramSocket()) {
+                String jobName = System.getenv("JENKINS_JOB_NAME");
+                List<Parameter> listOfParameters = new ArrayList<Parameter>();
+                Parameters parameters = new Parameters();
+                Parameter parameter = new Parameter();
+                parameter.setName("SUBMISSION_ID");
+                parameter.setValue(String.valueOf(submissionData.getSubmissionId()));
+                listOfParameters.add(parameter);
+                parameter = new Parameter();
+                parameter.setName("BLUEPRINT");
+                parameter.setValue(submissionData.getValidationNexusTestResult().getBlueprintName());
+                listOfParameters.add(parameter);
+                parameter = new Parameter();
+                parameter.setName("LAYER");
+                if (submissionData.getValidationNexusTestResult().getAllLayers()) {
+                    parameter.setValue("all");
+                } else {
+                    parameter.setValue(submissionData.getValidationNexusTestResult().getwRobotNexusTestResults().get(0)
+                            .getBlueprintLayer().name().toLowerCase());
+                }
+                listOfParameters.add(parameter);
+                parameter = new Parameter();
+                parameter.setName("VERSION");
+                parameter.setValue(submissionData.getValidationNexusTestResult().getVersion());
+                listOfParameters.add(parameter);
+                parameter = new Parameter();
+                parameter.setName("LAB");
+                parameter.setValue(submissionData.getTimeslot().getLab().getLab().name());
+                listOfParameters.add(parameter);
+                parameter = new Parameter();
+                parameter.setName("OPTIONAL");
+                parameter.setValue(
+                        String.valueOf(submissionData.getValidationNexusTestResult().getOptional().toString()));
+                listOfParameters.add(parameter);
+                parameter = new Parameter();
+                parameter.setName("UI_IP");
+                Random random = new Random();
+                socket.connect(InetAddress.getByName(random.nextInt(256) + "." + random.nextInt(256) + "."
+                        + random.nextInt(256) + "." + random.nextInt(256)), 10002);
+                String localIP = socket.getLocalAddress().getHostAddress();
+                parameter.setValue(localIP);
+                listOfParameters.add(parameter);
+                parameters.setParameter(listOfParameters);
+                jenkinsService.postJobWithQueryParams(jobName, parameters).toString();
+                return submissionData;
+            } catch (Exception e) {
+                LOGGER.error(EELFLoggerDelegate.errorLogger,
+                        "Error when triggering Jenkins job. " + UserUtils.getStackTrace(e));
+                return null;
+            }
+        }
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/service/IntegratedResultService.java b/ui/src/main/java/org/akraino/validation/ui/service/IntegratedResultService.java
new file mode 100644 (file)
index 0000000..0015590
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License. You may obtain
+ * a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+package org.akraino.validation.ui.service;
+
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.NoSuchAlgorithmException;
+import java.text.DateFormat;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+import org.akraino.validation.ui.client.nexus.NexusExecutorClient;
+import org.akraino.validation.ui.client.nexus.resources.ValidationNexusTestResult;
+import org.akraino.validation.ui.data.BlueprintLayer;
+import org.akraino.validation.ui.data.Lab;
+import org.akraino.validation.ui.data.SubmissionData;
+import org.akraino.validation.ui.entity.LabInfo;
+import org.akraino.validation.ui.entity.LabSilo;
+import org.akraino.validation.ui.entity.ValidationDbTestResult;
+import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
+import org.onap.portalsdk.core.web.support.UserUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.databind.JsonMappingException;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.UniformInterfaceException;
+
+@Service
+@Transactional
+public class IntegratedResultService {
+
+    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(IntegratedResultService.class);
+
+    @Autowired
+    private DbSubmissionAdapter submissionService;
+
+    @Autowired
+    private SiloService siloService;
+
+    @Autowired
+    NexusExecutorClient nexusService;
+
+    @Autowired
+    LabService labService;
+
+    @Autowired
+    DbResultAdapter dbAdapter;
+
+    public List<Lab> getLabsFromNexus()
+            throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException,
+            UniformInterfaceException, NoSuchAlgorithmException, IOException, IllegalArgumentException, ParseException {
+        List<Lab> labs = new ArrayList<Lab>();
+        for (String cLabSilo : nexusService.getResource(null)) {
+            for (LabSilo silo : siloService.getSilos()) {
+                if (silo.getSilo().equals(cLabSilo)) {
+                    labs.add(silo.getLab().getLab());
+                }
+            }
+        }
+        return labs;
+    }
+
+    public List<String> getBlueprintNamesOfLabFromNexus(@Nonnull Lab lab)
+            throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException,
+            UniformInterfaceException, NoSuchAlgorithmException, IOException, IllegalArgumentException, ParseException {
+        String siloText = null;
+        for (LabSilo silo : siloService.getSilos()) {
+            if (silo.getLab().getLab().equals(lab)) {
+                siloText = silo.getSilo();
+            }
+        }
+        if (siloText == null) {
+            throw new IllegalArgumentException("Could not retrieve blueprint names of lab : " + lab.toString());
+        }
+        List<String> blueprintNames = new ArrayList<String>();
+        List<String> cBlueprintNames = nexusService.getResource(siloText);
+        for (String cBlueprintName : cBlueprintNames) {
+            if (!cBlueprintName.equals("job")) {
+                blueprintNames.add(cBlueprintName);
+            }
+        }
+        return blueprintNames;
+    }
+
+    public List<String> getBlueprintVersionsFromNexus(@Nonnull String name, @Nonnull Lab lab)
+            throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException,
+            UniformInterfaceException, NoSuchAlgorithmException, IOException, IllegalArgumentException, ParseException {
+        String siloText = null;
+        for (LabSilo silo : siloService.getSilos()) {
+            if (silo.getLab().getLab().equals(lab)) {
+                siloText = silo.getSilo();
+            }
+        }
+        if (siloText == null) {
+            throw new IllegalArgumentException("Could not retrieve silo of the lab : " + lab.toString());
+        }
+        return nexusService.getResource(siloText, name);
+    }
+
+    public List<String> getBlueprintTimeStampsFromNexus(@Nonnull String name, @Nonnull String version, @Nonnull Lab lab)
+            throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException,
+            UniformInterfaceException, NoSuchAlgorithmException, IOException, ParseException {
+        String siloText = null;
+        for (LabSilo silo : siloService.getSilos()) {
+            if (silo.getLab().getLab().equals(lab)) {
+                siloText = silo.getSilo();
+            }
+        }
+        if (siloText == null) {
+            throw new IllegalArgumentException("Could not retrieve silo of the lab : " + lab.toString());
+        }
+        return nexusService.getResource(siloText, name, version);
+    }
+
+    public List<ValidationNexusTestResult> getResultsFromNexus(@Nonnull String name, @Nonnull String version,
+            @Nonnull Lab lab, int noTimestamps)
+                    throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException,
+                    UniformInterfaceException, NoSuchAlgorithmException, IOException, IllegalArgumentException, ParseException {
+        String siloText = null;
+        for (LabSilo silo : siloService.getSilos()) {
+            if (silo.getLab().getLab().equals(lab)) {
+                siloText = silo.getSilo();
+            }
+        }
+        if (siloText == null) {
+            throw new IllegalArgumentException("Could not retrieve silo of the lab : " + lab.toString());
+        }
+        return nexusService.getResults(name, version, siloText, noTimestamps);
+    }
+
+    public ValidationNexusTestResult getResultFromNexus(@Nonnull String name, @Nonnull String version, @Nonnull Lab lab,
+            @Nonnull String timestamp) throws JsonParseException, JsonMappingException, IOException,
+    KeyManagementException, ClientHandlerException, UniformInterfaceException, NoSuchAlgorithmException,
+    NullPointerException, ParseException {
+        String siloText = null;
+        for (LabSilo silo : siloService.getSilos()) {
+            if (silo.getLab().getLab().equals(lab)) {
+                siloText = silo.getSilo();
+            }
+        }
+        if (siloText == null) {
+            throw new IllegalArgumentException("Could not retrieve silo of the lab : " + lab.toString());
+        }
+        return nexusService.getResult(name, version, siloText, timestamp);
+    }
+
+    public ValidationNexusTestResult getLastResultBasedOnOutcomeFromNexus(@Nonnull String name, @Nonnull String version,
+            @Nonnull Lab lab, Boolean allLayers, Boolean optional, boolean outcome)
+                    throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException,
+                    UniformInterfaceException, NoSuchAlgorithmException, NullPointerException, IOException, ParseException {
+        String siloText = null;
+        for (LabSilo silo : siloService.getSilos()) {
+            if (silo.getLab().getLab().equals(lab)) {
+                siloText = silo.getSilo();
+            }
+        }
+        if (siloText == null) {
+            throw new IllegalArgumentException("Lab does not exist: " + lab.toString());
+        }
+        return nexusService.getLastResultBasedOnOutcome(name, version, siloText, allLayers, optional, outcome);
+    }
+
+    public ValidationNexusTestResult getLastResultBasedOnOutcomeFromNexus(@Nonnull String name, @Nonnull String version,
+            @Nonnull Lab lab, @Nonnull List<BlueprintLayer> layers, Boolean optional, boolean outcome)
+                    throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException,
+                    UniformInterfaceException, NoSuchAlgorithmException, NullPointerException, IOException, ParseException {
+        String siloText = null;
+        for (LabSilo silo : siloService.getSilos()) {
+            if (silo.getLab().getLab().equals(lab)) {
+                siloText = silo.getSilo();
+            }
+        }
+        if (siloText == null) {
+            throw new IllegalArgumentException("Lab does not exist: " + lab.toString());
+        }
+        return nexusService.getLastResultBasedOnOutcome(name, version, siloText, layers, optional, outcome);
+    }
+
+    public List<ValidationNexusTestResult> getBasedOnDateFromNexus(@Nonnull String name, @Nonnull String version,
+            @Nonnull Lab lab, @Nonnull Date date)
+                    throws JsonParseException, JsonMappingException, IOException, ParseException, KeyManagementException,
+                    ClientHandlerException, UniformInterfaceException, NoSuchAlgorithmException, NullPointerException {
+        String siloText = null;
+        for (LabSilo silo : siloService.getSilos()) {
+            if (silo.getLab().getLab().equals(lab)) {
+                siloText = silo.getSilo();
+            }
+        }
+        if (siloText == null) {
+            throw new IllegalArgumentException("Lab does not exist: " + lab.toString());
+        }
+        return nexusService.getResults(name, version, siloText, date);
+    }
+
+    public Set<Lab> getLabsFromDb() {
+        Set<Lab> labs = new HashSet<Lab>();
+        for (ValidationDbTestResult result : dbAdapter.getValidationTestResults()) {
+            labs.add(result.getLab().getLab());
+        }
+        return labs;
+    }
+
+    public Set<String> getBlueprintNamesOfLabFromDb(Lab lab) {
+        Set<String> blueprintNames = new HashSet<String>();
+        for (ValidationDbTestResult result : dbAdapter.getValidationTestResults()) {
+            if (result.getLab().getLab().equals(lab)) {
+                blueprintNames.add(result.getBlueprintName());
+            }
+        }
+        return blueprintNames;
+    }
+
+    public Set<String> getBlueprintVersionsFromDb(String name, Lab lab) {
+        Set<String> blueprintVersions = new HashSet<String>();
+        for (ValidationDbTestResult result : dbAdapter.getValidationTestResults()) {
+            if (result.getLab().getLab().equals(lab) && result.getBlueprintName().equals(name)) {
+                blueprintVersions.add(result.getVersion());
+            }
+        }
+        return blueprintVersions;
+    }
+
+    public ValidationNexusTestResult getResults(@Nonnull String submissionId)
+            throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException,
+            UniformInterfaceException, NoSuchAlgorithmException, IOException, NullPointerException, ParseException {
+        SubmissionData submissionData = submissionService.getSubmissionData(submissionId);
+        ValidationNexusTestResult vNexusResult = dbAdapter.readResultFromDb(submissionId);
+        return vNexusResult == null
+                ? this.getResultFromNexus(submissionData.getValidationNexusTestResult().getBlueprintName(),
+                        submissionData.getValidationNexusTestResult().getVersion(),
+                        submissionData.getTimeslot().getLab().getLab(),
+                        submissionData.getValidationNexusTestResult().getTimestamp())
+                        : vNexusResult;
+    }
+
+    public ValidationNexusTestResult getResult(@Nonnull String name, @Nonnull String version, @Nonnull Lab lab,
+            @Nonnull String timestamp)
+                    throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException,
+                    UniformInterfaceException, NoSuchAlgorithmException, NullPointerException, IOException, ParseException {
+        LabInfo actualLabInfo = labService.getLab(lab);
+        if (actualLabInfo == null) {
+            return null;
+        }
+        ValidationNexusTestResult vNexusResult = dbAdapter.readResultFromDb(lab, timestamp);
+        return vNexusResult == null ? this.getResultFromNexus(name, version, lab, timestamp) : vNexusResult;
+    }
+
+    public ValidationNexusTestResult getLastResultBasedOnOutcome(@Nonnull String name, @Nonnull String version,
+            @Nonnull Lab lab, Boolean allLayers, Boolean optional, boolean outcome)
+                    throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException,
+                    UniformInterfaceException, NoSuchAlgorithmException, IOException, NullPointerException, ParseException {
+        LabInfo actualLabInfo = labService.getLab(lab);
+        if (actualLabInfo == null) {
+            return null;
+        }
+        List<ValidationNexusTestResult> vNexusResults = dbAdapter.readResultFromDb(name, version, lab, null, allLayers,
+                optional, outcome);
+        if (vNexusResults != null) {
+            vNexusResults.removeIf(entry -> entry.getDateOfStorage() == null);
+            DateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
+            Collections.sort(vNexusResults, new Comparator<ValidationNexusTestResult>() {
+                @Override
+                public int compare(ValidationNexusTestResult vNexusResult1, ValidationNexusTestResult vNexusResult2) {
+                    try {
+                        return dateFormat.parse(vNexusResult2.getDateOfStorage())
+                                .compareTo(dateFormat.parse(vNexusResult1.getDateOfStorage()));
+                    } catch (ParseException e) {
+                        LOGGER.error(EELFLoggerDelegate.errorLogger,
+                                "Error when parsing date. " + UserUtils.getStackTrace(e));
+                        return 0;
+                    }
+                }
+            });
+            return vNexusResults.get(0);
+        }
+        return this.getLastResultBasedOnOutcomeFromNexus(name, version, lab, allLayers, optional, outcome);
+    }
+
+    public ValidationNexusTestResult getLastResultBasedOnOutcome(@Nonnull String name, @Nonnull String version,
+            @Nonnull Lab lab, List<BlueprintLayer> layers, Boolean optional, boolean outcome)
+                    throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException,
+                    UniformInterfaceException, NoSuchAlgorithmException, IOException, NullPointerException, ParseException {
+        LabInfo actualLabInfo = labService.getLab(lab);
+        if (actualLabInfo == null) {
+            return null;
+        }
+        List<ValidationNexusTestResult> vNexusResults = dbAdapter.readResultFromDb(name, version, lab, layers, null,
+                optional, outcome);
+        if (vNexusResults != null) {
+            vNexusResults.removeIf(entry -> entry.getDateOfStorage() == null);
+            DateFormat dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
+            Collections.sort(vNexusResults, new Comparator<ValidationNexusTestResult>() {
+                @Override
+                public int compare(ValidationNexusTestResult vNexusResult1, ValidationNexusTestResult vNexusResult2) {
+                    try {
+                        return dateFormat.parse(vNexusResult2.getDateOfStorage())
+                                .compareTo(dateFormat.parse(vNexusResult1.getDateOfStorage()));
+                    } catch (ParseException e) {
+                        LOGGER.error(EELFLoggerDelegate.errorLogger,
+                                "Error when parsing date. " + UserUtils.getStackTrace(e));
+                        return 0;
+                    }
+                }
+            });
+            return vNexusResults.get(0);
+        }
+        return this.getLastResultBasedOnOutcomeFromNexus(name, version, lab, layers, optional, outcome);
+    }
+
+}
index c2482b2..429696a 100644 (file)
  */
 package org.akraino.validation.ui.service;
 
-import org.akraino.validation.ui.conf.UiUtils;
-import org.akraino.validation.ui.data.BlueprintLayer;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.akraino.validation.ui.client.nexus.resources.ValidationNexusTestResult;
+import org.akraino.validation.ui.dao.ValidationTestResultDAO;
 import org.akraino.validation.ui.data.JnksJobNotify;
 import org.akraino.validation.ui.data.SubmissionStatus;
 import org.akraino.validation.ui.entity.LabSilo;
 import org.akraino.validation.ui.entity.Submission;
+import org.akraino.validation.ui.entity.ValidationDbTestResult;
 import org.akraino.validation.ui.service.utils.SubmissionHelper;
 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -37,11 +41,20 @@ public class JenkinsJobNotificationService {
     private SubmissionHelper submissionHelper;
 
     @Autowired
-    private SubmissionService submissionService;
+    private DbSubmissionAdapter submissionService;
 
     @Autowired
     private SiloService siloService;
 
+    @Autowired
+    private DbResultAdapter dbAdapter;
+
+    @Autowired
+    private IntegratedResultService iService;
+
+    @Autowired
+    private ValidationTestResultDAO vTestResultDAO;
+
     public void handle(JnksJobNotify jnksJobNotify) throws Exception {
         String jenkinsJobName = System.getenv("JENKINS_JOB_NAME");
         if (!jenkinsJobName.equals(jnksJobNotify.getName())) {
@@ -59,20 +72,24 @@ public class JenkinsJobNotificationService {
             }
         }
         if (siloText == null) {
-            throw new Exception("Could not retrieve silo of the selected lab : "
+            throw new IllegalArgumentException("Could not retrieve silo of the selected lab : "
                     + submission.getTimeslot().getLab().getLab().toString());
         }
-
-        String nexusUrl = UiUtils.NEXUS_URL + "/" + siloText + "/job/" + System.getenv("JENKINS_JOB_NAME") + "/"
-                + String.valueOf(jnksJobNotify.getbuildNumber() + "/results");
-        if (!submission.getBlueprintInstanceForValidation().getLayer().equals(BlueprintLayer.All)) {
-            nexusUrl = nexusUrl + "/" + submission.getBlueprintInstanceForValidation().getLayer().name().toLowerCase();
-        }
-        submission.setNexusResultUrl(nexusUrl);
         LOGGER.info(EELFLoggerDelegate.applicationLogger,
                 "Updating submission with id: " + submission.getSubmissionId());
         submission.setSubmissionStatus(SubmissionStatus.Completed);
         submissionHelper.saveSubmission(submission);
+        ValidationDbTestResult vDbResult = vTestResultDAO.getValidationTestResult(submission);
+        if (vDbResult != null) {
+            ValidationNexusTestResult vNexusResult = iService.getResult(vDbResult.getBlueprintName(),
+                    vDbResult.getVersion(), vDbResult.getLab().getLab(), jnksJobNotify.getTimestamp());
+            if (vNexusResult != null) {
+                List<ValidationNexusTestResult> vNexusResults = new ArrayList<ValidationNexusTestResult>();
+                vNexusResults.add(vNexusResult);
+                dbAdapter.storeResultInDb(vNexusResults);
+            }
+        }
+        dbAdapter.updateTimestamp(jnksJobNotify);
     }
 
 }
index 8dfc15e..4280f37 100644 (file)
@@ -18,6 +18,7 @@ package org.akraino.validation.ui.service;
 import java.util.List;
 
 import org.akraino.validation.ui.dao.LabDAO;
+import org.akraino.validation.ui.data.Lab;
 import org.akraino.validation.ui.entity.LabInfo;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
@@ -31,15 +32,15 @@ public class LabService {
     private LabDAO labDAO;
 
     public void saveLab(LabInfo lab) {
-
         labDAO.saveOrUpdate(lab);
+    }
 
+    public LabInfo getLab(Lab lab) {
+        return labDAO.getLab(lab);
     }
 
     public List<LabInfo> getLabs() {
-
         return labDAO.getLabs();
-
     }
 
     public void deleteAll() {
diff --git a/ui/src/main/java/org/akraino/validation/ui/service/ResultService.java b/ui/src/main/java/org/akraino/validation/ui/service/ResultService.java
deleted file mode 100644 (file)
index b189dba..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-package org.akraino.validation.ui.service;
-
-import java.io.IOException;
-import java.net.URL;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.util.List;
-
-import org.akraino.validation.ui.client.jenkins.JenkinsExecutorClient;
-import org.akraino.validation.ui.client.jenkins.resources.QueueJobItem;
-import org.akraino.validation.ui.client.jenkins.resources.QueueJobItem.Executable;
-import org.akraino.validation.ui.client.nexus.NexusExecutorClient;
-import org.akraino.validation.ui.client.nexus.resources.WrapperRobotTestResult;
-import org.akraino.validation.ui.conf.UiUtils;
-import org.akraino.validation.ui.data.BlueprintLayer;
-import org.akraino.validation.ui.entity.LabSilo;
-import org.akraino.validation.ui.entity.Submission;
-import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.databind.JsonMappingException;
-import com.sun.jersey.api.client.ClientHandlerException;
-import com.sun.jersey.api.client.UniformInterfaceException;
-
-@Service
-public class ResultService {
-
-    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(ResultService.class);
-
-    @Autowired
-    private SubmissionService submissionService;
-
-    @Autowired
-    private SiloService siloService;
-
-    @Deprecated
-    public URL getNexusResultUrl(Submission submission) throws Exception {
-
-        String url = System.getenv("JENKINS_URL");
-        String userName = System.getenv("JENKINS_USERNAME");
-        String password = System.getenv("JENKINS_USER_PASSWORD");
-
-        Executable executable = null;
-        while (executable == null) {
-            JenkinsExecutorClient client;
-            client = JenkinsExecutorClient.getInstance(userName, password, url);
-            QueueJobItem queueJobItem = client.getQueueJobItem(new URL(submission.getJenkinsQueueJobItemUrl()));
-            executable = queueJobItem.getExecutable();
-            Thread.sleep(2000);
-        }
-        String siloText = null;
-        for (LabSilo silo : siloService.getSilos()) {
-            if (silo.getLab().getLab().equals(submission.getTimeslot().getLab().getLab())) {
-                siloText = silo.getSilo();
-            }
-        }
-        if (siloText == null) {
-            throw new Exception("Could not retrieve silo of the selected lab : "
-                    + submission.getTimeslot().getLab().getLab().toString());
-        }
-        String nexusUrl = UiUtils.NEXUS_URL + "/" + siloText + "/job/" + System.getenv("JENKINS_JOB_NAME") + "/"
-                + String.valueOf(executable.getNumber() + "/results");
-        if (!submission.getBlueprintInstanceForValidation().getLayer().equals(BlueprintLayer.All)) {
-            nexusUrl = nexusUrl + "/" + submission.getBlueprintInstanceForValidation().getLayer().name().toLowerCase();
-        }
-        return new URL(nexusUrl);
-    }
-
-    public List<WrapperRobotTestResult> getRobotTestResults(String submissionId)
-            throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException,
-            UniformInterfaceException, NoSuchAlgorithmException, IOException {
-        Submission submission = submissionService.getSubmission(submissionId);
-        if (submission == null) {
-            LOGGER.info(EELFLoggerDelegate.applicationLogger, "Requested submission does not exist");
-            return null;
-        }
-        String nexusUrl = submission.getNexusResultUrl();
-        String urlLastpart = nexusUrl.substring(nexusUrl.lastIndexOf('/') + 1);
-        if (blueprintLayerContains(urlLastpart.substring(0, 1).toUpperCase() + urlLastpart.substring(1))) {
-            nexusUrl = nexusUrl.substring(0, nexusUrl.lastIndexOf(urlLastpart) - 1);
-        }
-        NexusExecutorClient client = new NexusExecutorClient(nexusUrl);
-        return client.getRobotTestResults();
-    }
-
-    private boolean blueprintLayerContains(String layer) {
-        for (BlueprintLayer blueprintLayer : BlueprintLayer.values()) {
-            if (blueprintLayer.name().equals(layer)) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-}
index 16ebe30..23332d7 100644 (file)
@@ -31,15 +31,11 @@ public class SiloService {
     private SiloDAO siloDAO;
 
     public void saveSilo(LabSilo silo) {
-
         siloDAO.saveOrUpdate(silo);
-
     }
 
     public List<LabSilo> getSilos() {
-
         return siloDAO.getSilos();
-
     }
 
     public void deleteAll() {
diff --git a/ui/src/main/java/org/akraino/validation/ui/service/SubmissionService.java b/ui/src/main/java/org/akraino/validation/ui/service/SubmissionService.java
deleted file mode 100644 (file)
index ccf4087..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may
- * not use this file except in compliance with the License. You may obtain
- * a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- * implied. See the License for the specific language governing
- * permissions and limitations under the License.
- */
-package org.akraino.validation.ui.service;
-
-import java.net.DatagramSocket;
-import java.net.InetAddress;
-import java.net.MalformedURLException;
-import java.net.SocketException;
-import java.net.UnknownHostException;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-import java.util.concurrent.CompletableFuture;
-
-import org.akraino.validation.ui.client.jenkins.JenkinsExecutorClient;
-import org.akraino.validation.ui.client.jenkins.resources.Parameter;
-import org.akraino.validation.ui.client.jenkins.resources.Parameters;
-import org.akraino.validation.ui.conf.UiUtils;
-import org.akraino.validation.ui.dao.SubmissionDAO;
-import org.akraino.validation.ui.data.SubmissionStatus;
-import org.akraino.validation.ui.entity.Submission;
-import org.akraino.validation.ui.service.utils.PrioritySupplier;
-import org.akraino.validation.ui.service.utils.SubmissionHelper;
-import org.apache.commons.httpclient.HttpException;
-import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
-import org.onap.portalsdk.core.web.support.UserUtils;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import com.sun.jersey.api.client.ClientHandlerException;
-import com.sun.jersey.api.client.UniformInterfaceException;
-
-@Service
-@Transactional
-public class SubmissionService {
-
-    private static final EELFLoggerDelegate LOGGER = EELFLoggerDelegate.getLogger(SubmissionService.class);
-
-    @Autowired
-    private SubmissionDAO submissionDAO;
-
-    @Autowired
-    private SubmissionHelper submissionHelper;
-
-    public Submission saveSubmission(Submission submission) {
-        submission.setSubmissionStatus(SubmissionStatus.Submitted);
-        submissionDAO.saveOrUpdate(submission);
-
-        JenkinsTriggerSubmissionJob task = new JenkinsTriggerSubmissionJob(submission);
-        CompletableFuture<Submission> completableFuture =
-                CompletableFuture.supplyAsync(new PrioritySupplier<>(1, task::execute), UiUtils.executorService);
-        completableFuture.thenAcceptAsync(result -> this.callbackNotify(result));
-
-        return submission;
-    }
-
-    public List<Submission> getSubmissions() {
-        return submissionDAO.getSubmissions();
-    }
-
-    public Submission getSubmission(String submissionId) {
-        return submissionDAO.getSubmission(Integer.valueOf(submissionId));
-    }
-
-    public void deleteSubmission(Integer submissionId) {
-        submissionDAO.deleteSubmission(submissionId);
-    }
-
-    public void deleteAll() {
-        submissionDAO.deleteAll();
-    }
-
-    private void callbackNotify(Submission submission) {
-        if (submission == null) {
-            return;
-        }
-        submission.setSubmissionStatus(SubmissionStatus.Running);
-        submissionHelper.saveSubmission(submission);
-    }
-
-    private class JenkinsTriggerSubmissionJob {
-
-        private Submission submission;
-
-        public JenkinsTriggerSubmissionJob(Submission submission) {
-            this.submission = submission;
-        }
-
-        public Submission execute() {
-            String url = System.getenv("JENKINS_URL");
-            String userName = System.getenv("JENKINS_USERNAME");
-            String userPassword = System.getenv("JENKINS_USER_PASSWORD");
-            String jobName = System.getenv("JENKINS_JOB_NAME");
-            List<Parameter> listOfParameters = new ArrayList<Parameter>();
-            Parameters parameters = new Parameters();
-            Parameter parameter = new Parameter();
-            parameter.setName("SUBMISSION_ID");
-            parameter.setValue(String.valueOf(submission.getSubmissionId()));
-            listOfParameters.add(parameter);
-            parameter = new Parameter();
-            parameter.setName("BLUEPRINT");
-            parameter.setValue(
-                    submission.getBlueprintInstanceForValidation().getBlueprint().getBlueprintName().toLowerCase());
-            listOfParameters.add(parameter);
-            parameter = new Parameter();
-            parameter.setName("LAYER");
-            parameter.setValue(submission.getBlueprintInstanceForValidation().getLayer().name().toLowerCase());
-            listOfParameters.add(parameter);
-            parameter = new Parameter();
-            parameter.setName("VERSION");
-            parameter.setValue(submission.getBlueprintInstanceForValidation().getVersion().toLowerCase());
-            listOfParameters.add(parameter);
-            parameter = new Parameter();
-            parameter.setName("UI_IP");
-            Random random = new Random();
-            String localIP = null;
-            try (final DatagramSocket socket = new DatagramSocket()) {
-                socket.connect(InetAddress.getByName(random.nextInt(256) + "." + random.nextInt(256) + "."
-                        + random.nextInt(256) + "." + random.nextInt(256)), 10002);
-                localIP = socket.getLocalAddress().getHostAddress();
-                parameter.setValue(localIP);
-                listOfParameters.add(parameter);
-                parameters.setParameter(listOfParameters);
-                JenkinsExecutorClient client;
-                client = JenkinsExecutorClient.getInstance(userName, userPassword, url);
-                submission.setJnksQueueJobItemUrl(client.postJobWithQueryParams(jobName, parameters).toString());
-                return submission;
-            } catch (SocketException | UnknownHostException | KeyManagementException | HttpException
-                    | ClientHandlerException | UniformInterfaceException | MalformedURLException
-                    | NoSuchAlgorithmException e) {
-                LOGGER.error(EELFLoggerDelegate.errorLogger,
-                        "Error when triggering Jenkins job. " + UserUtils.getStackTrace(e));
-                return null;
-            }
-        }
-    }
-
-}
index 8df150d..6445d7f 100644 (file)
@@ -31,15 +31,11 @@ public class TimeslotService {
     private TimeslotDAO timeslotDAO;
 
     public void saveTimeslot(Timeslot timeslot) {
-
         timeslotDAO.saveOrUpdate(timeslot);
-
     }
 
     public List<Timeslot> getTimeslots() {
-
         return timeslotDAO.getTimeslots();
-
     }
 
     public void deleteAll() {
index 8e45d73..8f5bf7e 100644 (file)
@@ -33,4 +33,8 @@ public class SubmissionHelper {
         return submission;
     }
 
+    public Submission getSubmission(int submissionId) {
+        return submissionDAO.getSubmission(submissionId);
+    }
+
 }
index 9c7102e..391f5a9 100644 (file)
@@ -46,7 +46,7 @@
   <!--<jmxConfigurator /> -->
 
   <!--  specify the component name -->
-  <property name="componentName" value="AECBlueprintValidationUI"></property>
+  <property name="componentName" value="bluvalui"></property>
 
   <!--  specify the base path of the log directory -->
   <property name="logDirPrefix" value="${catalina.base}/logs"></property>
index f5c824a..ed2de35 100644 (file)
@@ -13,8 +13,8 @@ music.cleanup.frequency = 6
 #how old of session need to be cleaned up (hour)
 music.cleanup.threshold = 10
 music.enable = false
-cassandra.host=135.197.226.103
-zookeeper.host=135.197.226.103, 135.197.226.108, 135.197.226.119
+cassandra.host=localhost
+zookeeper.host=localhost1,localhost2,localhost3
 cassandra.user=cassandra
 cassandra.password=cassandra
 
index 5434599..b6c0dc1 100644 (file)
@@ -68,3 +68,15 @@ ueb_listeners_enable = false
 # If key ueb_listeners_enable is set to false,
 # then only the ueb_app_key is required.
 ueb_app_key = REPLACE-ME-UEB-APP-KEY-EPSDK-APP-OS
+
+# Name of the akraino database
+akraino_database_name = akraino
+
+# Nexus URL
+nexus_url = https://nexus.akraino.org/content/sites/logs
+
+# Sleep time of threads in milliseconds
+thread_sleep = 5000
+
+# Number of last timestamps to retrieve proactively from Nexus
+no_last_timestamps = 50
\ No newline at end of file
index 6276357..fa26104 100644 (file)
@@ -39,7 +39,7 @@ decryption_key                = AGLDdG4D04BKm2IxIWEr8o==
 
 #Mysql
 db.driver =  org.mariadb.jdbc.Driver
-db.userName = root
+db.userName = akraino
 db.encrypt_flag = false
 db.hib.dialect = org.hibernate.dialect.MySQLDialect
 db.min_pool_size = 5
index ec0ec0d..f64ea8f 100644 (file)
 
 <tiles-definitions>
 
-    <definition name="newSubmission"
-        template="/app/AECBlueprintValidationUI/NewSubmission/NewSubmission.html" />
+    <definition name="newsubmission"
+        template="/app/BluvalUI/NewSubmission/NewSubmission.html" />
 
-    <definition name="committedSubmissions"
-        template="/app/AECBlueprintValidationUI/CommittedSubmissions/CommittedSubmissions.html" />
+    <definition name="committedsubmissions"
+        template="/app/BluvalUI/CommittedSubmissions/CommittedSubmissions.html" />
 
-    <definition name="getBySubmissionId"
-        template="/app/AECBlueprintValidationUI/GetBySubmissionId/GetBySubmissionId.html" />
+    <definition name="getmostrecent"
+        template="/app/BluvalUI/GetMostRecent/GetMostRecent.html" />
+
+    <definition name="getbytimestamp"
+        template="/app/BluvalUI/GetByTimestamp/GetByTimestamp.html" />
+
+    <definition name="getlastrun"
+        template="/app/BluvalUI/GetLastRun/GetLastRun.html" />
+
+    <definition name="getbasedondate"
+        template="/app/BluvalUI/GetBasedOnDate/GetBasedOnDate.html" />
+
+    <definition name="validationresults"
+        template="/app/BluvalUI/ValidationResults/ValidationResults.html" />
 
 </tiles-definitions>
index c5b43e0..b1554a7 100644 (file)
@@ -23,92 +23,105 @@ limitations under the License.
 %>
 
 <html>
-       <head>
-               <meta charset="utf-8">
-               <meta http-equiv="X-UA-Compatible" content="IE=edge">
-               <meta name="viewport" content="width=device-width, initial-scale=1">
-               <title>Login</title>
-               <style>
-               html {
-                       font-family: Verdana, Arial, Helvetica, sans-serif;
-               }
-               body {
-                       padding-top: 15px;
-               }
-               .logo {
-                       position: fixed;
-                       left: 15px;
-                       top: 15px;
-                       z-index: -1;
-               }
-               .loginError {
-                       font-size: 18px;
-                       color: red;
-                       text-align: center;
-               }
-               .login {
-                       font-size: 16px;
-                       display: block;
-                       margin-left: auto;
-                       margin-right: auto;
-                       text-align: center;
-                       width: 100%;
-               }
-               .login input[type=submit] {
-                       font-size: 16px;
-               }
-               .terms {
-                       font-size: 10px;
-                       text-align: center;
-                       margin-left: auto;
-                       margin-right: auto;
-               }
-               .terms a {
-                       font-size: 10px;
-                       text-align: center;
-                       margin-left: auto;
-                       margin-right: auto;
-               }
-               </style>
-       </head>
-       <body>
-               <div class="login">
-                       <img src="static/fusion/images/logo_akraino_edge_stack.png" alt="Akraino" width="400&quot;" height="114" border="0" />
-                       <h2>
-                               <%=appDisplayName%>
-                       </h2>
-                       <br />
-                       <form action="do_login_external" method="POST">
-                               <label for="loginId">Login ID:</label>
-                               <input id="loginId" name="loginId" type="text" style="width: 140px;height:25px;border-radius:7px;font-size:18px;padding-left:5px;" maxlength="30">
-                               <br/>
-                               <br/>
-                               <label for="password">Password:</label>
-                               <input id="password" name="password" type="password" style="width: 140px;height:25px;border-radius:7px;font-size:18px;padding-left:5px;"
-                                                       maxlength="30" >
-                               <br />
-                               <br />
-                               <input id="loginBtn" type="submit" alt="Login" value="Login">
-                       </form>
-               </div>
-               <br />
-               <br />
-               <div class="loginError">${model.error}</div>
-               <br />
-               <br />
-               <br />
-               <br />
-               <br />
-               <br />
-               <div id="footer">
-                       <div class="terms">
-                       Copyright <script>new Date().getFullYear()>2017&&document.write(new Date().getFullYear());</script>
-                               Akraino Edge Stack and Linux Foundation.
-                       </div>
-                       <p>
-                       <div class="terms">
 
-                       </div>
-               </div>
-       </body>
-</html>
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>Login</title>
+    <style>
+        html {
+            font-family: Verdana, Arial, Helvetica, sans-serif;
+        }
+
+        body {
+            padding-top: 15px;
+        }
+
+        .logo {
+            position: fixed;
+            left: 15px;
+            top: 15px;
+            z-index: -1;
+        }
+
+        .loginError {
+            font-size: 18px;
+            color: red;
+            text-align: center;
+        }
+
+        .login {
+            font-size: 16px;
+            display: block;
+            margin-left: auto;
+            margin-right: auto;
+            text-align: center;
+            width: 100%;
+        }
+
+        .login input[type=submit] {
+            font-size: 16px;
+        }
+
+        .terms {
+            font-size: 10px;
+            text-align: center;
+            margin-left: auto;
+            margin-right: auto;
+        }
+
+        .terms a {
+            font-size: 10px;
+            text-align: center;
+            margin-left: auto;
+            margin-right: auto;
+        }
+    </style>
+</head>
+
+<body>
+    <div class="login">
+        <img src="static/fusion/images/logo_akraino_edge_stack.png" alt="Akraino" width="400&quot;" height="114"
+            border="0" />
+        <h2>
+            <%=appDisplayName%>
+        </h2>
+        <br />
+        <form action="do_login_external" method="POST">
+            <label for="loginId">Login ID:</label>
+            <input id="loginId" name="loginId" type="text"
+                style="width: 140px;height:25px;border-radius:7px;font-size:18px;padding-left:5px;" maxlength="30">
+            <br />
+            <br />
+            <label for="password">Password:</label>
+            <input id="password" name="password" type="password"
+                style="width: 140px;height:25px;border-radius:7px;font-size:18px;padding-left:5px;" maxlength="30">
+            <br />
+            <br />
+            <input id="loginBtn" type="submit" alt="Login" value="Login">
+        </form>
+    </div>
+    <br />
+    <br />
+    <div class="loginError">${model.error}</div>
+    <br />
+    <br />
+    <br />
+    <br />
+    <br />
+    <br />
+    <div id="footer">
+        <div class="terms">
+            Copyright
+            <script>new Date().getFullYear() > 2017 && document.write(new Date().getFullYear());</script>
+            Akraino Edge Stack and Linux Foundation.
+        </div>
+        <p>
+            <div class="terms">
+
+            </div>
+    </div>
+</body>
+
+</html>
\ No newline at end of file
index 9d389d0..a007d05 100644 (file)
@@ -23,92 +23,105 @@ limitations under the License.
 %>
 
 <html>
-       <head>
-               <meta charset="utf-8">
-               <meta http-equiv="X-UA-Compatible" content="IE=edge">
-               <meta name="viewport" content="width=device-width, initial-scale=1">
-               <style>
-               html {
-                       font-family: Verdana, Arial, Helvetica, sans-serif;
-               }
-               body {
-                       padding-top: 15px;
-               }
-               .logo {
-                       position: fixed;
-                       left: 15px;
-                       top: 15px;
-                       z-index: -1;
-               }
-               .loginError {
-                       font-size: 18px;
-                       color: red;
-                       text-align: center;
-               }
-               .login {
-                       font-size: 16px;
-                       display: block;
-                       margin-left: auto;
-                       margin-right: auto;
-                       text-align: center;
-                       width: 100%;
-               }
-               .login input[type=submit] {
-                       font-size: 16px;
-               }
-               .terms {
-                       font-size: 10px;
-                       text-align: center;
-                       margin-left: auto;
-                       margin-right: auto;
-               }
-               .terms a {
-                       font-size: 10px;
-                       text-align: center;
-                       margin-left: auto;
-                       margin-right: auto;
-               }
-               </style>
-       </head>
-       <body>
-
-               <div class="login">
-                       <img src="static/fusion/images/logo_akraino_edge_stack.png" alt="Akraino" width="400&quot;" height="114" border="0"/>
-                       <h2>
-                               <%=appDisplayName%>
-                       </h2>
-                       <br />
-                       <form action="login_external" method="POST">
-                               <label for="loginId">Login ID:</label>
-                               <input id="loginId" name="loginId" type="text" style="width: 140px;height:25px;border-radius:7px;font-size:18px;padding-left:5px;" maxlength="30">
-                               <br/>
-                               <br/>
-                               <label for="password">Password:</label>
-                               <input id="password" name="password" type="password" style="width: 140px;height:25px;border-radius:7px;font-size:18px;padding-left:5px;"
-                                                       maxlength="30" >
-                               <br />
-                               <br />
-                               <input id="loginBtn" type="submit" alt="Login" value="Login">
-                       </form>
-               </div>
-               <br />
-               <br />
-               <div class="loginError">${model.error}</div>
-               <br />
-               <br />
-               <br />
-               <br />
-               <br />
-               <br />
-               <div id="footer">
-                       <div class="terms">
-                       Copyright <script>new Date().getFullYear()>2017&&document.write(new Date().getFullYear());</script>
-                               Akraino Edge Stack and Linux Foundation.
-                       </div>
-                       <p>
-                       <div class="terms">
-
-                       </div>
-               </div>
-       </body>
-</html>
+
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <style>
+        html {
+            font-family: Verdana, Arial, Helvetica, sans-serif;
+        }
+
+        body {
+            padding-top: 15px;
+        }
+
+        .logo {
+            position: fixed;
+            left: 15px;
+            top: 15px;
+            z-index: -1;
+        }
+
+        .loginError {
+            font-size: 18px;
+            color: red;
+            text-align: center;
+        }
+
+        .login {
+            font-size: 16px;
+            display: block;
+            margin-left: auto;
+            margin-right: auto;
+            text-align: center;
+            width: 100%;
+        }
+
+        .login input[type=submit] {
+            font-size: 16px;
+        }
+
+        .terms {
+            font-size: 10px;
+            text-align: center;
+            margin-left: auto;
+            margin-right: auto;
+        }
+
+        .terms a {
+            font-size: 10px;
+            text-align: center;
+            margin-left: auto;
+            margin-right: auto;
+        }
+    </style>
+</head>
+
+<body>
+
+    <div class="login">
+        <img src="static/fusion/images/logo_akraino_edge_stack.png" alt="Akraino" width="400&quot;" height="114"
+            border="0" />
+        <h2>
+            <%=appDisplayName%>
+        </h2>
+        <br />
+        <form action="login_external" method="POST">
+            <label for="loginId">Login ID:</label>
+            <input id="loginId" name="loginId" type="text"
+                style="width: 140px;height:25px;border-radius:7px;font-size:18px;padding-left:5px;" maxlength="30">
+            <br />
+            <br />
+            <label for="password">Password:</label>
+            <input id="password" name="password" type="password"
+                style="width: 140px;height:25px;border-radius:7px;font-size:18px;padding-left:5px;" maxlength="30">
+            <br />
+            <br />
+            <input id="loginBtn" type="submit" alt="Login" value="Login">
+        </form>
+    </div>
+    <br />
+    <br />
+    <div class="loginError">${model.error}</div>
+    <br />
+    <br />
+    <br />
+    <br />
+    <br />
+    <br />
+    <div id="footer">
+        <div class="terms">
+            Copyright
+            <script>new Date().getFullYear() > 2017 && document.write(new Date().getFullYear());</script>
+            Akraino Edge Stack and Linux Foundation.
+        </div>
+        <p>
+            <div class="terms">
+
+            </div>
+    </div>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/ui/src/main/webapp/WEB-INF/jsp/logout.jsp b/ui/src/main/webapp/WEB-INF/jsp/logout.jsp
new file mode 100644 (file)
index 0000000..b92ceb3
--- /dev/null
@@ -0,0 +1,60 @@
+<%--
+  ============LICENSE_START==========================================
+  ONAP Portal SDK
+  ===================================================================
+  Copyright Ã‚© 2017 AT&T Intellectual Property. All rights reserved.
+  ===================================================================
+
+  Unless otherwise specified, all software contained herein is licensed
+  under the Apache License, Version 2.0 (the Ã¢â‚¬Å“Licenseâ€\9d);
+  you may not use this software except in compliance with the License.
+  You may obtain a copy of the License at
+
+              http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  Unless otherwise specified, all documentation contained herein is licensed
+  under the Creative Commons License, Attribution 4.0 Intl. (the Ã¢â‚¬Å“Licenseâ€\9d);
+  you may not use this documentation except in compliance with the License.
+  You may obtain a copy of the License at
+
+              https://creativecommons.org/licenses/by/4.0/
+
+  Unless required by applicable law or agreed to in writing, documentation
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+  ============LICENSE_END============================================
+
+
+  --%>
+<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
+<%@ page import="java.net.URLEncoder"%>
+<%@ page import="org.onap.portalsdk.core.util.SystemProperties"%>
+
+<%-- Redirected because we can't set the welcome page to a virtual URL. --%>
+<%-- Forward to the intended start page to reduce frustration for new users. --%>
+
+<%
+        String scheme = request.getScheme() + "://";
+        String servername = request.getServerName();
+        Integer urlPort = request.getServerPort();
+        String contextPath = request.getContextPath();
+        String htmFile = "/login.htm";
+        request.getSession().invalidate();
+        String redirectURL = "";
+        redirectURL = redirectURL + scheme + servername;
+        if ((urlPort != null) && (urlPort.intValue() != 80) && (urlPort.intValue() != 443)
+                        && (urlPort.intValue() != -1)) {
+                redirectURL += ":" + urlPort;
+        }
+        redirectURL += contextPath + htmFile;
+%>
+<c:redirect url="<%=redirectURL%>"></c:redirect>
\ No newline at end of file
index 92a2d59..2071632 100644 (file)
@@ -12,7 +12,7 @@
     xmlns:web="http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
     version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee">
 
-    <display-name>AECBlueprintValidationUI</display-name>
+    <display-name>bluvalui</display-name>
 
     <!-- The app can function on a HA cluster -->
     <distributable />
diff --git a/ui/src/main/webapp/app/AECBlueprintValidationUI/App.Services.js b/ui/src/main/webapp/app/AECBlueprintValidationUI/App.Services.js
deleted file mode 100644 (file)
index 8fa4ce6..0000000
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var services = angular.module('App.Services', [ 'App.Config' ]);
-
-services.factory('restAPISvc', [
-        '$http',
-        'appContext',
-        function($http, appContext) {
-            var svc = [];
-            svc.getRestAPI = function(path, cb) {
-                return $http({
-                    method : 'GET',
-                    url : appContext + path,
-                    headers : {
-                        'Content-Type' : "application/json",
-                        'Accept' : "application/json"
-                    }
-                }).then(
-                        function(response) {
-                            if (response.status == 200) {
-                                cb(response.data);
-                            } else {
-                                /* eslint-disable no-console */
-                                console.log("Get REST API error: "
-                                        + response.statusText);
-                                /* eslint-enable no-console */
-                                cb(null);
-                            }
-                        },
-                        function(error) {
-                            /* eslint-disable no-console */
-                            console.log("Get REST API error: "
-                                    + error.statusText);
-                            /* eslint-enable no-console */
-                            cb(null);
-                        });
-            };
-            svc.postRestAPI = function(path, json, cb) {
-                return $http({
-                    method : 'POST',
-                    url : appContext + path,
-                    headers : {
-                        'Content-Type' : "application/json",
-                        'Accept' : "application/json"
-                    },
-                    data : json
-                }).then(
-                        function(response) {
-                            if (response.status == 200
-                                    || response.status == 201) {
-                                cb(response.data);
-                            } else {
-                                /* eslint-disable no-console */
-                                console.log("Post REST API error: "
-                                        + response.statusText);
-                                /* eslint-enable no-console */
-                                cb(null);
-                            }
-                        },
-                        function(error) {
-                            /* eslint-disable no-console */
-                            console.log("Post REST API error: "
-                                    + error.statusText);
-                            /* eslint-enable no-console */
-                            cb(null);
-                        });
-            };
-            svc.deleteRestAPI = function(path, json) {
-                return $http({
-                    method : 'DELETE',
-                    url : appContext + path,
-                    headers : {
-                        'Content-Type' : "application/json",
-                        'Accept' : "application/json"
-                    },
-                    data : json
-                }).then(
-                        function(response) {
-                            if (response.status !== 200) {
-                                /* eslint-disable no-console */
-                                console.log("Delete REST API error: "
-                                        + response.statusText);
-                                /* eslint-enable no-console */
-                            }
-                        },
-                        function(error) {
-                            /* eslint-disable no-console */
-                            console.log("Delete REST API error: "
-                                    + error.statusText);
-                            /* eslint-enable no-console */
-                        });
-            };
-            return svc;
-        } ]);
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/AECBlueprintValidationUI/CommittedSubmissions/AECCommittedSubmissionsController.js b/ui/src/main/webapp/app/AECBlueprintValidationUI/CommittedSubmissions/AECCommittedSubmissionsController.js
deleted file mode 100644 (file)
index 27d4a14..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var app = angular.module('AECCommittedSubmissions');
-
-app.controller('AECCommittedSubmissionsController', function($scope,
-        restAPISvc, $interval, refreshPeriod) {
-
-    restAPISvc.getRestAPI("/api/submission/", function(data) {
-        $scope.submissions = data;
-    });
-
-    $scope.refreshCommittedSubmissions = function() {
-        restAPISvc.getRestAPI("/api/submission/", function(data) {
-            $scope.submissions = data;
-        });
-    }
-
-    $interval(function() {
-        $scope.refreshCommittedSubmissions();
-    }, refreshPeriod);
-
-});
diff --git a/ui/src/main/webapp/app/AECBlueprintValidationUI/CommittedSubmissions/CommittedSubmissionsTemplate.html b/ui/src/main/webapp/app/AECBlueprintValidationUI/CommittedSubmissions/CommittedSubmissionsTemplate.html
deleted file mode 100644 (file)
index b2e3838..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-<!--
-Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-<div id="page-content" class="content" style="padding: 25px;">
-
- <style>
-.grid {
-    width: 100%;
-    height: 400px;
-}
-
-.grid .ui-grid-header-cell {
-    text-align: center;
-}
-
-.icon-add-widget:before {
-    content: "\e717";
-}
-
-.ui-grid-icon-angle-down {
-    margin-top: 5px;
-}
-
-body {
-    font-size: 13px;
-}
-</style>
-
- <h1 class="heading-page">Committed Submissions</h1>
-
- <br>
-
- <div>
-  <label style="float: left; margin-top: 10px; margin-right: 10px;">Submission
-   Id:</label>
-  <div class="form-field form-field__glued pull-left size-onefifth"
-   style="float: left; width: 220px; margin-right: 20px;">
-   <input ng-model="filterSubmission.submissionId" type="text"
-    placeholder="Search for submission id?"
-    style="margin-top: 5px; width: 220px;">
-  </div>
-
-  <label style="float: left; margin-top: 10px; margin-right: 10px;">General
-   matching string:</label>
-  <div class="form-field form-field__glued pull-left size-onefifth"
-   style="float: left; width: 260px; margin-right: 40px;">
-   <input ng-model="filterGeneralMatch" type="text" placeholder="?"
-    style="margin-top: 5px; width: 260px;">
-  </div>
-
-  <div style="float: right;">
-   <button style="margin-left: 25px; margin-top: 4px;" type="submit"
-    class="btn btn-alt btn-small"
-    ng-click="refreshCommittedSubmissions();">Refresh</button>
-  </div>
-
-  <div ui-i18n="en"
-   class="grid ui-grid ng-isolate-scope grid1560525896761" id="grid1"
-   ui-grid="gridOptions" ui-grid-pagination="">
-   <!-- TODO (c0bra): add "scoped" attr here, eventually? -->
-   <style ui-grid-style="" class="ng-binding">
-.grid1560525896761 {
-    /* Styles for the grid */
-
-}
-
-.grid1560525896761 .ui-grid-row, .grid1560525896761 .ui-grid-cell,
-    .grid1560525896761 .ui-grid-cell .ui-grid-vertical-bar {
-    height: 30px;
-}
-
-.grid1560525896761 .ui-grid-row:last-child .ui-grid-cell {
-    border-bottom-width: 0px;
-}
-
-/*
-    .ui-grid[dir=rtl] .ui-grid-viewport {
-      padding-left: px;
-    }
-    */
-.grid1560525896761 .ui-grid-coluiGrid-000W {
-    min-width: 119px;
-    max-width: 119px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-000X {
-    min-width: 119px;
-    max-width: 119px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-000Y {
-    min-width: 119px;
-    max-width: 119px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-000Z {
-    min-width: 118px;
-    max-width: 118px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-0010 {
-    min-width: 118px;
-    max-width: 118px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-0011 {
-    min-width: 118px;
-    max-width: 118px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-0012 {
-    min-width: 118px;
-    max-width: 118px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-0013 {
-    min-width: 118px;
-    max-width: 118px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-0014 {
-    min-width: 118px;
-    max-width: 118px;
-}
-
-.grid1560525896761 .ui-grid-render-container-body .ui-grid-canvas {
-    width: 1065px;
-    height: 0px;
-}
-
-.grid1560525896761 .ui-grid-render-container-body .ui-grid-header-canvas
-    {
-    width: 1080px;
-}
-
-.grid1560525896761 .ui-grid-render-container-body .ui-grid-header-canvas
-    {
-    height: inherit;
-}
-
-.grid1560525896761 .ui-grid-render-container-body .ui-grid-viewport {
-    width: 1080px;
-    height: 338px;
-}
-
-.grid1560525896761 .ui-grid-render-container-body .ui-grid-header-viewport
-    {
-    width: 1080px;
-}
-
-.grid1560525896761 .ui-grid-render-container-body .ui-grid-footer-canvas
-    {
-    width: 1080px;
-}
-
-.grid1560525896761 .ui-grid-render-container-body .ui-grid-footer-viewport
-    {
-    width: 1080px;
-}
-
-.grid1560525896761 .ui-grid-footer-aggregates-row {
-    height: 30px;
-}
-
-.grid1560525896761 .ui-grid-footer-info {
-    height: 30px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-000W {
-    min-width: 119px;
-    max-width: 119px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-000X {
-    min-width: 119px;
-    max-width: 119px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-000Y {
-    min-width: 119px;
-    max-width: 119px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-000Z {
-    min-width: 118px;
-    max-width: 118px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-0010 {
-    min-width: 118px;
-    max-width: 118px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-0011 {
-    min-width: 118px;
-    max-width: 118px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-0012 {
-    min-width: 118px;
-    max-width: 118px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-0013 {
-    min-width: 118px;
-    max-width: 118px;
-}
-
-.grid1560525896761 .ui-grid-coluiGrid-0014 {
-    min-width: 118px;
-    max-width: 118px;
-}
-
-.table-container {
-    display: inline-block;
-    height: 400px;
-    padding-top: 1.875em;
-    position: relative;
-}
-
-.table-container>div {
-    border-color: #888;
-    border-style: solid;
-    border-width: 1px 1px 2px 1px;
-    height: 1.7em;
-    left: 0;
-    position: absolute;
-    right: 0;
-    top: 0;
-}
-
-table {
-    display: block;
-    height: 400px;
-    overflow-y: auto;
-}
-
-th {
-    padding: 0 5px;
-    text-align: center;
-}
-
-th:first-child>div {
-    border-left: none;
-    padding-left: 7px;
-}
-
-th>div {
-    border-left: 2px solid #888;
-    line-height: 1.875em;
-    margin-left: -6px;
-    padding-left: 5px;
-    position: absolute;
-    top: 0;
-}
-
-td {
-    border-color: #888;
-    border-style: solid;
-    border-width: 0 1px 2px 1px;
-    padding: 5px;
-}
-</style>
-   <div class="table-container">
-    <table cellspacing="0">
-     <thead>
-      <tr>
-       <th>Id&nbsp;</th>
-       <th>Status&nbsp;</th>
-       <th>Blueprint&nbsp;</th>
-       <th>Version</th>
-       <th>Layer&nbsp;</th>
-       <th>Desired Timeslot&nbsp;</th>
-       <th>Url of result&nbsp;</th>
-      </tr>
-     </thead>
-     <tbody>
-      <tr class="border_bottom"
-       ng-repeat="submission in submissions | filter:filterGeneralMatch | filter:filterSubmission">
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        submission.submissionId }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        submission.submissionStatus }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        submission.blueprintInstanceForValidation.blueprint.blueprintName
-        }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        submission.blueprintInstanceForValidation.version }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;"><a
-        href="#" data-toggle="tooltip"
-        title="{{submission.blueprintInstanceForValidation.layerDescription}}">{{
-         submission.blueprintInstanceForValidation.layer }}</a></td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">Lab:
-        {{ submission.timeslot.lab.lab }} Start date and time: {{
-        submission.timeslot.startDateTime }} <!-- duration(in sec) :
-        {{submission.timeslot.duration}}-->
-       </td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;"><a
-        href="{{submission.nexusResultUrl }}">{{
-         submission.nexusResultUrl }}</a></td>
-      </tr>
-     </tbody>
-    </table>
-
-   </div>
-  </div>
- </div>
-
- <script>
- $(document).ready(function(){
-  $('[data-toggle="tooltip"]').tooltip();
- });
- </script>
-
-</div>
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/AECBlueprintValidationUI/GetBySubmissionId/AECGetBySubmissionIdController.js b/ui/src/main/webapp/app/AECBlueprintValidationUI/GetBySubmissionId/AECGetBySubmissionIdController.js
deleted file mode 100644 (file)
index ebad5be..0000000
+++ /dev/null
@@ -1,130 +0,0 @@
-/*
- * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *        http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var app = angular.module('AECGetBySubmissionId');
-app
-        .controller(
-                'AECGetBySubmissionIdController',
-                function($scope, restAPISvc) {
-
-                    initialize();
-
-                    function initialize() {
-                        $scope.loading = false;
-                        $scope.showResults = false;
-                        $scope.results = [];
-                        $scope.resultsLayers = [];
-                        $scope.resultsLayerTestSuitesNames = [];
-                        $scope.selectedRobotTestResult = [];
-                        restAPISvc
-                                .getRestAPI(
-                                        "/api/submission/",
-                                        function(data) {
-                                            $scope.submissions = data;
-                                            $scope.submissionsForDisplay = [];
-                                            angular
-                                                    .forEach(
-                                                            $scope.submissions,
-                                                            function(
-                                                                    submissionData) {
-                                                                if (submissionData.submissionStatus === "Completed") {
-                                                                    var temp = "id: "
-                                                                            + submissionData.submissionId
-                                                                            + " blueprint: "
-                                                                            + submissionData.blueprintInstanceForValidation.blueprint.blueprintName
-                                                                            + " version: "
-                                                                            + submissionData.blueprintInstanceForValidation.version
-                                                                            + " layer: "
-                                                                            + submissionData.blueprintInstanceForValidation.layer
-                                                                            + " lab: "
-                                                                            + submissionData.timeslot.lab.lab
-                                                                            + " Start date and time: "
-                                                                            + submissionData.timeslot.startDateTime
-                                                                    /*
-                                                                     * + "
-                                                                     * duration: " +
-                                                                     * submissionData.blueprintInstanceForValidation.timeslot.duration
-                                                                     */;
-                                                                    $scope.submissionsForDisplay
-                                                                            .push(temp);
-                                                                }
-                                                            });
-                                        });
-                    }
-                    $scope.selectedSubmissionChange = function(
-                            selectedSubmission) {
-                        $scope.results = [];
-                        $scope.resultsLayers = [];
-                        $scope.resultsLayerTestSuitesNames = [];
-                        $scope.selectedRobotTestResult = [];
-                        $scope.loading = true;
-                        $scope.showResults = false;
-                        var id = selectedSubmission.substring(
-                                selectedSubmission.indexOf("id:") + 4,
-                                selectedSubmission.indexOf("blueprint") - 1);
-                        restAPISvc
-                                .getRestAPI(
-                                        "/api/results/getBySubmissionId/" + id,
-                                        function(data) {
-                                            $scope.loading = false;
-                                            if (data !== undefined) {
-                                                $scope.results = data;
-                                                angular
-                                                        .forEach(
-                                                                $scope.results,
-                                                                function(result) {
-                                                                    $scope.resultsLayers
-                                                                            .push(result.blueprintLayer);
-                                                                });
-                                                $scope.showResults = true;
-                                            } else {
-                                                confirm("Error when committing the submission");
-                                            }
-                                        });
-                    }
-
-                    $scope.selectedResultsLayerChange = function(selectedLayer) {
-                        $scope.resultsLayerTestSuitesNames = [];
-                        $scope.robotTestResults = [];
-                        $scope.selectedRobotTestResult = [];
-                        var selectedLayerResult = [];
-                        angular.forEach($scope.results, function(result) {
-                            if (result.blueprintLayer === selectedLayer) {
-                                selectedLayerResult = result;
-                            }
-                        });
-                        $scope.robotTestResults = selectedLayerResult.robotTestResults;
-                        angular.forEach($scope.robotTestResults, function(
-                                robotTestResult) {
-                            $scope.resultsLayerTestSuitesNames
-                                    .push(robotTestResult.name);
-                        });
-                    }
-
-                    $scope.selectedTestSuitesNameChange = function(
-                            selectedTestSuiteName) {
-                        angular
-                                .forEach(
-                                        $scope.robotTestResults,
-                                        function(robotTestResult) {
-                                            if (robotTestResult.name.trim() === selectedTestSuiteName
-                                                    .trim()) {
-                                                $scope.selectedRobotTestResult = robotTestResult;
-                                            }
-                                        });
-                    }
-
-                });
diff --git a/ui/src/main/webapp/app/AECBlueprintValidationUI/GetBySubmissionId/GetBySubmissionIdTemplate.html b/ui/src/main/webapp/app/AECBlueprintValidationUI/GetBySubmissionId/GetBySubmissionIdTemplate.html
deleted file mode 100644 (file)
index 8d6324c..0000000
+++ /dev/null
@@ -1,388 +0,0 @@
-<!--
-Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-
-<div id="page-content" class="content" style="padding: 25px;">
- <style>
-.graph, .empty-graph {
-    border: 1px solid #ccc;
-    width: auto;
-    height: 7px;
-    padding: 0;
-    background: #f33;
-}
-
-.pass-bar {
-    background: #1d4;
-}
-
-.pass-bar, .fail-bar {
-    float: left;
-    height: 100%;
-}
-
-div.box {
-    border: 1px solid black;
-}
-</style>
-
- <h1 class="heading-page">Get results by submission</h1>
-
- <h2 class="heading-small">General matching string:</h2>
- <div>
-  <input ng-model="filterGeneralMatch" type="text" placeholder="?"
-   style="margin-top: 5px; width: 260px;">
- </div>
-
- <h2 class="heading-small">Select Submission:</h2>
-
- <div>
-  <select ng-model="selectedSubmission"
-   ng-init="selectedSubmission=submissionsForDisplay[0]"
-   ng-change="selectedSubmissionChange(selectedSubmission)"
-   ng-options="n for n in submissionsForDisplay | filter:filterGeneralMatch">
-  </select>
- </div>
-
- <div ng-show="loading">
-  <img src=" static/fusion/images/giphy.gif" />
- </div>
-
- <h2 class="heading-small"></h2>
- <div ng-show="showResults">
-  <h2 class="heading-small">Select a blueprint layer of the
-   selected submission:</h2>
-  <div>
-   <select ng-model="selectedLayer" ng-init="resultsLayers[0]"
-    ng-change="selectedResultsLayerChange(selectedLayer)"
-    ng-options="n for n in resultsLayers">
-   </select>
-  </div>
-
-  <h2 class="heading-small">Select a test suite of the selected
-   (submission, layer) pair in order to be displayed:</h2>
-  <div>
-   <select ng-model="selectedTestSuiteName"
-    ng-init="resultsLayerTestSuitesNames[0]"
-    ng-change="selectedTestSuitesNameChange(selectedTestSuiteName)"
-    ng-options="n for n in resultsLayerTestSuitesNames">
-   </select>
-  </div>
- </div>
-
- <br> <br> <br>
-
- <div
-  ng-hide="selectedSubmission == null || selectedLayer == null || selectedTestSuiteName == null">
-  <div>
-   <h2 class="heading-small"></h2>
-   <div class="box">
-    <h3 class="heading-small">
-     <u>General Info</u>
-    </h3>
-    <p></p>
-
-    <p></p>
-    <p>Name: {{selectedRobotTestResult.name}}</p>
-    <p>Generated: {{selectedRobotTestResult.robot.generated}}</p>
-    <p>Generator: {{selectedRobotTestResult.robot.generator}}</p>
-    <p>Errors: {{selectedRobotTestResult.robot.errors}}</p>
-
-    <h2 class="heading-small"></h2>
-    <h3 class="heading-small">
-     <u>Test Statistics</u>
-    </h3>
-    <p></p>
-    <table class="striped" cellspacing="0" cellpadding="10">
-     <caption>
-      <h3></h3>
-     </caption>
-     <thead>
-      <th><p>&nbsp;Total statistics&nbsp;</p></th>
-      <th><p>Total&nbsp;</p></th>
-      <th><p>Pass&nbsp;</p></th>
-      <th><p>Fail&nbsp;</p></th>
-      <th><p>Pass / Fail&nbsp;</p></th>
-      </tr>
-     </thead>
-     <tbody>
-      <tr
-       ng-repeat="stat in selectedRobotTestResult.robot.statistics.total.stat">
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        stat.content }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        (stat.fail * 1) + (stat.pass*1) }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        stat.pass }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        stat.fail}}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">
-        <div class="graph">
-         <div class="pass-bar"
-          ng-style="{ 'width': {{(100* stat.pass/((stat.fail * 1) + (stat.pass*1)) )| number:0}} + '%' }"
-          title="100%"></div>
-         <div class="fail-bar"
-          ng-style="{ 'width': {{(100* stat.fail/((stat.fail * 1) + (stat.pass*1)) )| number:0}} + '%' }"
-          title="0%"></div>
-        </div>
-       </td>
-      </tr>
-     </tbody>
-    </table>
-
-    <br>
-
-    <h3 class="heading-small"></h3>
-    <table class="striped" cellspacing="0" cellpadding="10">
-     <caption>
-      <h3></h3>
-     </caption>
-     <thead>
-      <th><p>&nbsp;Statistics by Tag&nbsp;</p></th>
-      <th><p>Total&nbsp;</p></th>
-      <th><p>Pass&nbsp;</p></th>
-      <th><p>Fail&nbsp;</p></th>
-      <th><p>Pass / Fail&nbsp;</p></th>
-      </tr>
-     </thead>
-     <tbody>
-      <tr
-       ng-repeat="stat in selectedRobotTestResult.robot.statistics.tag.stat">
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        stat.content }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        (stat.fail * 1) + (stat.pass*1) }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        stat.pass }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        stat.fail}}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">
-        <div class="graph">
-         <div class="pass-bar"
-          ng-style="{ 'width': {{(100* stat.pass/((stat.fail * 1) + (stat.pass*1)) )| number:0}} + '%' }"
-          title="100%"></div>
-         <div class="fail-bar"
-          ng-style="{ 'width': {{(100* stat.fail/((stat.fail * 1) + (stat.pass*1)) )| number:0}} + '%' }"
-          title="0%"></div>
-        </div>
-       </td>
-      </tr>
-     </tbody>
-    </table>
-
-    <br>
-
-    <h3 class="heading-small"></h3>
-    <table class="striped" cellspacing="0" cellpadding="10">
-     <caption>
-      <h3></h3>
-     </caption>
-     <thead>
-      <th><p>&nbsp;Statistics by Suite&nbsp;</p></th>
-      <th><p>Total&nbsp;</p></th>
-      <th><p>Pass&nbsp;</p></th>
-      <th><p>Fail&nbsp;</p></th>
-      <th><p>Pass / Fail&nbsp;</p></th>
-      </tr>
-     </thead>
-     <tbody>
-      <tr
-       ng-repeat="stat in selectedRobotTestResult.robot.statistics.suite.stat">
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        stat.content }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        (stat.fail * 1) + (stat.pass*1) }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        stat.pass }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        stat.fail}}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">
-        <div class="graph">
-         <div class="pass-bar"
-          ng-style="{ 'width': {{(100* stat.pass/((stat.fail * 1) + (stat.pass*1)) )| number:0}} + '%' }"
-          title="100%"></div>
-         <div class="fail-bar"
-          ng-style="{ 'width': {{(100* stat.fail/((stat.fail * 1) + (stat.pass*1)) )| number:0}} + '%' }"
-          title="0%"></div>
-        </div>
-       </td>
-      </tr>
-     </tbody>
-    </table>
-   </div>
-
-   <h2 class="heading-small"></h2>
-   <div class="box">
-    <h3 class="heading-small">
-     <a href="#" ng-click="showDetailsLog = ! showDetailsLog">Test
-      Execution Log</a>
-    </h3>
-    <div ng-show="showDetailsLog">
-     <p></p>
-     <p>Root Suite Full Name:
-      {{selectedRobotTestResult.robot.suite.name}}</p>
-     <p>Source: {{selectedRobotTestResult.robot.suite.source}}</p>
-     <p>Status:
-      {{selectedRobotTestResult.robot.suite.status.status}}</p>
-     <p>Start time:
-      {{selectedRobotTestResult.robot.suite.status.starttime}}</p>
-     <p>End time:
-      {{selectedRobotTestResult.robot.suite.status.endtime}}</p>
-
-     <h2 class="heading-small"></h2>
-     <p></p>
-     <p>Sub-suite Full Name:
-      {{selectedRobotTestResult.robot.suite.suite.name}}</p>
-     <p>Documentation:
-      {{selectedRobotTestResult.robot.suite.suite.doc}}</p>
-     <p>Source: {{selectedRobotTestResult.robot.suite.suite.source}}</p>
-     <p>Status:
-      {{selectedRobotTestResult.robot.suite.suite.status.status}}</p>
-     <p>Start time:
-      {{selectedRobotTestResult.robot.suite.suite.status.starttime}}</p>
-     <p>End time:
-      {{selectedRobotTestResult.robot.suite.suite.status.endtime}}</p>
-    </div>
-   </div>
-
-   <h2 class="heading-small"></h2>
-   <div class="box">
-    <ul>
-     <h4 class="heading-small">Sub-suite Robot keywords</h4>
-     <li ng-repeat="kw in selectedRobotTestResult.robot.suite.suite.kw">
-      <h2 class="heading-small"></h2>
-      <h4>
-       <a href="#" ng-click="showDetails = ! showDetails">
-        {{kw.name}}</a>
-      </h4>
-      <div ng-show="showDetails">
-       <p>&emsp;&emsp;&emsp;&emsp; Type: {{kw.type}}</p>
-       <p>&emsp;&emsp;&emsp;&emsp; Library: {{kw.library}}</p>
-       <p>&emsp;&emsp;&emsp;&emsp; Documentation: {{kw.doc}}</p>
-       <p>&emsp;&emsp;&emsp;&emsp; Start time:
-        {{kw.status.starttime}}</p>
-       <p>&emsp;&emsp;&emsp;&emsp; End time: {{kw.status.endtime}}</p>
-       <p>&emsp;&emsp;&emsp;&emsp; Status: {{kw.status.status}}</p>
-       <p></p>
-       <p>&emsp;&emsp;&emsp;&emsp; Used Robot keywords</p>
-       <ul>
-        <li ng-repeat="kw2 in kw.kw">
-         <h4>
-          <a href="#" ng-click="showDetails2 = ! showDetails2">&emsp;&emsp;&emsp;&emsp;
-           {{kw2.name}}</a>
-         </h4>
-         <div ng-show="showDetails2">
-          <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; Type:
-           {{kw2.type}}</p>
-          <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
-           Library: {{kw2.library}}</p>
-          <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
-           Documentation: {{kw2.doc}}</p>
-          <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; Start
-           time: {{kw2.status.starttime}}</p>
-          <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp; End
-           time: {{kw2.status.endtime}}</p>
-          <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
-           Status: {{kw2.status.status}}</p>
-         </div>
-        </li>
-       </ul>
-      </div>
-     </li>
-    </ul>
-   </div>
-
-   <h2 class="heading-small"></h2>
-   <div class="box">
-    <h3 class="heading-small">Test Cases</h3>
-    <table class="striped" cellspacing="0" cellpadding="10">
-     <caption>
-      <h3></h3>
-     </caption>
-     <thead>
-      <th><p>&nbsp;Full Name&nbsp;</p></th>
-      <th><p>Documentation&nbsp;</p></th>
-      <th><p>Status&nbsp;</p></th>
-      <th><p>Start Time&nbsp;</p></th>
-      <th><p>End Time&nbsp;</p></th>
-      <th><p>Critical&nbsp;</p></th>
-      <th><p>Message&nbsp;</p></th>
-      <th><p>Robot keywords&nbsp;</p></th>
-      </tr>
-     </thead>
-     <tbody>
-      <tr
-       ng-repeat="test in selectedRobotTestResult.robot.suite.suite.test">
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
-        test.name }}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{test.doc}}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{test.status.status}}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{test.status.starttime}}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{test.status.endtime}}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{test.status.critical}}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{test.status.content}}</td>
-       <td style="padding-left: 10px; font-size: 15px; width: 13%;">
-
-        <ul>
-         <li ng-repeat="testKw in test.kw">
-          <h2 class="heading-small"></h2>
-          <h4>
-           <a href="#" ng-click="showDetails3 = ! showDetails3">
-            {{testKw.name}}</a>
-          </h4>
-          <div ng-show="showDetails3">
-           <p>&emsp;&emsp;&emsp;&emsp; Type: {{testKw.type}}</p>
-           <p>&emsp;&emsp;&emsp;&emsp; Library: {{testKw.library}}</p>
-           <p>&emsp;&emsp;&emsp;&emsp; Documentation: {{testKw.doc}}</p>
-           <p>&emsp;&emsp;&emsp;&emsp; Start time:
-            {{testKw.status.starttime}}</p>
-           <p>&emsp;&emsp;&emsp;&emsp; End time:
-            {{testKw.status.endtime}}</p>
-           <p>&emsp;&emsp;&emsp;&emsp; Status:
-            {{testKw.status.status}}</p>
-           <p></p>
-           <p>&emsp;&emsp;&emsp;&emsp; Used Robot keywords</p>
-           <ul>
-            <li ng-repeat="testKw2 in testKw.kw">
-             <h4>
-              <a href="#" ng-click="showDetails4 = ! showDetails4">&emsp;&emsp;&emsp;&emsp;
-               {{testKw2.name}}</a>
-             </h4>
-             <div ng-show="showDetails4">
-              <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
-               Type: {{testKw2.type}}</p>
-              <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
-               Library: {{testKw2.library}}</p>
-              <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
-               Documentation: {{testKw2.doc}}</p>
-              <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
-               Start time: {{testKw2.status.starttime}}</p>
-              <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
-               End time: {{testKw2.status.endtime}}</p>
-              <p>&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;&emsp;
-               Status: {{testKw2.status.status}}</p>
-             </div>
-            </li>
-           </ul>
-       </td>
-
-      </tr>
-     </tbody>
-    </table>
-   </div>
-
-  </div>
- </div>
-</div>
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/AECBlueprintValidationUI/GetBySubmissionId/Route.js b/ui/src/main/webapp/app/AECBlueprintValidationUI/GetBySubmissionId/Route.js
deleted file mode 100644 (file)
index 58c09fd..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-appDS2
-        .config(function($routeProvider) {
-            $routeProvider
-
-                    .otherwise({
-                        templateUrl : 'app/AECBlueprintValidationUI/GetBySubmissionId/GetBySubmissionIdTemplate.html',
-                        controller : "AECGetBySubmissionIdController"
-                    });
-        });
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/AECBlueprintValidationUI/NewSubmission/NewSubmissionTemplate.html b/ui/src/main/webapp/app/AECBlueprintValidationUI/NewSubmission/NewSubmissionTemplate.html
deleted file mode 100644 (file)
index a84fa05..0000000
+++ /dev/null
@@ -1,73 +0,0 @@
-<!--
-Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-       http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
--->
-
-<div id="page-content" class="content" style="padding: 25px;">
- <div>
-  <h1 class="heading-page">New Submission</h1>
-  <h2 class="heading-small">Submission form</h2>
-
-  <div>
-   <div class="form-row">
-    <label for="textinputID-3a">Select Blueprint: </label> <select
-     ng-model="selectedBlueprintName"
-     ng-init="selectedBlueprintName=blueprintNames[0]"
-     ng-change="selectedBluePrintNameChange()"
-     ng-options="n for n in blueprintNames">
-    </select>
-   </div>
-  </div>
-  <br>
-
-  <div>
-   <div class="form-row">
-    <label for="textinputID-3a">Select Blueprint Version: </label> <select
-     ng-model="selectedBlueprintVersion"
-     ng-change="selectedBluePrintVersionChange()"
-     ng-options="y for y in blueprintVersions">
-    </select>
-   </div>
-  </div>
-  <br>
-
-  <div>
-   <div class="form-row">
-    <label for="textinputID-3a">Select Blueprint Layer: </label> <select
-     ng-model="selectedBlueprintLayer"
-     ng-change="selectedBluePrintLayerChange()"
-     ng-options="l for l in blueprintLayers">
-    </select>
-   </div>
-  </div>
-  <br>
-
-
-  <div>
-   <div class="form-row">
-    <label for="textinputID-3a">Select Timeslot: </label> <select
-     ng-model="selectedDeclerativeTimeslot"
-     ng-options="v for v in declerativeTimeslots">
-    </select>
-   </div>
-  </div>
-  <br>
-
-  <div class="fn-ebz-container" style="position: relative; top: 25px;">
-   <button href="javascript:void(0)" id="addbtn" style="bottom: -17px;"
-    size="small" att-accessibility-click="13,32"
-    class="btn btn-alt btn-small" ng-click="submit();">Submit</button>
-  </div>
- </div>
-</div>
@@ -15,5 +15,5 @@
  */
 
 var config_module = angular.module('App.Config', []);
-config_module.constant('appContext', '/AECBlueprintValidationUI');
-config_module.constant('refreshPeriod', '5000'); // in msecs
+config_module.constant('appContext', '/bluvalui');
+config_module.constant('refreshPeriod', '12000'); // in msecs
diff --git a/ui/src/main/webapp/app/BluvalUI/App.Services.js b/ui/src/main/webapp/app/BluvalUI/App.Services.js
new file mode 100644 (file)
index 0000000..b5123e1
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var services = angular.module('App.Services', ['App.Config']);
+
+services.factory('restAPISvc', [
+    '$http',
+    'appContext',
+    function ($http, appContext) {
+        var svc = [];
+        svc.getRestAPI = function (path, cb) {
+            return $http({
+                method: 'GET',
+                url: appContext + path,
+                headers: {
+                    'Content-Type': "application/json",
+                    'Accept': "application/json"
+                }
+            }).then(
+                function (response) {
+                    if (response.status == 200) {
+                        cb(response.data);
+                    } else {
+                        /* eslint-disable no-console */
+                        console.log("Get REST API error: "
+                            + response.statusText);
+                        /* eslint-enable no-console */
+                        cb(null);
+                    }
+                },
+                function (error) {
+                    /* eslint-disable no-console */
+                    console.log("Get REST API error: "
+                        + error.statusText);
+                    /* eslint-enable no-console */
+                    cb(null);
+                });
+        };
+        svc.postRestAPI = function (path, json, cb) {
+            return $http({
+                method: 'POST',
+                url: appContext + path,
+                headers: {
+                    'Content-Type': "application/json",
+                    'Accept': "application/json"
+                },
+                data: json
+            }).then(
+                function (response) {
+                    if (response.status == 200
+                        || response.status == 201) {
+                        cb(response.data);
+                    } else {
+                        /* eslint-disable no-console */
+                        console.log("Post REST API error: "
+                            + response.statusText);
+                        /* eslint-enable no-console */
+                        cb(null);
+                    }
+                },
+                function (error) {
+                    /* eslint-disable no-console */
+                    console.log("Post REST API error: "
+                        + error.statusText);
+                    /* eslint-enable no-console */
+                    cb(null);
+                });
+        };
+        svc.deleteRestAPI = function (path, json) {
+            return $http({
+                method: 'DELETE',
+                url: appContext + path,
+                headers: {
+                    'Content-Type': "application/json",
+                    'Accept': "application/json"
+                },
+                data: json
+            }).then(
+                function (response) {
+                    if (response.status !== 200) {
+                        /* eslint-disable no-console */
+                        console.log("Delete REST API error: "
+                            + response.statusText);
+                        /* eslint-enable no-console */
+                    }
+                },
+                function (error) {
+                    /* eslint-disable no-console */
+                    console.log("Delete REST API error: "
+                        + error.statusText);
+                    /* eslint-enable no-console */
+                });
+        };
+        return svc;
+    }]);
+
+services.factory("sharedContext", function () {
+    var context = [];
+    var addData = function (key, value) {
+        var data = {
+            key: key,
+            value: value
+        };
+        context.push(data);
+    }
+    var getData = function (key) {
+        var data = [];
+        angular
+            .forEach(
+                context,
+                function (pair) {
+                    if (pair.key === key) {
+                        data = pair.value;
+                    }
+                });
+        return data;
+    }
+
+    return {
+        addData: addData,
+        getData: getData
+    }
+});
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissions.Services.js b/ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissions.Services.js
new file mode 100644 (file)
index 0000000..dd4f699
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var app = angular.module('CommittedSubmissions');
+
+app
+        .factory(
+                'committedSubmissionsSvc',
+                [ function() {
+                    var svc = [];
+                    svc.getLayer = function(validationNexusTestResult) {
+                        if (validationNexusTestResult.allLayers) {
+                            return "all";
+                        }
+                        var layers = [];
+                        angular
+                                .forEach(
+                                        validationNexusTestResult.wRobotNexusTestResults,
+                                        function(result) {
+                                            layers.push(result.blueprintLayer);
+                                        });
+                        return layers;
+                    };
+                    svc.getResultUrl = function(submissionData) {
+                        if (submissionData.status !== "Completed") {
+                            return null;
+                        }
+                        if (!submissionData.validationNexusTestResult.wRobotNexusTestResults) {
+                            return null;
+                        }
+                        if (submissionData.validationNexusTestResult.wRobotNexusTestResults.length === 0) {
+                            return null;
+                        }
+                        var resultExistence = false;
+                        angular
+                                .forEach(
+                                        submissionData.validationNexusTestResult.wRobotNexusTestResults,
+                                        function(result) {
+                                            if (result.robotTestResults
+                                                    && result.robotTestResults.length > 0) {
+                                                resultExistence = true;
+                                            }
+                                        });
+                        if (resultExistence) {
+                            return "https://nexus.akraino.org/content/sites/logs/"
+                                    + submissionData.validationNexusTestResult.silo
+                                    + "/"
+                                    + submissionData.validationNexusTestResult.blueprintName
+                                    + "/"
+                                    + submissionData.validationNexusTestResult.version
+                                    + "/"
+                                    + submissionData.validationNexusTestResult.timestamp
+                                    + "/";
+                        }
+                        return null;
+                    };
+                    svc.mapResult = function(validationNexusTestResult) {
+                        if (!validationNexusTestResult.timestamp) {
+                            return null;
+                        }
+                        if (!validationNexusTestResult.wRobotNexusTestResults) {
+                            return null;
+                        }
+                        if (validationNexusTestResult.wRobotNexusTestResults.length === 0) {
+                            return null;
+                        }
+                        var resultExistence = false;
+                        angular
+                                .forEach(
+                                        validationNexusTestResult.wRobotNexusTestResults,
+                                        function(result) {
+                                            if (result.robotTestResults
+                                                    && result.robotTestResults.length > 0) {
+                                                resultExistence = true;
+                                            }
+                                        });
+                        if (resultExistence) {
+                            if (validationNexusTestResult.result === true) {
+                                return 'SUCCESS';
+                            }
+                            return 'FAILURE'
+                        }
+                        return null;
+                    };
+                    return svc;
+                } ]);
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissions.html b/ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissions.html
new file mode 100644 (file)
index 0000000..3352960
--- /dev/null
@@ -0,0 +1,189 @@
+<!--
+Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<!DOCTYPE html>
+<!-- Single-page application for EPSDK-App using DS2 look and feel. -->
+<html>
+
+<head>
+<meta charset="ISO-8859-1">
+<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
+
+<title>Committed Submissions</title>
+
+<!-- B2b Library -->
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/b2b/css/b2b-angular/b2b-angular.css">
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/b2b/css/b2b-angular/font_icons.css">
+
+<!-- icons in open source -->
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/ds2/css/digital-ng-library/ionicons.css">
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/ds2/css/digital-ng-library/ecomp-ionicons.css">
+
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/angular-bootstrap/ui-bootstrap-csp.css">
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/angular-gridster/dist/angular-gridster.min.css">
+<link rel="stylesheet" type="text/css"
+    href="static/fusion/sample/css/scribble.css" />
+<link rel="stylesheet" type="text/css"
+    href="static/fusion/sample/css/welcome.css" />
+
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/styles/ecomp.css">
+
+<link rel="stylesheet"
+    href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" />
+<link rel="stylesheet"
+    href="https://cdnjs.cloudflare.com/ajax/libs/ng-table/1.0.0/ng-table.css">
+
+<!-- Common scripts -->
+<script src="app/fusion/external/angular-1.4.8/angular.min.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-messages.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-touch.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-sanitize.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-route.min.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-cookies.min.js"></script>
+<script src="app/fusion/external/jquery/dist/jquery.min.js"></script>
+<script
+    src="app/fusion/external/javascript-detect-element-resize/jquery.resize.js"></script>
+<script
+    src="app/fusion/external/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
+<script
+    src="app/fusion/external/angular-gridster/dist/angular-gridster.min.js"></script>
+
+<!-- EPSDK App scripts and common services -->
+<!-- B2b Library -->
+<script src="app/fusion/external/b2b/js/b2b-angular/b2b-library.min.js"></script>
+<script
+    src="https://cdnjs.cloudflare.com/ajax/libs/ng-table/1.0.0/ng-table.js"></script>
+<script src="app/fusion/scripts/DS2-services/ds2-modal/modalService.js"></script>
+<script src="app/BluvalUI/App.Config.js"></script>
+<script src="app/BluvalUI/App.Services.js"></script>
+<script src="app/BluvalUI/CommittedSubmissions/CommittedSubmissions.js"></script>
+
+<script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
+<script src="app/fusion/scripts/DS2-services/headerServiceDS2.js"></script>
+<script src="app/fusion/scripts/DS2-services/leftMenuServiceDS2.js"></script>
+<script src="app/fusion/scripts/DS2-services/manifestService.js"></script>
+
+<script src="app/fusion/scripts/DS2-directives/footer.js"></script>
+<script src="app/fusion/scripts/DS2-directives/ds2Header.js"></script>
+<script src="app/fusion/scripts/DS2-directives/ds2LeftMenu.js"></script>
+<script src="app/fusion/scripts/DS2-directives/b2b-leftnav-ext.js"></script>
+<script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
+
+<!-- Page specific items -->
+<script
+    src="app/BluvalUI/CommittedSubmissions/CommittedSubmissions.Services.js"></script>
+<script
+    src="app/BluvalUI/CommittedSubmissions/CommittedSubmissionsController.js"></script>
+<script src="app/BluvalUI/CommittedSubmissions/Route.js"></script>
+
+<style>
+.controls {
+    margin-bottom: 20px;
+}
+
+.page-header {
+    margin-top: 20px;
+}
+
+ul {
+    list-style: none;
+}
+
+.box {
+    height: 100%;
+    border: 1px solid #ccc;
+    background-color: #fff;
+    position: relative;
+    overflow: hidden;
+}
+
+.box-header {
+    background-color: #eee;
+    padding: 0px 0px 0px 0px;
+    margin-bottom: -25px;
+    cursor: move;
+    position: relative;
+}
+
+.box-header h3 {
+    margin-top: 0px;
+    display: inline-block;
+}
+
+.box-content {
+    padding: 10px;
+    display: block;
+    height: 100%;
+    position: relative;
+    overflow-x: auto;
+    overflow-y: auto;
+}
+
+.box-header-btns {
+    top: 15px;
+    right: 10px;
+    cursor: pointer;
+    position: absolute;
+}
+
+.gridster {
+    border: none;
+    position: relative;
+}
+
+.box-content .box-content-frame {
+
+}
+
+.box table {
+    border: none;
+    display: block;
+}
+
+.box table tr {
+    line-height: 20px;
+}
+
+.box table th {
+    border: none;
+    line-height: 20px;
+}
+
+.menu-container {
+    margin-top: 0px
+}
+
+.handle-e {
+    width: 3px;
+}
+</style>
+</head>
+
+<body class="appBody" ng-app="CommittedSubmissions">
+    <div ds2-Header class="header-container"></div>
+    <div ds2-menu id="menuContainer" class="menu-container"></div>
+    <div ng-view id="rightContentProfile" class="content-container"></div>
+    <div ds2-Footer class="footer-container"></div>
+</body>
+
+</html>
\ No newline at end of file
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-var appDS2 = angular.module("AECGetBySubmissionId", [ 'ngRoute', 'ngMessages',
+var appDS2 = angular.module("CommittedSubmissions", [ 'ngRoute', 'ngMessages',
         'modalServices', 'ngCookies', 'b2b.att', 'gridster', 'ui.bootstrap',
-        'ui.bootstrap.modal', 'App.Services' ]);
\ No newline at end of file
+        'ui.bootstrap.modal', 'App.Config', 'App.Services', 'ngTable' ]);
diff --git a/ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissionsController.js b/ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissionsController.js
new file mode 100644 (file)
index 0000000..8f7a8a3
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var app = angular.module('CommittedSubmissions');
+
+app.controller('CommittedSubmissionsController', function($scope, restAPISvc,
+        $interval, refreshPeriod, committedSubmissionsSvc, NgTableParams,
+        appContext, $window) {
+
+    $scope.getLayer = committedSubmissionsSvc.getLayer;
+    $scope.getResultUrl = committedSubmissionsSvc.getResultUrl;
+    $scope.mapResult = committedSubmissionsSvc.mapResult;
+
+    initialize();
+
+    function initialize() {
+        restAPISvc.getRestAPI("/api/v1/submission/", function(submissions) {
+            $scope.submissionDatas = submissions;
+            var data = submissions;
+            $scope.tableParams = new NgTableParams({
+                page : 1,
+                count : 5
+            }, {
+                dataset : data
+            });
+        });
+    }
+
+    $scope.refreshCommittedSubmissions = function() {
+        initialize();
+    }
+
+    $scope.getValidationResults = function(submissionData) {
+        if (!submissionData.validationNexusTestResult.timestamp) {
+            return;
+        }
+        $window.location.href = appContext
+                + "/validationresults#?submissionId="
+                + submissionData.submissionId;
+    }
+
+    $interval(function() {
+        $scope.refreshCommittedSubmissions();
+    }, refreshPeriod);
+
+});
diff --git a/ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissionsTemplate.html b/ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/CommittedSubmissionsTemplate.html
new file mode 100644 (file)
index 0000000..cdb6de9
--- /dev/null
@@ -0,0 +1,73 @@
+<!--
+Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<div id="page-content" class="content" style="padding: 25px;">
+
+    <style>
+body {
+    font-size: 13px;
+}
+
+.box {
+    overflow-x: scroll;
+    overflow-y: scroll;
+}
+</style>
+
+    <div class="box">
+        <h1 class="heading-page">Committed Submissions</h1>
+        <div>
+            <button
+                style="margin-left: 25px; margin-top: 4px; float: right; background-color: #337ab7;"
+                type="submit" class="btn-alt btn-small"
+                ng-click="refreshCommittedSubmissions()">Refresh</button>
+        </div>
+        <table ng-table="tableParams" class="table" show-filter="true">
+            <tr ng-repeat="submissionData in $data">
+                <td title="'Id'" filter="{ submissionId: 'text'}"
+                    sortable="'submissionId'">{{
+                    submissionData.submissionId }}</td>
+                <td title="'Timeslot'" filter="{ timeslot: 'text'}"
+                    sortable="'timeslot'">Lab: {{
+                    submissionData.timeslot.lab.lab }} Start date and
+                    time: {{ submissionData.timeslot.startDateTime }} <!-- duration(in sec) :
+                                {{submission.timeslot.duration}}-->
+                </td>
+                <td title="'Blueprint Name'">{{
+                    submissionData.validationNexusTestResult.blueprintName
+                    }}</td>
+                <td title="'Version'">{{
+                    submissionData.validationNexusTestResult.version }}</td>
+                <td title="'Layer(s)'">{{
+                    getLayer(submissionData.validationNexusTestResult)
+                    }}</td>
+                <td title="'Optional Test Cases'">{{
+                    submissionData.validationNexusTestResult.optional}}</td>
+                <td title="'Status'" filter="{ status: 'text'}"
+                    sortable="'status'">{{ submissionData.status }}</td>
+                <td title="'Nexus URL result'"><a
+                    href="{{getResultUrl(submissionData)}}">{{getResultUrl(submissionData)}}</a></td>
+                <td title="'Result'">
+                    <button
+                        style="margin-left: 25px; margin-top: 4px; float: right; background-color: #337ab7;"
+                        type="submit" class="btn-alt btn-small"
+                        ng-click="getValidationResults(submissionData);">{{
+                        mapResult(submissionData.validationNexusTestResult)}}</button>
+                </td>
+            </tr>
+        </table>
+    </div>
+
+</div>
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/Route.js b/ui/src/main/webapp/app/BluvalUI/CommittedSubmissions/Route.js
new file mode 100644 (file)
index 0000000..aedc6d9
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+appDS2
+    .config(function ($routeProvider) {
+        $routeProvider
+            .otherwise({
+                templateUrl: 'app/BluvalUI/CommittedSubmissions/CommittedSubmissionsTemplate.html',
+                controller: "CommittedSubmissionsController"
+            });
+    });
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/GetBasedOnDate.html b/ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/GetBasedOnDate.html
new file mode 100644 (file)
index 0000000..1453020
--- /dev/null
@@ -0,0 +1,179 @@
+<!--
+Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<!DOCTYPE html>
+<!-- Single-page application for EPSDK-App using DS2 look and feel. -->
+<html>
+
+<head>
+<meta charset="ISO-8859-1">
+<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
+
+<title>Get Most Recent Results</title>
+
+<!-- B2b Library -->
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/b2b/css/b2b-angular/b2b-angular.css">
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/b2b/css/b2b-angular/font_icons.css">
+
+<!-- icons in open source -->
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/ds2/css/digital-ng-library/ionicons.css">
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/ds2/css/digital-ng-library/ecomp-ionicons.css">
+
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/angular-bootstrap/ui-bootstrap-csp.css">
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/angular-gridster/dist/angular-gridster.min.css">
+<link rel="stylesheet" type="text/css"
+    href="static/fusion/sample/css/scribble.css" />
+<link rel="stylesheet" type="text/css"
+    href="static/fusion/sample/css/welcome.css" />
+
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/styles/ecomp.css">
+
+<!-- Common scripts -->
+<script src="app/fusion/external/angular-1.4.8/angular.min.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-messages.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-touch.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-sanitize.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-route.min.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-cookies.min.js"></script>
+<script src="app/fusion/external/jquery/dist/jquery.min.js"></script>
+<script
+    src="app/fusion/external/javascript-detect-element-resize/jquery.resize.js"></script>
+<script
+    src="app/fusion/external/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
+<script
+    src="app/fusion/external/angular-gridster/dist/angular-gridster.min.js"></script>
+
+<!-- EPSDK App scripts and common services -->
+<!-- B2b Library -->
+<script src="app/fusion/external/b2b/js/b2b-angular/b2b-library.min.js"></script>
+<script src="app/fusion/scripts/DS2-services/ds2-modal/modalService.js"></script>
+<script src="app/BluvalUI/App.Config.js"></script>
+<script src="app/BluvalUI/App.Services.js"></script>
+<script src="app/BluvalUI/GetBasedOnDate/GetBasedOnDate.js"></script>
+
+<script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
+<script src="app/fusion/scripts/DS2-services/headerServiceDS2.js"></script>
+<script src="app/fusion/scripts/DS2-services/leftMenuServiceDS2.js"></script>
+<script src="app/fusion/scripts/DS2-services/manifestService.js"></script>
+
+<script src="app/fusion/scripts/DS2-directives/footer.js"></script>
+<script src="app/fusion/scripts/DS2-directives/ds2Header.js"></script>
+<script src="app/fusion/scripts/DS2-directives/ds2LeftMenu.js"></script>
+<script src="app/fusion/scripts/DS2-directives/b2b-leftnav-ext.js"></script>
+<script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
+
+<!-- Page specific items -->
+<script src="app/BluvalUI/GetBasedOnDate/GetBasedOnDateController.js"></script>
+<script src="app/BluvalUI/GetBasedOnDate/Route.js"></script>
+
+<style>
+.controls {
+    margin-bottom: 20px;
+}
+
+.page-header {
+    margin-top: 20px;
+}
+
+ul {
+    list-style: none;
+}
+
+.box {
+    height: 100%;
+    border: 1px solid #ccc;
+    background-color: #fff;
+    position: relative;
+    overflow: hidden;
+}
+
+.box-header {
+    background-color: #eee;
+    padding: 0px 0px 0px 0px;
+    margin-bottom: -25px;
+    cursor: move;
+    position: relative;
+}
+
+.box-header h3 {
+    margin-top: 0px;
+    display: inline-block;
+}
+
+.box-content {
+    padding: 10px;
+    display: block;
+    height: 100%;
+    position: relative;
+    overflow-x: auto;
+    overflow-y: auto;
+}
+
+.box-header-btns {
+    top: 15px;
+    right: 10px;
+    cursor: pointer;
+    position: absolute;
+}
+
+.gridster {
+    border: none;
+    position: relative;
+}
+
+.box-content .box-content-frame {
+
+}
+
+.box table {
+    border: none;
+    display: block;
+}
+
+.box table tr {
+    line-height: 20px;
+}
+
+.box table th {
+    border: none;
+    line-height: 20px;
+}
+
+.menu-container {
+    margin-top: 0px
+}
+
+.handle-e {
+    width: 3px;
+}
+</style>
+</head>
+
+<body class="appBody" ng-app="GetBasedOnDate">
+    <div ds2-Header class="header-container"></div>
+    <div ds2-menu id="menuContainer" class="menu-container"></div>
+    <div ng-view id="rightContentProfile" class="content-container"></div>
+    <div ds2-Footer class="footer-container"></div>
+</body>
+
+</html>
\ No newline at end of file
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
-var appDS2 = angular.module("AECCommittedSubmissions", [ 'ngRoute',
-        'ngMessages', 'modalServices', 'ngCookies', 'b2b.att', 'gridster',
-        'ui.bootstrap', 'ui.bootstrap.modal', 'App.Config', 'App.Services' ]);
+var appDS2 = angular.module("GetBasedOnDate", ['ngRoute', 'ngMessages',
+    'modalServices', 'ngCookies', 'b2b.att', 'gridster', 'ui.bootstrap',
+    'ui.bootstrap.modal', 'App.Services', 'App.Config']);
+
diff --git a/ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/GetBasedOnDateController.js b/ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/GetBasedOnDateController.js
new file mode 100644 (file)
index 0000000..607634b
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var app = angular.module('GetBasedOnDate');
+app.controller('GetBasedOnDateController', function($scope, restAPISvc,
+        $window, appContext, $filter) {
+
+    initialize();
+
+    function initialize() {
+        $scope.loadingLabs = true;
+        $scope.loadingBlueprints = false;
+        $scope.loadingVersions = false;
+        restAPISvc.getRestAPI("/api/v1/results/getlabs/", function(data) {
+            $scope.labs = data;
+            $scope.loadingLabs = false;
+        });
+    }
+
+    $scope.selectedLabChange = function() {
+        $scope.loadingLabs = false;
+        $scope.loadingBlueprints = true;
+        $scope.loadingVersions = false;
+        $scope.blueprints = [];
+        $scope.versions = [];
+        $scope.selectedBlueprint = {};
+        $scope.selectedVersion = {};
+        restAPISvc.getRestAPI("/api/v1/results/getblueprintnamesoflab/"
+                + $scope.selectedLab, function(data) {
+            $scope.blueprints = data;
+            $scope.loadingBlueprints = false;
+        });
+    }
+
+    $scope.selectedBlueprintChange = function() {
+        if (!$scope.selectedLab) {
+            return;
+        }
+        $scope.loadingLabs = false;
+        $scope.loadingBlueprints = false;
+        $scope.loadingVersions = true;
+        $scope.versions = [];
+        $scope.selectedVersion = {};
+        restAPISvc.getRestAPI("/api/v1/results/getblueprintversions/"
+                + $scope.selectedBlueprint + "/" + $scope.selectedLab,
+                function(data) {
+                    $scope.versions = data;
+                    $scope.loadingVersions = false;
+                });
+    }
+
+    $scope.selectedVersionChange = function() {
+    }
+
+    $scope.get = function() {
+        if (!$scope.selectedLab || !$scope.selectedBlueprint
+                || !$scope.selectedVersion || !$scope.selectedDate) {
+            confirm("You must specify all data fields");
+            return;
+        }
+        var selectedDate = $filter('date')($scope.selectedDate, "MM-dd-yyyy");
+
+        $window.location.href = appContext
+                + "/validationresults#?blueprintName="
+                + $scope.selectedBlueprint + "&" + "version="
+                + $scope.selectedVersion + "&" + "lab=" + $scope.selectedLab
+                + "&" + "date=" + selectedDate;
+    }
+
+});
diff --git a/ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/GetBasedOnDateTemplate.html b/ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/GetBasedOnDateTemplate.html
new file mode 100644 (file)
index 0000000..e8240cf
--- /dev/null
@@ -0,0 +1,71 @@
+<!--
+Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<div id="page-content" class="content" style="padding: 25px;">
+
+    <h1 class="heading-page">Get Results Based on Date</h1>
+
+    <div class="Row">
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Lab: </label> <select
+                    ng-model="selectedLab" ng-init="labs[0]"
+                    ng-change="selectedLabChange()"
+                    ng-options="n for n in labs">
+                </select>
+            </div>
+        </div>
+
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Blueprint: </label> <select
+                    ng-model="selectedBlueprint" ng-init="blueprints[0]"
+                    ng-change="selectedBlueprintChange()"
+                    ng-options="n for n in blueprints">
+                </select>
+            </div>
+        </div>
+
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Blueprint
+                    Version: </label> <select ng-model="selectedVersion"
+                    ng-init="versions[0]"
+                    ng-change="selectedVersionChange()"
+                    ng-options="n for n in versions">
+                </select>
+            </div>
+        </div>
+
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Date: </label> <input
+                    type="date" ng-model="selectedDate">
+            </div>
+        </div>
+    </div>
+
+    <div class="fn-ebz-container" style="position: relative; top: 25px;">
+        <button href="javascript:void(0)" id="addbtn"
+            style="bottom: -17px;" size="small"
+            att-accessibility-click="13,32"
+            class="btn btn-alt btn-small" ng-click="get();">Get</button>
+    </div>
+
+    <div ng-show="loadingLabs || loadingBlueprints || loadingVersions">
+        <img src=" static/fusion/images/giphy.gif" />
+    </div>
+
+</div>
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/Route.js b/ui/src/main/webapp/app/BluvalUI/GetBasedOnDate/Route.js
new file mode 100644 (file)
index 0000000..007a7f0
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+appDS2.config(function($routeProvider) {
+    $routeProvider.otherwise({
+        templateUrl : 'app/BluvalUI/GetBasedOnDate/GetBasedOnDateTemplate.html',
+        controller : "GetBasedOnDateController"
+    });
+});
\ No newline at end of file
@@ -17,35 +17,36 @@ limitations under the License.
 <!DOCTYPE html>
 <!-- Single-page application for EPSDK-App using DS2 look and feel. -->
 <html>
+
 <head>
 <meta charset="ISO-8859-1">
 <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
 
-<title>Committed Submissions</title>
+<title>Get By Timestamp</title>
 
 <!-- B2b Library -->
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/b2b/css/b2b-angular/b2b-angular.css">
   href="app/fusion/external/b2b/css/b2b-angular/b2b-angular.css">
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/b2b/css/b2b-angular/font_icons.css">
   href="app/fusion/external/b2b/css/b2b-angular/font_icons.css">
 
 <!-- icons in open source -->
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/ds2/css/digital-ng-library/ionicons.css">
   href="app/fusion/external/ds2/css/digital-ng-library/ionicons.css">
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/ds2/css/digital-ng-library/ecomp-ionicons.css">
   href="app/fusion/external/ds2/css/digital-ng-library/ecomp-ionicons.css">
 
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/angular-bootstrap/ui-bootstrap-csp.css">
   href="app/fusion/external/angular-bootstrap/ui-bootstrap-csp.css">
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/angular-gridster/dist/angular-gridster.min.css">
   href="app/fusion/external/angular-gridster/dist/angular-gridster.min.css">
 <link rel="stylesheet" type="text/css"
- href="static/fusion/sample/css/scribble.css" />
   href="static/fusion/sample/css/scribble.css" />
 <link rel="stylesheet" type="text/css"
- href="static/fusion/sample/css/welcome.css" />
   href="static/fusion/sample/css/welcome.css" />
 
 <link rel="stylesheet" type="text/css"
- href="app/fusion/styles/ecomp.css">
   href="app/fusion/styles/ecomp.css">
 
 <!-- Common scripts -->
 <script src="app/fusion/external/angular-1.4.8/angular.min.js"></script>
@@ -56,20 +57,19 @@ limitations under the License.
 <script src="app/fusion/external/angular-1.4.8/angular-cookies.min.js"></script>
 <script src="app/fusion/external/jquery/dist/jquery.min.js"></script>
 <script
- src="app/fusion/external/javascript-detect-element-resize/jquery.resize.js"></script>
   src="app/fusion/external/javascript-detect-element-resize/jquery.resize.js"></script>
 <script
- src="app/fusion/external/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
   src="app/fusion/external/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
 <script
- src="app/fusion/external/angular-gridster/dist/angular-gridster.min.js"></script>
   src="app/fusion/external/angular-gridster/dist/angular-gridster.min.js"></script>
 
 <!-- EPSDK App scripts and common services -->
 <!-- B2b Library -->
 <script src="app/fusion/external/b2b/js/b2b-angular/b2b-library.min.js"></script>
 <script src="app/fusion/scripts/DS2-services/ds2-modal/modalService.js"></script>
-<script src="app/AECBlueprintValidationUI/App.Config.js"></script>
-<script src="app/AECBlueprintValidationUI/App.Services.js"></script>
-<script
- src="app/AECBlueprintValidationUI/CommittedSubmissions/AECCommittedSubmissions.js"></script>
+<script src="app/BluvalUI/App.Config.js"></script>
+<script src="app/BluvalUI/App.Services.js"></script>
+<script src="app/BluvalUI/GetByTimestamp/GetByTimestamp.js"></script>
 
 <script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
 <script src="app/fusion/scripts/DS2-services/headerServiceDS2.js"></script>
@@ -83,63 +83,62 @@ limitations under the License.
 <script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
 
 <!-- Page specific items -->
-<script
- src="app/AECBlueprintValidationUI/CommittedSubmissions/AECCommittedSubmissionsController.js"></script>
-<script src="app/AECBlueprintValidationUI/CommittedSubmissions/Route.js"></script>
+<script src="app/BluvalUI/GetByTimestamp/GetByTimestampController.js"></script>
+<script src="app/BluvalUI/GetByTimestamp/Route.js"></script>
 
 <style>
 .controls {
-       margin-bottom: 20px;
+    margin-bottom: 20px;
 }
 
 .page-header {
-       margin-top: 20px;
+    margin-top: 20px;
 }
 
 ul {
-       list-style: none;
+    list-style: none;
 }
 
 .box {
-       height: 100%;
-       border: 1px solid #ccc;
-       background-color: #fff;
-       position: relative;
-       overflow: hidden;
+    height: 100%;
+    border: 1px solid #ccc;
+    background-color: #fff;
+    position: relative;
+    overflow: hidden;
 }
 
 .box-header {
-       background-color: #eee;
-       padding: 0px 0px 0px 0px;
-       margin-bottom: -25px;
-       cursor: move;
-       position: relative;
+    background-color: #eee;
+    padding: 0px 0px 0px 0px;
+    margin-bottom: -25px;
+    cursor: move;
+    position: relative;
 }
 
 .box-header h3 {
-       margin-top: 0px;
-       display: inline-block;
+    margin-top: 0px;
+    display: inline-block;
 }
 
 .box-content {
-       padding: 10px;
-       display: block;
-       height: 100%;
-       position: relative;
-       overflow-x: auto;
-       overflow-y: auto;
+    padding: 10px;
+    display: block;
+    height: 100%;
+    position: relative;
+    overflow-x: auto;
+    overflow-y: auto;
 }
 
 .box-header-btns {
-       top: 15px;
-       right: 10px;
-       cursor: pointer;
-       position: absolute;
+    top: 15px;
+    right: 10px;
+    cursor: pointer;
+    position: absolute;
 }
 
 .gridster {
-       border: none;
-       position: relative;
+    border: none;
+    position: relative;
 }
 
 .box-content .box-content-frame {
@@ -147,32 +146,34 @@ ul {
 }
 
 .box table {
-       border: none;
-       display: block;
+    border: none;
+    display: block;
 }
 
 .box table tr {
-       line-height: 20px;
+    line-height: 20px;
 }
 
 .box table th {
-       border: none;
-       line-height: 20px;
+    border: none;
+    line-height: 20px;
 }
 
 .menu-container {
-       margin-top: 0px
+    margin-top: 0px
 }
 
 .handle-e {
-       width: 3px;
+    width: 3px;
 }
 </style>
 </head>
-<body class="appBody" ng-app="AECCommittedSubmissions">
- <div ds2-Header class="header-container"></div>
- <div ds2-menu id="menuContainer" class="menu-container"></div>
- <div ng-view id="rightContentProfile" class="content-container"></div>
- <div ds2-Footer class="footer-container"></div>
+
+<body class="appBody" ng-app="GetByTimestamp">
+    <div ds2-Header class="header-container"></div>
+    <div ds2-menu id="menuContainer" class="menu-container"></div>
+    <div ng-view id="rightContentProfile" class="content-container"></div>
+    <div ds2-Footer class="footer-container"></div>
 </body>
+
 </html>
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/GetByTimestamp/GetByTimestamp.js b/ui/src/main/webapp/app/BluvalUI/GetByTimestamp/GetByTimestamp.js
new file mode 100644 (file)
index 0000000..623cf62
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var appDS2 = angular.module("GetByTimestamp", [ 'ngRoute', 'ngMessages',
+        'modalServices', 'ngCookies', 'b2b.att', 'gridster', 'ui.bootstrap',
+        'ui.bootstrap.modal', 'App.Services', 'App.Config' ]);
diff --git a/ui/src/main/webapp/app/BluvalUI/GetByTimestamp/GetByTimestampController.js b/ui/src/main/webapp/app/BluvalUI/GetByTimestamp/GetByTimestampController.js
new file mode 100644 (file)
index 0000000..cb75d5c
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var app = angular.module('GetByTimestamp');
+app.controller('GetByTimestampController',
+
+function($scope, restAPISvc, $window, appContext) {
+    initialize();
+
+    function initialize() {
+        $scope.loadingLabs = true;
+        $scope.loadingBlueprints = false;
+        $scope.loadingVersions = false;
+        restAPISvc.getRestAPI("/api/v1/results/getlabs/", function(data) {
+            $scope.labs = data;
+            $scope.loadingLabs = false;
+        });
+    }
+
+    $scope.selectedLabChange = function() {
+        $scope.loadingLabs = false;
+        $scope.loadingBlueprints = true;
+        $scope.loadingVersions = false;
+        $scope.blueprints = [];
+        $scope.versions = [];
+        $scope.selectedBlueprint = {};
+        $scope.selectedVersion = {};
+        restAPISvc.getRestAPI("/api/v1/results/getblueprintnamesoflab/"
+                + $scope.selectedLab, function(data) {
+            $scope.blueprints = data;
+            $scope.loadingBlueprints = false;
+        });
+    }
+
+    $scope.selectedBlueprintChange = function() {
+        if (!$scope.selectedLab) {
+            return;
+        }
+        $scope.loadingLabs = false;
+        $scope.loadingBlueprints = false;
+        $scope.loadingVersions = true;
+        $scope.versions = [];
+        $scope.selectedVersion = {};
+        restAPISvc.getRestAPI("/api/v1/results/getblueprintversions/"
+                + $scope.selectedBlueprint + "/" + $scope.selectedLab,
+                function(data) {
+                    $scope.versions = data;
+                    $scope.loadingVersions = false;
+                });
+    }
+
+    $scope.selectedVersionChange = function() {
+        $scope.loadingLabs = false;
+        $scope.loadingBlueprints = false;
+        $scope.loadingVersions = false;
+        $scope.loadingResults = false;
+    }
+
+    $scope.get = function() {
+        if (!$scope.selectedLab || !$scope.selectedBlueprint
+                || !$scope.selectedVersion || !$scope.definedTimestamp) {
+            confirm("You must specify all data fields");
+            return;
+        }
+
+        $window.location.href = appContext
+                + "/validationresults#?blueprintName="
+                + $scope.selectedBlueprint + "&" + "version="
+                + $scope.selectedVersion + "&" + "lab=" + $scope.selectedLab
+                + "&" + "timestamp=" + $scope.definedTimestamp;
+    }
+
+});
diff --git a/ui/src/main/webapp/app/BluvalUI/GetByTimestamp/GetByTimestampTemplate.html b/ui/src/main/webapp/app/BluvalUI/GetByTimestamp/GetByTimestampTemplate.html
new file mode 100644 (file)
index 0000000..0972b68
--- /dev/null
@@ -0,0 +1,67 @@
+<!--
+Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<div id="page-content" class="content" style="padding: 25px;">
+
+    <h1 class="heading-page">Get Results By Timestamp</h1>
+
+    <div class="Row">
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Lab: </label> <select
+                    ng-model="selectedLab" ng-init="labs[0]"
+                    ng-change="selectedLabChange()"
+                    ng-options="n for n in labs">
+                </select>
+            </div>
+        </div>
+
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Blueprint: </label> <select
+                    ng-model="selectedBlueprint" ng-init="blueprints[0]"
+                    ng-change="selectedBlueprintChange()"
+                    ng-options="n for n in blueprints">
+                </select>
+            </div>
+        </div>
+
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Blueprint
+                    Version: </label> <select ng-model="selectedVersion"
+                    ng-init="versions[0]"
+                    ng-change="selectedVersionChange()"
+                    ng-options="n for n in versions">
+                </select>
+            </div>
+        </div>
+
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Define Timestamp: </label> <input
+                    ng-model="definedTimestamp"</input>
+            </div>
+        </div>
+    </div>
+
+    <div class="fn-ebz-container" style="position: relative; top: 25px;">
+        <button href="javascript:void(0)" id="addbtn"
+            style="bottom: -17px;" size="small"
+            att-accessibility-click="13,32"
+            class="btn btn-alt btn-small" ng-click="get();">Get</button>
+    </div>
+</div>
\ No newline at end of file
@@ -17,9 +17,8 @@
 appDS2
         .config(function($routeProvider) {
             $routeProvider
-
                     .otherwise({
-                        templateUrl : 'app/AECBlueprintValidationUI/NewSubmission/NewSubmissionTemplate.html',
-                        controller : "AECNewSubmissionController"
+                        templateUrl : 'app/BluvalUI/GetByTimestamp/GetByTimestampTemplate.html',
+                        controller : "GetByTimestampController"
                     });
         });
\ No newline at end of file
@@ -17,35 +17,36 @@ limitations under the License.
 <!DOCTYPE html>
 <!-- Single-page application for EPSDK-App using DS2 look and feel. -->
 <html>
+
 <head>
 <meta charset="ISO-8859-1">
 <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
 
-<title>New Submission</title>
+<title>Get Last Run</title>
 
 <!-- B2b Library -->
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/b2b/css/b2b-angular/b2b-angular.css">
   href="app/fusion/external/b2b/css/b2b-angular/b2b-angular.css">
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/b2b/css/b2b-angular/font_icons.css">
   href="app/fusion/external/b2b/css/b2b-angular/font_icons.css">
 
 <!-- icons in open source -->
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/ds2/css/digital-ng-library/ionicons.css">
   href="app/fusion/external/ds2/css/digital-ng-library/ionicons.css">
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/ds2/css/digital-ng-library/ecomp-ionicons.css">
   href="app/fusion/external/ds2/css/digital-ng-library/ecomp-ionicons.css">
 
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/angular-bootstrap/ui-bootstrap-csp.css">
   href="app/fusion/external/angular-bootstrap/ui-bootstrap-csp.css">
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/angular-gridster/dist/angular-gridster.min.css">
   href="app/fusion/external/angular-gridster/dist/angular-gridster.min.css">
 <link rel="stylesheet" type="text/css"
- href="static/fusion/sample/css/scribble.css" />
   href="static/fusion/sample/css/scribble.css" />
 <link rel="stylesheet" type="text/css"
- href="static/fusion/sample/css/welcome.css" />
   href="static/fusion/sample/css/welcome.css" />
 
 <link rel="stylesheet" type="text/css"
- href="app/fusion/styles/ecomp.css">
   href="app/fusion/styles/ecomp.css">
 
 <!-- Common scripts -->
 <script src="app/fusion/external/angular-1.4.8/angular.min.js"></script>
@@ -56,20 +57,19 @@ limitations under the License.
 <script src="app/fusion/external/angular-1.4.8/angular-cookies.min.js"></script>
 <script src="app/fusion/external/jquery/dist/jquery.min.js"></script>
 <script
- src="app/fusion/external/javascript-detect-element-resize/jquery.resize.js"></script>
   src="app/fusion/external/javascript-detect-element-resize/jquery.resize.js"></script>
 <script
- src="app/fusion/external/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
   src="app/fusion/external/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
 <script
- src="app/fusion/external/angular-gridster/dist/angular-gridster.min.js"></script>
   src="app/fusion/external/angular-gridster/dist/angular-gridster.min.js"></script>
 
 <!-- EPSDK App scripts and common services -->
 <!-- B2b Library -->
 <script src="app/fusion/external/b2b/js/b2b-angular/b2b-library.min.js"></script>
 <script src="app/fusion/scripts/DS2-services/ds2-modal/modalService.js"></script>
-<script src="app/AECBlueprintValidationUI/App.Config.js"></script>
-<script src="app/AECBlueprintValidationUI/App.Services.js"></script>
-<script
- src="app/AECBlueprintValidationUI/NewSubmission/AECNewSubmission.js"></script>
+<script src="app/BluvalUI/App.Config.js"></script>
+<script src="app/BluvalUI/App.Services.js"></script>
+<script src="app/BluvalUI/GetLastRun/GetLastRun.js"></script>
 
 <script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
 <script src="app/fusion/scripts/DS2-services/headerServiceDS2.js"></script>
@@ -83,63 +83,62 @@ limitations under the License.
 <script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
 
 <!-- Page specific items -->
-<script
- src="app/AECBlueprintValidationUI/NewSubmission/AECNewSubmissionController.js"></script>
-<script src="app/AECBlueprintValidationUI/NewSubmission/Route.js"></script>
+<script src="app/BluvalUI/GetLastRun/GetLastRunController.js"></script>
+<script src="app/BluvalUI/GetLastRun/Route.js"></script>
 
 <style>
 .controls {
-       margin-bottom: 20px;
+    margin-bottom: 20px;
 }
 
 .page-header {
-       margin-top: 20px;
+    margin-top: 20px;
 }
 
 ul {
-       list-style: none;
+    list-style: none;
 }
 
 .box {
-       height: 100%;
-       border: 1px solid #ccc;
-       background-color: #fff;
-       position: relative;
-       overflow: hidden;
+    height: 100%;
+    border: 1px solid #ccc;
+    background-color: #fff;
+    position: relative;
+    overflow: hidden;
 }
 
 .box-header {
-       background-color: #eee;
-       padding: 0px 0px 0px 0px;
-       margin-bottom: -25px;
-       cursor: move;
-       position: relative;
+    background-color: #eee;
+    padding: 0px 0px 0px 0px;
+    margin-bottom: -25px;
+    cursor: move;
+    position: relative;
 }
 
 .box-header h3 {
-       margin-top: 0px;
-       display: inline-block;
+    margin-top: 0px;
+    display: inline-block;
 }
 
 .box-content {
-       padding: 10px;
-       display: block;
-       height: 100%;
-       position: relative;
-       overflow-x: auto;
-       overflow-y: auto;
+    padding: 10px;
+    display: block;
+    height: 100%;
+    position: relative;
+    overflow-x: auto;
+    overflow-y: auto;
 }
 
 .box-header-btns {
-       top: 15px;
-       right: 10px;
-       cursor: pointer;
-       position: absolute;
+    top: 15px;
+    right: 10px;
+    cursor: pointer;
+    position: absolute;
 }
 
 .gridster {
-       border: none;
-       position: relative;
+    border: none;
+    position: relative;
 }
 
 .box-content .box-content-frame {
@@ -147,32 +146,34 @@ ul {
 }
 
 .box table {
-       border: none;
-       display: block;
+    border: none;
+    display: block;
 }
 
 .box table tr {
-       line-height: 20px;
+    line-height: 20px;
 }
 
 .box table th {
-       border: none;
-       line-height: 20px;
+    border: none;
+    line-height: 20px;
 }
 
 .menu-container {
-       margin-top: 0px
+    margin-top: 0px
 }
 
 .handle-e {
-       width: 3px;
+    width: 3px;
 }
 </style>
 </head>
-<body class="appBody" ng-app="AECNewSubmission">
- <div ds2-Header class="header-container"></div>
- <div ds2-menu id="menuContainer" class="menu-container"></div>
- <div ng-view id="rightContentProfile" class="content-container"></div>
- <div ds2-Footer class="footer-container"></div>
+
+<body class="appBody" ng-app="GetLastRun">
+    <div ds2-Header class="header-container"></div>
+    <div ds2-menu id="menuContainer" class="menu-container"></div>
+    <div ng-view id="rightContentProfile" class="content-container"></div>
+    <div ds2-Footer class="footer-container"></div>
 </body>
+
 </html>
\ No newline at end of file
@@ -14,6 +14,6 @@
  * limitations under the License.
  */
 
-var appDS2 = angular.module("AECNewSubmission", [ 'ngRoute', 'ngMessages',
+var appDS2 = angular.module("GetLastRun", [ 'ngRoute', 'ngMessages',
         'modalServices', 'ngCookies', 'b2b.att', 'gridster', 'ui.bootstrap',
-        'ui.bootstrap.modal', 'App.Services' ]);
\ No newline at end of file
+        'ui.bootstrap.modal', 'App.Services', 'App.Config' ]);
diff --git a/ui/src/main/webapp/app/BluvalUI/GetLastRun/GetLastRunController.js b/ui/src/main/webapp/app/BluvalUI/GetLastRun/GetLastRunController.js
new file mode 100644 (file)
index 0000000..65f727e
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var app = angular.module('GetLastRun');
+app.controller('GetLastRunController',
+
+function($scope, restAPISvc, $window, appContext) {
+    initialize();
+
+    function initialize() {
+        $scope.loadingLabs = true;
+        $scope.loadingBlueprints = false;
+        $scope.loadingVersions = false;
+        restAPISvc.getRestAPI("/api/v1/results/getlabs/", function(data) {
+            $scope.labs = data;
+            $scope.loadingLabs = false;
+        });
+    }
+
+    $scope.selectedLabChange = function() {
+        $scope.loadingLabs = false;
+        $scope.loadingBlueprints = true;
+        $scope.loadingVersions = false;
+        $scope.blueprints = [];
+        $scope.versions = [];
+        $scope.layers = [];
+        $scope.optionals = [];
+        $scope.outcomes = [];
+        $scope.selectedBlueprint = {};
+        $scope.selectedVersion = {};
+        $scope.selectedLayer = {};
+        $scope.selectedOptional = {};
+        $scope.selectedOutcome = {};
+        restAPISvc.getRestAPI("/api/v1/results/getblueprintnamesoflab/"
+                + $scope.selectedLab, function(data) {
+            $scope.blueprints = data;
+            $scope.loadingBlueprints = false;
+        });
+    }
+
+    $scope.selectedBlueprintChange = function() {
+        if (!$scope.selectedLab) {
+            return;
+        }
+        $scope.loadingLabs = false;
+        $scope.loadingBlueprints = false;
+        $scope.loadingVersions = true;
+        $scope.versions = [];
+        $scope.layers = [];
+        $scope.optionals = [];
+        $scope.outcomes = [];
+        $scope.selectedVersion = {};
+        $scope.selectedLayer = {};
+        $scope.selectedOptional = {};
+        $scope.selectedOutcome = {};
+        restAPISvc.getRestAPI("/api/v1/results/getblueprintversions/"
+                + $scope.selectedBlueprint + "/" + $scope.selectedLab,
+                function(data) {
+                    $scope.versions = data;
+                    $scope.loadingVersions = false;
+                });
+    }
+
+    $scope.selectedVersionChange = function() {
+        $scope.layers = [];
+        $scope.optionals = [];
+        $scope.outcomes = [];
+        $scope.selectedLayer = {};
+        $scope.selectedOptional = {};
+        $scope.selectedOutcome = {};
+        $scope.loadingLabs = false;
+        $scope.loadingBlueprints = false;
+        $scope.loadingVersions = false;
+        $scope.loadingResults = false;
+        $scope.layers = [ 'all', 'hardware', 'os', 'k8s', 'openstack' ];
+    }
+
+    $scope.selectedLayerChange = function() {
+        $scope.optionals = [];
+        $scope.outcomes = [];
+        $scope.selectedOptional = {};
+        $scope.selectedOutcome = {};
+        $scope.loadingLabs = false;
+        $scope.loadingBlueprints = false;
+        $scope.loadingVersions = false;
+        $scope.loadingResults = false;
+        $scope.optionals = [ 'true', 'false' ];
+    }
+
+    $scope.selectedOptionalChange = function() {
+        $scope.outcomes = [];
+        $scope.selectedOutcome = {};
+        $scope.loadingLabs = false;
+        $scope.loadingBlueprints = false;
+        $scope.loadingVersions = false;
+        $scope.loadingResults = false;
+        $scope.outcomes = [ 'SUCCESS', 'FAILURE' ];
+    }
+
+    $scope.selectedOutcomeChange = function() {
+        $scope.loadingLabs = false;
+        $scope.loadingBlueprints = false;
+        $scope.loadingVersions = false;
+        $scope.loadingResults = false;
+    }
+
+    $scope.get = function() {
+        if (!$scope.selectedLab || !$scope.selectedBlueprint
+                || !$scope.selectedVersion || !$scope.selectedLayer
+                || !$scope.selectedOptional || !$scope.selectedOutcome) {
+            confirm("You must specify all data fields");
+            return;
+        }
+        var outcome = "";
+        if ($scope.selectedOutcome === 'SUCCESS') {
+            outcome = true;
+        } else {
+            outcome = false;
+        }
+        var allLayers = "";
+        var layer = "";
+        if ($scope.selectedLayer === 'all') {
+            allLayers = "true";
+        } else {
+            layer = $scope.selectedLayer;
+        }
+        $window.location.href = appContext
+                + "/validationresults#?blueprintName="
+                + $scope.selectedBlueprint + "&" + "version="
+                + $scope.selectedVersion + "&" + "lab=" + $scope.selectedLab
+                + "&" + "allLayers=" + allLayers + "&" + "layer=" + layer + "&"
+                + "optional=" + $scope.selectedOptional + "&" + "outcome="
+                + outcome;
+    }
+
+});
diff --git a/ui/src/main/webapp/app/BluvalUI/GetLastRun/GetLastRunTemplate.html b/ui/src/main/webapp/app/BluvalUI/GetLastRun/GetLastRunTemplate.html
new file mode 100644 (file)
index 0000000..3e0dee5
--- /dev/null
@@ -0,0 +1,93 @@
+<!--
+Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<div id="page-content" class="content" style="padding: 25px;">
+
+    <h1 class="heading-page">Get Last Run</h1>
+
+    <div class="Row">
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Lab: </label> <select
+                    ng-model="selectedLab" ng-init="labs[0]"
+                    ng-change="selectedLabChange()"
+                    ng-options="n for n in labs">
+                </select>
+            </div>
+        </div>
+
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Blueprint: </label> <select
+                    ng-model="selectedBlueprint" ng-init="blueprints[0]"
+                    ng-change="selectedBlueprintChange()"
+                    ng-options="n for n in blueprints">
+                </select>
+            </div>
+        </div>
+
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Blueprint
+                    Version: </label> <select ng-model="selectedVersion"
+                    ng-init="versions[0]"
+                    ng-change="selectedVersionChange()"
+                    ng-options="n for n in versions">
+                </select>
+            </div>
+        </div>
+
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Blueprint
+                    Layer Under Validation: </label> <select
+                    ng-model="selectedLayer" ng-init="layers[0]"
+                    ng-change="selectedLayerChange()"
+                    ng-options="n for n in layers">
+                </select>
+            </div>
+        </div>
+
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Optional Test Cases:
+                </label> <select ng-model="selectedOptional"
+                    ng-init="optional[0]"
+                    ng-change="selectedOptionalChange()"
+                    ng-options="n for n in optionals">
+                </select>
+            </div>
+        </div>
+
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Desired
+                    Overall Outcome: </label> <select ng-model="selectedOutcome"
+                    ng-init="outcomes[0]"
+                    ng-change="selectedOutcomeChange()"
+                    ng-options="n for n in outcomes">
+                </select>
+            </div>
+        </div>
+    </div>
+
+    <div class="fn-ebz-container" style="position: relative; top: 25px;">
+        <button href="javascript:void(0)" id="addbtn"
+            style="bottom: -17px;" size="small"
+            att-accessibility-click="13,32"
+            class="btn btn-alt btn-small" ng-click="get();">Get</button>
+    </div>
+</div>
\ No newline at end of file
@@ -18,7 +18,7 @@ appDS2
         .config(function($routeProvider) {
             $routeProvider
                     .otherwise({
-                        templateUrl : 'app/AECBlueprintValidationUI/CommittedSubmissions/CommittedSubmissionsTemplate.html',
-                        controller : "AECCommittedSubmissionsController"
+                        templateUrl : 'app/BluvalUI/GetLastRun/GetLastRunTemplate.html',
+                        controller : "GetLastRunController"
                     });
         });
\ No newline at end of file
@@ -17,35 +17,36 @@ limitations under the License.
 <!DOCTYPE html>
 <!-- Single-page application for EPSDK-App using DS2 look and feel. -->
 <html>
+
 <head>
 <meta charset="ISO-8859-1">
 <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
 
-<title>Get By Submission Id</title>
+<title>Get Most Recent Results</title>
 
 <!-- B2b Library -->
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/b2b/css/b2b-angular/b2b-angular.css">
   href="app/fusion/external/b2b/css/b2b-angular/b2b-angular.css">
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/b2b/css/b2b-angular/font_icons.css">
   href="app/fusion/external/b2b/css/b2b-angular/font_icons.css">
 
 <!-- icons in open source -->
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/ds2/css/digital-ng-library/ionicons.css">
   href="app/fusion/external/ds2/css/digital-ng-library/ionicons.css">
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/ds2/css/digital-ng-library/ecomp-ionicons.css">
   href="app/fusion/external/ds2/css/digital-ng-library/ecomp-ionicons.css">
 
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/angular-bootstrap/ui-bootstrap-csp.css">
   href="app/fusion/external/angular-bootstrap/ui-bootstrap-csp.css">
 <link rel="stylesheet" type="text/css"
- href="app/fusion/external/angular-gridster/dist/angular-gridster.min.css">
   href="app/fusion/external/angular-gridster/dist/angular-gridster.min.css">
 <link rel="stylesheet" type="text/css"
- href="static/fusion/sample/css/scribble.css" />
   href="static/fusion/sample/css/scribble.css" />
 <link rel="stylesheet" type="text/css"
- href="static/fusion/sample/css/welcome.css" />
   href="static/fusion/sample/css/welcome.css" />
 
 <link rel="stylesheet" type="text/css"
- href="app/fusion/styles/ecomp.css">
   href="app/fusion/styles/ecomp.css">
 
 <!-- Common scripts -->
 <script src="app/fusion/external/angular-1.4.8/angular.min.js"></script>
@@ -56,20 +57,19 @@ limitations under the License.
 <script src="app/fusion/external/angular-1.4.8/angular-cookies.min.js"></script>
 <script src="app/fusion/external/jquery/dist/jquery.min.js"></script>
 <script
- src="app/fusion/external/javascript-detect-element-resize/jquery.resize.js"></script>
   src="app/fusion/external/javascript-detect-element-resize/jquery.resize.js"></script>
 <script
- src="app/fusion/external/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
   src="app/fusion/external/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
 <script
- src="app/fusion/external/angular-gridster/dist/angular-gridster.min.js"></script>
   src="app/fusion/external/angular-gridster/dist/angular-gridster.min.js"></script>
 
 <!-- EPSDK App scripts and common services -->
 <!-- B2b Library -->
 <script src="app/fusion/external/b2b/js/b2b-angular/b2b-library.min.js"></script>
 <script src="app/fusion/scripts/DS2-services/ds2-modal/modalService.js"></script>
-<script src="app/AECBlueprintValidationUI/App.Config.js"></script>
-<script src="app/AECBlueprintValidationUI/App.Services.js"></script>
-<script
- src="app/AECBlueprintValidationUI/GetBySubmissionId/AECGetBySubmissionId.js"></script>
+<script src="app/BluvalUI/App.Config.js"></script>
+<script src="app/BluvalUI/App.Services.js"></script>
+<script src="app/BluvalUI/GetMostRecent/GetMostRecent.js"></script>
 
 <script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
 <script src="app/fusion/scripts/DS2-services/headerServiceDS2.js"></script>
@@ -83,63 +83,62 @@ limitations under the License.
 <script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
 
 <!-- Page specific items -->
-<script
- src="app/AECBlueprintValidationUI/GetBySubmissionId/AECGetBySubmissionIdController.js"></script>
-<script src="app/AECBlueprintValidationUI/GetBySubmissionId/Route.js"></script>
+<script src="app/BluvalUI/GetMostRecent/GetMostRecentController.js"></script>
+<script src="app/BluvalUI/GetMostRecent/Route.js"></script>
 
 <style>
 .controls {
-       margin-bottom: 20px;
+    margin-bottom: 20px;
 }
 
 .page-header {
-       margin-top: 20px;
+    margin-top: 20px;
 }
 
 ul {
-       list-style: none;
+    list-style: none;
 }
 
 .box {
-       height: 100%;
-       border: 1px solid #ccc;
-       background-color: #fff;
-       position: relative;
-       overflow: hidden;
+    height: 100%;
+    border: 1px solid #ccc;
+    background-color: #fff;
+    position: relative;
+    overflow: hidden;
 }
 
 .box-header {
-       background-color: #eee;
-       padding: 0px 0px 0px 0px;
-       margin-bottom: -25px;
-       cursor: move;
-       position: relative;
+    background-color: #eee;
+    padding: 0px 0px 0px 0px;
+    margin-bottom: -25px;
+    cursor: move;
+    position: relative;
 }
 
 .box-header h3 {
-       margin-top: 0px;
-       display: inline-block;
+    margin-top: 0px;
+    display: inline-block;
 }
 
 .box-content {
-       padding: 10px;
-       display: block;
-       height: 100%;
-       position: relative;
-       overflow-x: auto;
-       overflow-y: auto;
+    padding: 10px;
+    display: block;
+    height: 100%;
+    position: relative;
+    overflow-x: auto;
+    overflow-y: auto;
 }
 
 .box-header-btns {
-       top: 15px;
-       right: 10px;
-       cursor: pointer;
-       position: absolute;
+    top: 15px;
+    right: 10px;
+    cursor: pointer;
+    position: absolute;
 }
 
 .gridster {
-       border: none;
-       position: relative;
+    border: none;
+    position: relative;
 }
 
 .box-content .box-content-frame {
@@ -147,32 +146,34 @@ ul {
 }
 
 .box table {
-       border: none;
-       display: block;
+    border: none;
+    display: block;
 }
 
 .box table tr {
-       line-height: 20px;
+    line-height: 20px;
 }
 
 .box table th {
-       border: none;
-       line-height: 20px;
+    border: none;
+    line-height: 20px;
 }
 
 .menu-container {
-       margin-top: 0px
+    margin-top: 0px
 }
 
 .handle-e {
-       width: 3px;
+    width: 3px;
 }
 </style>
 </head>
-<body class="appBody" ng-app="AECGetBySubmissionId">
- <div ds2-Header class="header-container"></div>
- <div ds2-menu id="menuContainer" class="menu-container"></div>
- <div ng-view id="rightContentProfile" class="content-container"></div>
- <div ds2-Footer class="footer-container"></div>
+
+<body class="appBody" ng-app="GetMostRecent">
+    <div ds2-Header class="header-container"></div>
+    <div ds2-menu id="menuContainer" class="menu-container"></div>
+    <div ng-view id="rightContentProfile" class="content-container"></div>
+    <div ds2-Footer class="footer-container"></div>
 </body>
+
 </html>
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/GetMostRecent/GetMostRecent.js b/ui/src/main/webapp/app/BluvalUI/GetMostRecent/GetMostRecent.js
new file mode 100644 (file)
index 0000000..8fbbc64
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var appDS2 = angular.module("GetMostRecent", ['ngRoute', 'ngMessages',
+    'modalServices', 'ngCookies', 'b2b.att', 'gridster', 'ui.bootstrap',
+    'ui.bootstrap.modal', 'App.Services', 'App.Config']);
+
diff --git a/ui/src/main/webapp/app/BluvalUI/GetMostRecent/GetMostRecentController.js b/ui/src/main/webapp/app/BluvalUI/GetMostRecent/GetMostRecentController.js
new file mode 100644 (file)
index 0000000..76307eb
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var app = angular.module('GetMostRecent');
+app.controller('GetMostRecentController', function($scope, restAPISvc, $window,
+        appContext) {
+
+    initialize();
+
+    function initialize() {
+
+        $scope.loadingLabs = true;
+        $scope.loadingBlueprints = false;
+        $scope.loadingVersions = false;
+        $scope.loadingResults = false;
+        restAPISvc.getRestAPI("/api/v1/results/getlabs/", function(data) {
+            $scope.labs = data;
+            $scope.loadingLabs = false;
+        });
+    }
+
+    $scope.selectedLabChange = function() {
+        $scope.loadingLabs = false;
+        $scope.loadingBlueprints = true;
+        $scope.loadingVersions = false;
+        $scope.blueprints = [];
+        $scope.versions = [];
+        $scope.selectedBlueprint = {};
+        $scope.selectedVersion = {};
+        restAPISvc.getRestAPI("/api/v1/results/getblueprintnamesoflab/"
+                + $scope.selectedLab, function(data) {
+            $scope.blueprints = data;
+            $scope.loadingBlueprints = false;
+        });
+    }
+
+    $scope.selectedBlueprintChange = function() {
+        if (!$scope.selectedLab) {
+            return;
+        }
+        $scope.loadingLabs = false;
+        $scope.loadingBlueprints = false;
+        $scope.loadingVersions = true;
+        $scope.versions = [];
+        $scope.selectedVersion = {};
+        restAPISvc.getRestAPI("/api/v1/results/getblueprintversions/"
+                + $scope.selectedBlueprint + "/" + $scope.selectedLab,
+                function(data) {
+                    $scope.versions = data;
+                    $scope.loadingVersions = false;
+                });
+    }
+
+    $scope.selectedVersionChange = function() {
+    }
+
+    $scope.get = function() {
+        if (!$scope.selectedLab || !$scope.selectedBlueprint
+                || !$scope.selectedVersion) {
+            confirm("You must specify all data fields");
+            return;
+        }
+        $window.location.href = appContext + "/validationresults#?lab="
+                + $scope.selectedLab + "&" + "blueprintName="
+                + $scope.selectedBlueprint + "&" + "version="
+                + $scope.selectedVersion;
+    }
+
+});
diff --git a/ui/src/main/webapp/app/BluvalUI/GetMostRecent/GetMostRecentTemplate.html b/ui/src/main/webapp/app/BluvalUI/GetMostRecent/GetMostRecentTemplate.html
new file mode 100644 (file)
index 0000000..6985bd8
--- /dev/null
@@ -0,0 +1,65 @@
+<!--
+Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<div id="page-content" class="content" style="padding: 25px;">
+
+    <h1 class="heading-page">Get Most Recent Blueprint Validation
+        Results</h1>
+
+    <div class="Row">
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Lab: </label> <select
+                    ng-model="selectedLab" ng-init="labs[0]"
+                    ng-change="selectedLabChange()"
+                    ng-options="n for n in labs">
+                </select>
+            </div>
+        </div>
+
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Blueprint: </label> <select
+                    ng-model="selectedBlueprint" ng-init="blueprints[0]"
+                    ng-change="selectedBlueprintChange()"
+                    ng-options="n for n in blueprints">
+                </select>
+            </div>
+        </div>
+
+        <div class="Column">
+            <div class="form-row">
+                <label for="textinputID-3a">Select Blueprint
+                    Version: </label> <select ng-model="selectedVersion"
+                    ng-init="versions[0]"
+                    ng-change="selectedVersionChange()"
+                    ng-options="n for n in versions">
+                </select>
+            </div>
+        </div>
+    </div>
+
+    <div class="fn-ebz-container" style="position: relative; top: 25px;">
+        <button href="javascript:void(0)" id="addbtn"
+            style="bottom: -17px;" size="small"
+            att-accessibility-click="13,32"
+            class="btn btn-alt btn-small" ng-click="get();">Get</button>
+    </div>
+
+    <div ng-show="loadingLabs || loadingBlueprints || loadingVersions">
+        <img src=" static/fusion/images/giphy.gif" />
+    </div>
+
+</div>
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/GetMostRecent/Route.js b/ui/src/main/webapp/app/BluvalUI/GetMostRecent/Route.js
new file mode 100644 (file)
index 0000000..951eafc
--- /dev/null
@@ -0,0 +1,22 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+appDS2.config(function($routeProvider) {
+    $routeProvider.otherwise({
+        templateUrl : 'app/BluvalUI/GetMostRecent/GetMostRecentTemplate.html',
+        controller : "GetMostRecentController"
+    });
+});
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/NewSubmission/NewSubmission.html b/ui/src/main/webapp/app/BluvalUI/NewSubmission/NewSubmission.html
new file mode 100644 (file)
index 0000000..430e4de
--- /dev/null
@@ -0,0 +1,165 @@
+<!--
+Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<!DOCTYPE html>
+<!-- Single-page application for EPSDK-App using DS2 look and feel. -->
+<html>
+
+<head>
+    <meta charset="ISO-8859-1">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
+
+    <title>New Submission</title>
+
+    <!-- B2b Library -->
+    <link rel="stylesheet" type="text/css" href="app/fusion/external/b2b/css/b2b-angular/b2b-angular.css">
+    <link rel="stylesheet" type="text/css" href="app/fusion/external/b2b/css/b2b-angular/font_icons.css">
+
+    <!-- icons in open source -->
+    <link rel="stylesheet" type="text/css" href="app/fusion/external/ds2/css/digital-ng-library/ionicons.css">
+    <link rel="stylesheet" type="text/css" href="app/fusion/external/ds2/css/digital-ng-library/ecomp-ionicons.css">
+
+    <link rel="stylesheet" type="text/css" href="app/fusion/external/angular-bootstrap/ui-bootstrap-csp.css">
+    <link rel="stylesheet" type="text/css" href="app/fusion/external/angular-gridster/dist/angular-gridster.min.css">
+    <link rel="stylesheet" type="text/css" href="static/fusion/sample/css/scribble.css" />
+    <link rel="stylesheet" type="text/css" href="static/fusion/sample/css/welcome.css" />
+
+    <link rel="stylesheet" type="text/css" href="app/fusion/styles/ecomp.css">
+
+    <!-- Common scripts -->
+    <script src="app/fusion/external/angular-1.4.8/angular.min.js"></script>
+    <script src="app/fusion/external/angular-1.4.8/angular-messages.js"></script>
+    <script src="app/fusion/external/angular-1.4.8/angular-touch.js"></script>
+    <script src="app/fusion/external/angular-1.4.8/angular-sanitize.js"></script>
+    <script src="app/fusion/external/angular-1.4.8/angular-route.min.js"></script>
+    <script src="app/fusion/external/angular-1.4.8/angular-cookies.min.js"></script>
+    <script src="app/fusion/external/jquery/dist/jquery.min.js"></script>
+    <script src="app/fusion/external/javascript-detect-element-resize/jquery.resize.js"></script>
+    <script src="app/fusion/external/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
+    <script src="app/fusion/external/angular-gridster/dist/angular-gridster.min.js"></script>
+
+    <!-- EPSDK App scripts and common services -->
+    <!-- B2b Library -->
+    <script src="app/fusion/external/b2b/js/b2b-angular/b2b-library.min.js"></script>
+    <script src="app/fusion/scripts/DS2-services/ds2-modal/modalService.js"></script>
+    <script src="app/BluvalUI/App.Config.js"></script>
+    <script src="app/BluvalUI/App.Services.js"></script>
+    <script src="app/BluvalUI/NewSubmission/NewSubmission.js"></script>
+
+    <script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
+    <script src="app/fusion/scripts/DS2-services/headerServiceDS2.js"></script>
+    <script src="app/fusion/scripts/DS2-services/leftMenuServiceDS2.js"></script>
+    <script src="app/fusion/scripts/DS2-services/manifestService.js"></script>
+
+    <script src="app/fusion/scripts/DS2-directives/footer.js"></script>
+    <script src="app/fusion/scripts/DS2-directives/ds2Header.js"></script>
+    <script src="app/fusion/scripts/DS2-directives/ds2LeftMenu.js"></script>
+    <script src="app/fusion/scripts/DS2-directives/b2b-leftnav-ext.js"></script>
+    <script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
+
+    <!-- Page specific items -->
+    <script src="app/BluvalUI/NewSubmission/NewSubmissionController.js"></script>
+    <script src="app/BluvalUI/NewSubmission/Route.js"></script>
+
+    <style>
+        .controls {
+            margin-bottom: 20px;
+        }
+
+        .page-header {
+            margin-top: 20px;
+        }
+
+        ul {
+            list-style: none;
+        }
+
+        .box {
+            height: 100%;
+            border: 1px solid #ccc;
+            background-color: #fff;
+            position: relative;
+            overflow: hidden;
+        }
+
+        .box-header {
+            background-color: #eee;
+            padding: 0px 0px 0px 0px;
+            margin-bottom: -25px;
+            cursor: move;
+            position: relative;
+        }
+
+        .box-header h3 {
+            margin-top: 0px;
+            display: inline-block;
+        }
+
+        .box-content {
+            padding: 10px;
+            display: block;
+            height: 100%;
+            position: relative;
+            overflow-x: auto;
+            overflow-y: auto;
+        }
+
+        .box-header-btns {
+            top: 15px;
+            right: 10px;
+            cursor: pointer;
+            position: absolute;
+        }
+
+        .gridster {
+            border: none;
+            position: relative;
+        }
+
+        .box-content .box-content-frame {}
+
+        .box table {
+            border: none;
+            display: block;
+        }
+
+        .box table tr {
+            line-height: 20px;
+        }
+
+        .box table th {
+            border: none;
+            line-height: 20px;
+        }
+
+        .menu-container {
+            margin-top: 0px
+        }
+
+        .handle-e {
+            width: 3px;
+        }
+    </style>
+</head>
+
+<body class="appBody" ng-app="NewSubmission">
+    <div ds2-Header class="header-container"></div>
+    <div ds2-menu id="menuContainer" class="menu-container"></div>
+    <div ng-view id="rightContentProfile" class="content-container"></div>
+    <div ds2-Footer class="footer-container"></div>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/NewSubmission/NewSubmission.js b/ui/src/main/webapp/app/BluvalUI/NewSubmission/NewSubmission.js
new file mode 100644 (file)
index 0000000..e46c86a
--- /dev/null
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var appDS2 = angular.module("NewSubmission", ['ngRoute', 'ngMessages',
+    'modalServices', 'ngCookies', 'b2b.att', 'gridster', 'ui.bootstrap',
+    'ui.bootstrap.modal', 'App.Services']);
\ No newline at end of file
  * limitations under the License.
  */
 
-var app = angular.module('AECNewSubmission');
+var app = angular.module('NewSubmission');
 app
         .controller(
-                'AECNewSubmissionController',
+                'NewSubmissionController',
                 function($scope, restAPISvc) {
 
                     initialize();
@@ -25,7 +25,7 @@ app
                     function initialize() {
                         restAPISvc
                                 .getRestAPI(
-                                        "/api/blueprintInstanceForValidation/",
+                                        "/api/v1/blueprintinstanceforvalidation/",
                                         function(data) {
                                             $scope.blueprintInstancesForValidation = data;
                                             $scope.blueprintNames = [];
@@ -41,12 +41,12 @@ app
                                                                 }
                                                             });
                                         });
-                        restAPISvc.getRestAPI("/api/timeslots/",
-                                function(data) {
-                                    $scope.timeslots = data;
-                                    $scope.declerativeTimeslots = [];
-                                    angular.forEach($scope.timeslots, function(
-                                            timeslot) {
+                        restAPISvc.getRestAPI("/api/v1/timeslots/", function(
+                                data) {
+                            $scope.timeslots = data;
+                            $scope.declerativeTimeslots = [];
+                            angular.forEach($scope.timeslots,
+                                    function(timeslot) {
                                         var temp = "id: " + timeslot.timeslotId
                                                 + " Start date and time: "
                                                 + timeslot.startDateTime
@@ -57,11 +57,15 @@ app
                                                 + " lab :" + timeslot.lab.lab;
                                         $scope.declerativeTimeslots.push(temp);
                                     });
-                                });
+                        });
                     }
                     $scope.selectedBluePrintNameChange = function() {
                         $scope.blueprintVersions = [];
                         $scope.blueprintLayers = [];
+                        $scope.optionals = [];
+                        $scope.selectedBlueprintVersion = {};
+                        $scope.selectedBlueprintLayer = {};
+                        $scope.selectedOptional = "";
                         angular
                                 .forEach(
                                         $scope.blueprintInstancesForValidation,
@@ -76,7 +80,13 @@ app
                                         });
                     }
                     $scope.selectedBluePrintVersionChange = function() {
+                        if (!$scope.selectedBlueprintName) {
+                            return;
+                        }
                         $scope.blueprintLayers = [];
+                        $scope.optionals = [];
+                        $scope.selectedBlueprintLayer = {};
+                        $scope.selectedOptional = "";
                         angular
                                 .forEach(
                                         $scope.blueprintInstancesForValidation,
@@ -91,30 +101,23 @@ app
                                                 }
                                             }
                                         });
+                        $scope.blueprintLayers.push("all");
+                    }
+
+                    $scope.selectedBluePrintLayerChange = function() {
+                        $scope.optionals = [ 'true', 'false' ];
                     }
 
                     $scope.submit = function() {
                         if (!$scope.selectedBlueprintName
                                 || !$scope.selectedBlueprintVersion
                                 || !$scope.selectedBlueprintLayer
+                                || !$scope.selectedOptional
                                 || !$scope.selectedDeclerativeTimeslot) {
                             confirm("You must specify all data fields");
                             return;
                         }
-                        var finalBlueprint;
                         var finalTimeslot;
-                        angular
-                                .forEach(
-                                        $scope.blueprintInstancesForValidation,
-                                        function(blueprintInstance) {
-                                            if (blueprintInstance["blueprint"]["blueprintName"] === $scope.selectedBlueprintName) {
-                                                if (blueprintInstance["version"] === $scope.selectedBlueprintVersion) {
-                                                    if (blueprintInstance["layer"] === $scope.selectedBlueprintLayer) {
-                                                        finalBlueprint = blueprintInstance;
-                                                    }
-                                                }
-                                            }
-                                        });
                         var selectedDeclerativeTimeslotId = $scope.selectedDeclerativeTimeslot
                                 .substring(
                                         $scope.selectedDeclerativeTimeslot
@@ -131,17 +134,35 @@ app
                                                 finalTimeslot = timeslot;
                                             }
                                         });
-                        var submission = {
-                            "blueprintInstanceForValidation" : finalBlueprint,
+                        var allLayers = "false";
+                        if ($scope.selectedBlueprintLayer === 'all') {
+                            allLayers = "true";
+                        }
+                        var wRobotTestResults = [];
+                        if (allLayers === "false") {
+                            wRobotTestResults = [ {
+                                "blueprintLayer" : $scope.selectedBlueprintLayer
+                            } ];
+                        }
+
+                        var validationNexusTestResult = {
+                            "blueprintName" : $scope.selectedBlueprintName,
+                            "version" : $scope.selectedBlueprintVersion,
+                            "allLayers" : allLayers,
+                            "wRobotNexusTestResults" : wRobotTestResults,
+                            "optional" : $scope.selectedOptional
+                        };
+                        var submissionData = {
+                            "validationNexusTestResult" : validationNexusTestResult,
                             "timeslot" : finalTimeslot
                         };
                         restAPISvc
                                 .postRestAPI(
-                                        "/api/submission/",
-                                        submission,
+                                        "/api/v1/submission/",
+                                        submissionData,
                                         function(data) {
                                             if (data !== undefined) {
-                                                var confirmText = "The blueprint instance for validation has been submitted successfully. Submissionn id:"
+                                                var confirmText = "The blueprint instance for validation has been submitted successfully. Submission id:"
                                                         + data.submissionId;
                                                 confirm(confirmText);
                                             } else {
@@ -151,6 +172,7 @@ app
                         $scope.selectedBlueprintName = {};
                         $scope.selectedBlueprintVersion = {};
                         $scope.selectedBlueprintLayer = {};
+                        $scope.selectedOptional = "";
                         $scope.selectedDeclerativeTimeslot = {};
                     }
 
diff --git a/ui/src/main/webapp/app/BluvalUI/NewSubmission/NewSubmissionTemplate.html b/ui/src/main/webapp/app/BluvalUI/NewSubmission/NewSubmissionTemplate.html
new file mode 100644 (file)
index 0000000..049c8bc
--- /dev/null
@@ -0,0 +1,85 @@
+<!--
+Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<div id="page-content" class="content" style="padding: 25px;">
+    <div>
+        <h1 class="heading-page">New Submission</h1>
+        <h2 class="heading-small">Submission form</h2>
+
+        <div>
+            <div class="form-row">
+                <label for="textinputID-3a">Select Blueprint: </label> <select
+                    ng-model="selectedBlueprintName"
+                    ng-change="selectedBluePrintNameChange()"
+                    ng-options="n for n in blueprintNames">
+                </select>
+            </div>
+        </div>
+        <br>
+
+        <div>
+            <div class="form-row">
+                <label for="textinputID-3a">Select Blueprint
+                    Version: </label> <select
+                    ng-model="selectedBlueprintVersion"
+                    ng-change="selectedBluePrintVersionChange()"
+                    ng-options="y for y in blueprintVersions">
+                </select>
+            </div>
+        </div>
+        <br>
+
+        <div>
+            <div class="form-row">
+                <label for="textinputID-3a">Select Blueprint
+                    Layer: </label> <select ng-model="selectedBlueprintLayer"
+                    ng-change="selectedBluePrintLayerChange()"
+                    ng-options="l for l in blueprintLayers">
+                </select>
+            </div>
+        </div>
+        <br>
+
+        <div>
+            <div class="form-row">
+                <label for="textinputID-3a">Optional Test Cases: </label> <select ng-model="selectedOptional"
+                    ng-change="selectedOptionalChange()"
+                    ng-options="l for l in optionals">
+                </select>
+            </div>
+        </div>
+        <br>
+
+
+        <div>
+            <div class="form-row">
+                <label for="textinputID-3a">Select Timeslot: </label> <select
+                    ng-model="selectedDeclerativeTimeslot"
+                    ng-options="v for v in declerativeTimeslots">
+                </select>
+            </div>
+        </div>
+        <br>
+
+        <div class="fn-ebz-container"
+            style="position: relative; top: 25px;">
+            <button href="javascript:void(0)" id="addbtn"
+                style="bottom: -17px;" size="small"
+                att-accessibility-click="13,32"
+                class="btn btn-alt btn-small" ng-click="submit();">Submit</button>
+        </div>
+    </div>
+</div>
diff --git a/ui/src/main/webapp/app/BluvalUI/NewSubmission/Route.js b/ui/src/main/webapp/app/BluvalUI/NewSubmission/Route.js
new file mode 100644 (file)
index 0000000..a9c8484
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+appDS2
+    .config(function ($routeProvider) {
+        $routeProvider
+            .otherwise({
+                templateUrl: 'app/BluvalUI/NewSubmission/NewSubmissionTemplate.html',
+                controller: "NewSubmissionController"
+            });
+    });
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/ValidationResults/Route.js b/ui/src/main/webapp/app/BluvalUI/ValidationResults/Route.js
new file mode 100644 (file)
index 0000000..57845b4
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+appDS2
+        .config(function($routeProvider) {
+            $routeProvider
+                    .otherwise({
+                        templateUrl : 'app/BluvalUI/ValidationResults/ValidationResultsTemplate.html',
+                        controller : "ValidationResultsController"
+                    });
+        });
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/ValidationResults/TestSuiteResults/TestSuiteResultsController.js b/ui/src/main/webapp/app/BluvalUI/ValidationResults/TestSuiteResults/TestSuiteResultsController.js
new file mode 100644 (file)
index 0000000..8804de8
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var app = angular.module('ValidationResults');
+app.controller('TestSuiteResultsController', function($scope,
+        generalValidationResultsSvc) {
+
+    initialize();
+
+    function initialize() {
+        $scope.showTestSuitesResults = false;
+        $scope.wRobotTestResults = [];
+        $scope.selectedTestId = null;
+        $scope.selectedTest = null;
+        $scope.resultsLayers = [];
+        $scope.resultsLayerTestSuitesNames = [];
+        $scope.selectedRobotTestResult = [];
+        $scope.selectedLayer = [];
+        $scope.selectedTestSuiteName = [];
+
+        $scope.validationNexusTestResult = $scope.params;
+        $scope.wRobotTestResults = $scope.params.wRobotNexusTestResults;
+        if (generalValidationResultsSvc
+                .mapResult($scope.validationNexusTestResult) === null) {
+            confirm("No data was found");
+        } else {
+            $scope.showTestSuitesResults = true;
+            angular.forEach($scope.wRobotTestResults, function(result) {
+                $scope.resultsLayers.push(result.blueprintLayer);
+            });
+        }
+
+    }
+
+    $scope.selectedResultsLayerChange = function(selectedLayer) {
+        $scope.selectedTestId = null;
+        $scope.selectedTest = null;
+        $scope.resultsLayerTestSuitesNames = [];
+        $scope.robotTestResults = [];
+        $scope.selectedRobotTestResult = [];
+        $scope.selectedTestSuiteName = [];
+        var selectedLayerResult = [];
+        angular.forEach($scope.wRobotTestResults, function(result) {
+            if (result.blueprintLayer === selectedLayer) {
+                selectedLayerResult = result;
+            }
+        });
+        $scope.robotTestResults = selectedLayerResult.robotTestResults;
+        angular.forEach($scope.robotTestResults, function(robotTestResult) {
+            $scope.resultsLayerTestSuitesNames.push(robotTestResult.name);
+        });
+    }
+
+    $scope.selectedTestSuitesNameChange = function(selectedTestSuiteName) {
+        if (!selectedTestSuiteName) {
+            return;
+        }
+        $scope.selectedTestId = null;
+        $scope.selectedTest = null;
+        angular.forEach($scope.robotTestResults, function(robotTestResult) {
+            if (robotTestResult.name.trim() === selectedTestSuiteName.trim()) {
+                $scope.selectedRobotTestResult = robotTestResult;
+            }
+        });
+    }
+
+    $scope.setClickedTest = function(test) {
+        $scope.selectedTestId = test.id;
+        $scope.selectedTest = test;
+    }
+
+});
diff --git a/ui/src/main/webapp/app/BluvalUI/ValidationResults/TestSuiteResults/TestSuiteResultsModal.html b/ui/src/main/webapp/app/BluvalUI/ValidationResults/TestSuiteResults/TestSuiteResultsModal.html
new file mode 100644 (file)
index 0000000..82eb5fe
--- /dev/null
@@ -0,0 +1,455 @@
+<!--
+Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<div id="page-content" class="content" style="padding: 25px;">
+
+    <style>
+.graph, .empty-graph {
+    border: 1px solid #ccc;
+    width: auto;
+    height: 7px;
+    padding: 0;
+    background: #f33;
+}
+
+.pass-bar {
+    background: #1d4;
+}
+
+.pass-bar, .fail-bar {
+    float: left;
+    height: 100%;
+}
+
+div.box {
+    border: 1px solid black;
+}
+
+.bluvalDetails .property {
+    width: 30%;
+    display: inline-block;
+    box-sizing: border-box;
+    text-align: left;
+}
+
+.bluvalDetails .value {
+    text-align: left;
+    padding-left: 10px;
+    width: 70%;
+    display: inline-block;
+    box-sizing: border-box;
+}
+
+.selected {
+    background-color: #337ab7;
+    font-weight: bold;
+}
+
+#page-content {
+    margin-left: 20px;
+}
+</style>
+
+    <div ng-show="showTestSuitesResults">
+        <h2 class="heading-small"></h2>
+        <h1 class="heading-page">Display Test Suites Results</h1>
+
+        <h2 class="heading-small"></h2>
+        <div>
+            <h2 class="heading-small">Select a blueprint layer:</h2>
+            <div>
+                <select ng-model="selectedLayer"
+                    ng-init="resultsLayers[0]"
+                    ng-change="selectedResultsLayerChange(selectedLayer)"
+                    ng-options="n for n in resultsLayers">
+                </select>
+            </div>
+
+            <h2 class="heading-small">Select a test suite of the
+                selected layer in order to be displayed:</h2>
+            <div>
+                <select ng-model="selectedTestSuiteName"
+                    ng-init="resultsLayerTestSuitesNames[0]"
+                    ng-change="selectedTestSuitesNameChange(selectedTestSuiteName)"
+                    ng-options="n for n in resultsLayerTestSuitesNames">
+                </select>
+            </div>
+        </div>
+
+        <br> <br> <br>
+
+        <div
+            ng-hide="selectedLayer == null || selectedTestSuiteName == null">
+            <div>
+                <h2 class="heading-small"></h2>
+                <div class="box">
+                    <h3 class="heading-small">
+                        <u>General Info</u>
+                    </h3>
+                    <p></p>
+
+                    <p></p>
+                    <p>Name: {{selectedRobotTestResult.name}}</p>
+                    <p>Generated:
+                        {{selectedRobotTestResult.robot.generated}}</p>
+                    <p>Generator:
+                        {{selectedRobotTestResult.robot.generator}}</p>
+                    <p>Errors:
+                        {{selectedRobotTestResult.robot.errors}}</p>
+
+                    <h2 class="heading-small"></h2>
+                    <h3 class="heading-small">
+                        <u>Test Statistics</u>
+                    </h3>
+                    <p></p>
+                    <table class="striped" cellspacing="0"
+                        cellpadding="10">
+                        <caption>
+                            <h3></h3>
+                        </caption>
+                        <thead>
+                            <th>
+                                <p>&nbsp;Total statistics&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Total&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Pass&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Fail&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Pass / Fail&nbsp;</p>
+                            </th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                            <tr
+                                ng-repeat="stat in selectedRobotTestResult.robot.statistics.total.stat">
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                                    stat.content }}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                                    (stat.fail * 1) + (stat.pass*1) }}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                                    stat.pass }}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                                    stat.fail}}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">
+                                    <div class="graph">
+                                        <div class="pass-bar"
+                                            ng-style="{ 'width': {{(100* stat.pass/((stat.fail * 1) + (stat.pass*1)) )| number:0}} + '%' }"
+                                            title="100%"></div>
+                                        <div class="fail-bar"
+                                            ng-style="{ 'width': {{(100* stat.fail/((stat.fail * 1) + (stat.pass*1)) )| number:0}} + '%' }"
+                                            title="0%"></div>
+                                    </div>
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
+
+                    <br>
+
+                    <h3 class="heading-small"></h3>
+                    <table class="striped" cellspacing="0"
+                        cellpadding="10">
+                        <caption>
+                            <h3></h3>
+                        </caption>
+                        <thead>
+                            <th>
+                                <p>&nbsp;Statistics by Tag&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Total&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Pass&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Fail&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Pass / Fail&nbsp;</p>
+                            </th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                            <tr
+                                ng-repeat="stat in selectedRobotTestResult.robot.statistics.tag.stat">
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                                    stat.content }}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                                    (stat.fail * 1) + (stat.pass*1) }}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                                    stat.pass }}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                                    stat.fail}}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">
+                                    <div class="graph">
+                                        <div class="pass-bar"
+                                            ng-style="{ 'width': {{(100* stat.pass/((stat.fail * 1) + (stat.pass*1)) )| number:0}} + '%' }"
+                                            title="100%"></div>
+                                        <div class="fail-bar"
+                                            ng-style="{ 'width': {{(100* stat.fail/((stat.fail * 1) + (stat.pass*1)) )| number:0}} + '%' }"
+                                            title="0%"></div>
+                                    </div>
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
+
+                    <br>
+
+                    <h3 class="heading-small"></h3>
+                    <table class="striped" cellspacing="0"
+                        cellpadding="10">
+                        <caption>
+                            <h3></h3>
+                        </caption>
+                        <thead>
+                            <th>
+                                <p>&nbsp;Statistics by Suite&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Total&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Pass&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Fail&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Pass / Fail&nbsp;</p>
+                            </th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                            <tr
+                                ng-repeat="stat in selectedRobotTestResult.robot.statistics.suite.stat">
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                                    stat.content }}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                                    (stat.fail * 1) + (stat.pass*1) }}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                                    stat.pass }}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                                    stat.fail}}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">
+                                    <div class="graph">
+                                        <div class="pass-bar"
+                                            ng-style="{ 'width': {{(100* stat.pass/((stat.fail * 1) + (stat.pass*1)) )| number:0}} + '%' }"
+                                            title="100%"></div>
+                                        <div class="fail-bar"
+                                            ng-style="{ 'width': {{(100* stat.fail/((stat.fail * 1) + (stat.pass*1)) )| number:0}} + '%' }"
+                                            title="0%"></div>
+                                    </div>
+                                </td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+
+                <h2 class="heading-small"></h2>
+                <div class="box">
+                    <h3 class="heading-small">
+                        <a href="javascript:void(0);"
+                            ng-click="showDetailsLog = ! showDetailsLog">Test
+                            Execution Log</a>
+                    </h3>
+                    <div ng-show="showDetailsLog">
+                        <p></p>
+                        <p>Root Suite Full Name:
+                            {{selectedRobotTestResult.robot.suite.name}}</p>
+                        <p>Source:
+                            {{selectedRobotTestResult.robot.suite.source}}</p>
+                        <p>Status:
+                            {{selectedRobotTestResult.robot.suite.status.status}}</p>
+                        <p>Start time:
+                            {{selectedRobotTestResult.robot.suite.status.starttime}}</p>
+                        <p>End time:
+                            {{selectedRobotTestResult.robot.suite.status.endtime}}</p>
+
+                        <h2 class="heading-small"></h2>
+                        <p></p>
+                        <p>Sub-suite Full Name:
+                            {{selectedRobotTestResult.robot.suite.suite.name}}</p>
+                        <p>Documentation:
+                            {{selectedRobotTestResult.robot.suite.suite.doc}}</p>
+                        <p>Source:
+                            {{selectedRobotTestResult.robot.suite.suite.source}}</p>
+                        <p>Status:
+                            {{selectedRobotTestResult.robot.suite.suite.status.status}}</p>
+                        <p>Start time:
+                            {{selectedRobotTestResult.robot.suite.suite.status.starttime}}</p>
+                        <p>End time:
+                            {{selectedRobotTestResult.robot.suite.suite.status.endtime}}</p>
+                    </div>
+                </div>
+
+                <h2 class="heading-small"></h2>
+                <div class="box">
+                    <ul>
+                        <h4 class="heading-small">Sub-suite Robot
+                            keywords</h4>
+                        <li
+                            ng-repeat="kw in selectedRobotTestResult.robot.suite.suite.kw"
+                            ng-include="'kwVal'"></li>
+                    </ul>
+                </div>
+
+                <h2 class="heading-small"></h2>
+                <div class="box">
+                    <h3 class="heading-small">Test Cases</h3>
+                    <table class="striped" cellspacing="0"
+                        cellpadding="10">
+                        <caption>
+                            <h3></h3>
+                        </caption>
+                        <thead>
+                            <th>
+                                <p>&nbsp;Full Name&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Documentation&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Status&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Start Time&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>End Time&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Critical&nbsp;</p>
+                            </th>
+                            <th>
+                                <p>Message&nbsp;</p>
+                            </th>
+                            </tr>
+                        </thead>
+                        <tbody>
+                            <tr
+                                ng-repeat="test in selectedRobotTestResult.robot.suite.suite.test"
+                                ng-class="{selected:test.id == selectedTestId}"
+                                ng-click="setClickedTest(test)">
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                                    test.name }}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{test.doc}}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{test.status.status}}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{test.status.starttime}}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{test.status.endtime}}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{test.status.critical}}</td>
+                                <td
+                                    style="padding-left: 10px; font-size: 15px; width: 13%;">{{test.status.content}}</td>
+                            </tr>
+                        </tbody>
+                    </table>
+                </div>
+
+                <h2 class="heading-small"></h2>
+                <div class="box">
+                    <ul>
+                        <h4 class="heading-small">Robot keywords of
+                            the selected test case</h4>
+                        <li ng-repeat="kw in selectedTest.kw"
+                            ng-include="'kwVal3'"></li>
+                    </ul>
+                </div>
+
+            </div>
+        </div>
+
+        <script type="text/ng-template" id="kwVal">
+<h2 class="heading-small"></h2>
+                        <h4>
+                            <a href="javascript:void(0);" ng-click="showDetails = ! showDetails">
+                                {{kw.name}}</a>
+                        </h4>
+                        <div ng-show="showDetails">
+                            <p>&emsp;&emsp;&emsp;&emsp; Type:
+                                {{kw.type}}</p>
+                            <p>&emsp;&emsp;&emsp;&emsp; Library:
+                                {{kw.library}}</p>
+                            <p>&emsp;&emsp;&emsp;&emsp;
+                                Documentation: {{kw.doc}}</p>
+                            <p>&emsp;&emsp;&emsp;&emsp; Start time:
+                                {{kw.status.starttime}}</p>
+                            <p>&emsp;&emsp;&emsp;&emsp; End time:
+                                {{kw.status.endtime}}</p>
+                            <p>&emsp;&emsp;&emsp;&emsp; Status:
+                                {{kw.status.status}}</p>
+                            <p></p>
+                            <p>&emsp;&emsp;&emsp;&emsp; Used Robot
+                                keywords:</p>
+   <ul ng-if="kw.kw">
+    <li ng-repeat="kw in kw.kw" ng-include="'kwVal'"></li>
+  </ul>
+</script>
+
+        <script type="text/ng-template" id="kwVal3">
+<h2 class="heading-small"></h2>
+                        <h4>
+                            <a href="javascript:void(0);" ng-click="showDetails4 = ! showDetails4">
+                                {{kw.name}}</a>
+                        </h4>
+                        <div ng-show="showDetails4">
+                            <p>&emsp;&emsp;&emsp;&emsp; Type:
+                                {{kw.type}}</p>
+                            <p>&emsp;&emsp;&emsp;&emsp; Library:
+                                {{kw.library}}</p>
+                            <p>&emsp;&emsp;&emsp;&emsp;
+                                Documentation: {{kw.doc}}</p>
+                            <p>&emsp;&emsp;&emsp;&emsp; Start time:
+                                {{kw.status.starttime}}</p>
+                            <p>&emsp;&emsp;&emsp;&emsp; End time:
+                                {{kw.status.endtime}}</p>
+                            <p>&emsp;&emsp;&emsp;&emsp; Status:
+                                {{kw.status.status}}</p>
+                            <p></p>
+                            <p>&emsp;&emsp;&emsp;&emsp; Used Robot
+                                keywords:</p>
+   <ul ng-if="kw.kw">
+    <li ng-repeat="kw in kw.kw" ng-include="'kwVal3'"></li>
+  </ul>
+</script>
+    </div>
+</div>
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResults.Services.js b/ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResults.Services.js
new file mode 100644 (file)
index 0000000..bfda0b1
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var app = angular.module('ValidationResults');
+
+app.factory('generalValidationResultsSvc', [ function() {
+    var svc = [];
+    svc.getBlueprintLayers = function(wRobotNexusTestResults) {
+        var layers = [];
+        angular.forEach(wRobotNexusTestResults,
+                function(wRobotNexusTestResult) {
+                    if (wRobotNexusTestResult.blueprintLayer !== undefined) {
+                        layers.push(wRobotNexusTestResult.blueprintLayer);
+                    }
+                });
+        return layers;
+    };
+    svc.mapResult = function(validationNexusTestResult) {
+        if (!validationNexusTestResult.timestamp) {
+            return null;
+        }
+        if (!validationNexusTestResult.wRobotNexusTestResults) {
+            return null;
+        }
+        if (validationNexusTestResult.wRobotNexusTestResults.length === 0) {
+            return null;
+        }
+        var resultExistence = false;
+        angular.forEach(validationNexusTestResult.wRobotNexusTestResults,
+                function(result) {
+                    if (result.robotTestResults
+                            && result.robotTestResults.length > 0) {
+                        resultExistence = true;
+                    }
+                });
+        if (resultExistence) {
+            if (validationNexusTestResult.result === true) {
+                return 'SUCCESS';
+            }
+            return 'FAILURE'
+        }
+        return null;
+    };
+    svc.filterWithLayer = function(validationNexusTestResults, filterLayer) {
+        if (filterLayer === undefined || filterLayer === '') {
+            return validationNexusTestResults;
+        }
+        var filteredResults = [];
+        angular.forEach(validationNexusTestResults, function(
+                validationNexusTestResult) {
+            angular.forEach(validationNexusTestResult.wRobotNexusTestResults,
+                    function(wRobotNexusTestResult) {
+                        if (wRobotNexusTestResult.blueprintLayer.toLowerCase()
+                                .includes(filterLayer.toLowerCase())) {
+                            filteredResults.push(validationNexusTestResult);
+                        }
+                    });
+        });
+        return filteredResults;
+    }
+    svc.filterWithResult = function(validationNexusTestResults, filterResult) {
+        if (filterResult === undefined || filterResult === '') {
+            return validationNexusTestResults;
+        }
+        var filteredResults = [];
+        angular.forEach(validationNexusTestResults, function(
+                validationNexusTestResult) {
+            if (validationNexusTestResult.result === true
+                    && 'success'.includes(filterResult.toLowerCase())) {
+                filteredResults.push(validationNexusTestResult);
+            } else if (validationNexusTestResult.result === false
+                    && 'failure'.includes(filterResult.toLowerCase())) {
+                filteredResults.push(validationNexusTestResult);
+            }
+        });
+        return filteredResults;
+    }
+    svc.getLab = function(silo, silos) {
+        var lab = null;
+        angular.forEach(silos, function(siloData) {
+            if (silo === siloData.silo) {
+                lab = siloData.lab.lab;
+            }
+        });
+        return lab;
+    }
+    return svc;
+} ]);
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResults.html b/ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResults.html
new file mode 100644 (file)
index 0000000..7015b76
--- /dev/null
@@ -0,0 +1,183 @@
+<!--
+Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+
+<!DOCTYPE html>
+<!-- Single-page application for EPSDK-App using DS2 look and feel. -->
+<html>
+
+<head>
+<meta charset="ISO-8859-1">
+<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
+
+<title>Get Validation Results</title>
+
+<!-- B2b Library -->
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/b2b/css/b2b-angular/b2b-angular.css">
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/b2b/css/b2b-angular/font_icons.css">
+
+<!-- icons in open source -->
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/ds2/css/digital-ng-library/ionicons.css">
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/ds2/css/digital-ng-library/ecomp-ionicons.css">
+
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/angular-bootstrap/ui-bootstrap-csp.css">
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/external/angular-gridster/dist/angular-gridster.min.css">
+<link rel="stylesheet" type="text/css"
+    href="static/fusion/sample/css/scribble.css" />
+<link rel="stylesheet" type="text/css"
+    href="static/fusion/sample/css/welcome.css" />
+
+<link rel="stylesheet" type="text/css"
+    href="app/fusion/styles/ecomp.css">
+
+<!-- Common scripts -->
+<script src="app/fusion/external/angular-1.4.8/angular.min.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-messages.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-touch.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-sanitize.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-route.min.js"></script>
+<script src="app/fusion/external/angular-1.4.8/angular-cookies.min.js"></script>
+<script src="app/fusion/external/jquery/dist/jquery.min.js"></script>
+<script
+    src="app/fusion/external/javascript-detect-element-resize/jquery.resize.js"></script>
+<script
+    src="app/fusion/external/angular-bootstrap/ui-bootstrap-tpls.min.js"></script>
+<script
+    src="app/fusion/external/angular-gridster/dist/angular-gridster.min.js"></script>
+
+<!-- EPSDK App scripts and common services -->
+<!-- B2b Library -->
+<script src="app/fusion/external/b2b/js/b2b-angular/b2b-library.min.js"></script>
+<script src="app/fusion/scripts/DS2-services/ds2-modal/modalService.js"></script>
+<script src="app/BluvalUI/App.Config.js"></script>
+<script src="app/BluvalUI/App.Services.js"></script>
+<script src="app/BluvalUI/ValidationResults/ValidationResults.js"></script>
+
+<script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
+<script src="app/fusion/scripts/DS2-services/headerServiceDS2.js"></script>
+<script src="app/fusion/scripts/DS2-services/leftMenuServiceDS2.js"></script>
+<script src="app/fusion/scripts/DS2-services/manifestService.js"></script>
+
+<script src="app/fusion/scripts/DS2-directives/footer.js"></script>
+<script src="app/fusion/scripts/DS2-directives/ds2Header.js"></script>
+<script src="app/fusion/scripts/DS2-directives/ds2LeftMenu.js"></script>
+<script src="app/fusion/scripts/DS2-directives/b2b-leftnav-ext.js"></script>
+<script src="app/fusion/scripts/DS2-services/userInfoServiceDS2.js"></script>
+
+<!-- Page specific items -->
+<script
+    src="app/BluvalUI/ValidationResults/ValidationResults.Services.js"></script>
+<script
+    src="app/BluvalUI/ValidationResults/ValidationResultsController.js"></script>
+<script
+    src="app/BluvalUI/ValidationResults/TestSuiteResults/TestSuiteResultsController.js"></script><script src="app/BluvalUI/ValidationResults/Route.js"></script>
+
+<style>
+.controls {
+    margin-bottom: 20px;
+}
+
+.page-header {
+    margin-top: 20px;
+}
+
+ul {
+    list-style: none;
+}
+
+.box {
+    height: 100%;
+    border: 1px solid #ccc;
+    background-color: #fff;
+    position: relative;
+    overflow: hidden;
+}
+
+.box-header {
+    background-color: #eee;
+    padding: 0px 0px 0px 0px;
+    margin-bottom: -25px;
+    cursor: move;
+    position: relative;
+}
+
+.box-header h3 {
+    margin-top: 0px;
+    display: inline-block;
+}
+
+.box-content {
+    padding: 10px;
+    display: block;
+    height: 100%;
+    position: relative;
+    overflow-x: auto;
+    overflow-y: auto;
+}
+
+.box-header-btns {
+    top: 15px;
+    right: 10px;
+    cursor: pointer;
+    position: absolute;
+}
+
+.gridster {
+    border: none;
+    position: relative;
+}
+
+.box-content .box-content-frame {
+
+}
+
+.box table {
+    border: none;
+    display: block;
+}
+
+.box table tr {
+    line-height: 20px;
+}
+
+.box table th {
+    border: none;
+    line-height: 20px;
+}
+
+.menu-container {
+    margin-top: 0px
+}
+
+.handle-e {
+    width: 3px;
+}
+</style>
+</head>
+
+<body class="appBody" ng-app="ValidationResults">
+    <div ds2-Header class="header-container"></div>
+    <div ds2-menu id="menuContainer" class="menu-container"></div>
+    <div ng-view id="rightContentProfile" class="content-container"></div>
+    <div ds2-Footer class="footer-container"></div>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResults.js b/ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResults.js
new file mode 100644 (file)
index 0000000..d071e9e
--- /dev/null
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var appDS2 = angular.module("ValidationResults", ['ngRoute', 'ngMessages',
+    'modalServices', 'ngCookies', 'b2b.att', 'gridster', 'ui.bootstrap',
+    'ui.bootstrap.modal', 'App.Services', 'App.Config']);
+
diff --git a/ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResultsController.js b/ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResultsController.js
new file mode 100644 (file)
index 0000000..c4e9e72
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ * Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+var app = angular.module('ValidationResults');
+app
+        .controller(
+                'ValidationResultsController',
+                function($scope, restAPISvc, generalValidationResultsSvc,
+                        $window, appContext, $location, $modal, $rootScope) {
+
+                    $scope.getBlueprintLayers = generalValidationResultsSvc.getBlueprintLayers;
+                    $scope.mapResult = generalValidationResultsSvc.mapResult;
+                    $scope.filterWithLayer = generalValidationResultsSvc.filterWithLayer;
+                    $scope.filterWithResult = generalValidationResultsSvc.filterWithResult;
+                    $scope.getLab = generalValidationResultsSvc.getLab;
+
+                    initialize();
+
+                    function initialize() {
+                        $scope.loadingResults = true;
+                        $scope.validationNexusTestResults = [];
+                        $scope.silos = [];
+                        var searchObject = $location.search();
+                        var submissionId = searchObject.submissionId;
+                        var blueprintName = searchObject.blueprintName;
+                        var version = searchObject.version;
+                        var lab = searchObject.lab;
+                        var allLayers = searchObject.allLayers;
+                        var layer = searchObject.layer;
+                        var optional = searchObject.optional;
+                        var outcome = searchObject.outcome;
+                        var timestamp = searchObject.timestamp;
+                        var date = searchObject.date;
+                        var reqUrl = "";
+                        if (submissionId) {
+                            reqUrl = "/api/v1/results/getbysubmissionid/"
+                                    + submissionId;
+                        } else if (outcome !== undefined && !layer) {
+                            reqUrl = "/api/v1/results/getlastrun/" + lab + "/"
+                                    + blueprintName + "/" + version + "/"
+                                    + allLayers + "/" + optional + "/"
+                                    + outcome;
+                        } else if (outcome !== undefined) {
+                            var layers = [];
+                            layers.push(layer);
+                            reqUrl = "/api/v1/results/getlastrunoflayers/"
+                                    + lab + "/" + blueprintName + "/" + version
+                                    + "/" + layers + "/" + optional + "/"
+                                    + outcome;
+                        } else if (timestamp) {
+                            reqUrl = "/api/v1/results/getbytimestamp/" + lab
+                                    + "/" + blueprintName + "/" + version + "/"
+                                    + timestamp;
+                        } else if (date) {
+                            reqUrl = "/api/v1/results/getbasedondate/" + lab
+                                    + "/" + blueprintName + "/" + version + "/"
+                                    + date;
+                        } else {
+                            reqUrl = "/api/v1/results/getmostrecent/"
+                                    + blueprintName + "/" + version + "/" + lab;
+                        }
+                        restAPISvc
+                                .getRestAPI(
+                                        reqUrl,
+                                        function(resultData) {
+                                            if (resultData) {
+                                                restAPISvc
+                                                        .getRestAPI(
+                                                                "/api/v1/silo/",
+                                                                function(
+                                                                        siloData) {
+                                                                    $scope.silos = siloData;
+                                                                    $scope.loadingResults = false;
+                                                                    if (!Array
+                                                                            .isArray(resultData)) {
+                                                                        $scope.validationNexusTestResults
+                                                                                .push(resultData);
+                                                                    } else {
+                                                                        $scope.validationNexusTestResults = resultData;
+                                                                    }
+                                                                });
+                                            } else {
+                                                confirm("No data was found");
+                                                $scope.loadingResults = false;
+                                            }
+                                        });
+                        $scope.descending = true;
+                    }
+
+                    $scope.dateTimeSort = function(validationNexusTestResult) {
+                        return new Date(validationNexusTestResult.dateOfStorage)
+                                .getTime();
+                    }
+
+                    $scope.descendingOrder = function() {
+                        $scope.descending = true;
+                    }
+
+                    $scope.ascendingOrder = function() {
+                        $scope.descending = false;
+                    }
+
+                    $scope.refreshValidationResults = function() {
+                        initialize();
+                    }
+
+                    $scope.getTestSuiteResults = function(
+                            validationNexusTestResult) {
+                        if (!generalValidationResultsSvc
+                                .mapResult(validationNexusTestResult)) {
+                            return;
+                        }
+                        var scope = $rootScope.$new();
+                        scope.params = validationNexusTestResult;
+                        $modal
+                                .open({
+                                    scope : scope,
+                                    templateUrl : 'app/BluvalUI/ValidationResults/TestSuiteResults/TestSuiteResultsModal.html',
+                                    controller : 'TestSuiteResultsController'
+                                });
+                    }
+
+                });
diff --git a/ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResultsTemplate.html b/ui/src/main/webapp/app/BluvalUI/ValidationResults/ValidationResultsTemplate.html
new file mode 100644 (file)
index 0000000..a327ca0
--- /dev/null
@@ -0,0 +1,239 @@
+<!--
+Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+-->
+<div id="page-content" class="content" style="padding: 25px;">
+
+    <style>
+.grid {
+    width: 100%;
+    height: 400px;
+}
+
+.grid .ui-grid-header-cell {
+    text-align: center;
+}
+
+.icon-add-widget:before {
+    content: "\e717";
+}
+
+.ui-grid-icon-angle-down {
+    margin-top: 5px;
+}
+
+body {
+    font-size: 13px;
+}
+
+.Row {
+    display: table;
+    width: 100%;
+}
+
+.Column {
+    display: table-cell;
+}
+
+.table-bordered, .table-bordered>tbody>tr>td, .table-bordered>tbody>tr>th,
+    .table-bordered>tfoot>tr>td, .table-bordered>tfoot>tr>th,
+    .table-bordered>thead>tr>td, .table-bordered>thead>tr>th {
+    border: 1px solid #d1d1d1;
+}
+
+.table {
+    width: 100%;
+    max-width: 100%;
+    margin-bottom: 20px;
+}
+
+table {
+    background-color: transparent;
+    border-collapse: collapse;
+    border-spacing: 0;
+    display: table;
+}
+
+.table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>th {
+    font-family: Open Sans;
+    font-style: normal;
+    font-weight: 600;
+}
+
+.table>caption+thead>tr:first-child>td, .table>caption+thead>tr:first-child>th,
+    .table>colgroup+thead>tr:first-child>td, .table>colgroup+thead>tr:first-child>th,
+    .table>thead:first-child>tr:first-child>td, .table>thead:first-child>tr:first-child>th
+    {
+    border-top: 0;
+}
+
+.table>tbody>tr>td, .table>tbody>tr>th, .table>tfoot>tr>td, .table>tfoot>tr>th,
+    .table>thead>tr>td, .table>thead>tr>th {
+    padding: 2px 10px 3px;
+}
+
+.table>tbody>tr.success>td, .table>tbody>tr.success>th, .table>tbody>tr>td.success,
+    .table>tbody>tr>th.success, .table>tfoot>tr.success>td, .table>tfoot>tr.success>th,
+    .table>tfoot>tr>td.success, .table>tfoot>tr>th.success, .table>thead>tr.success>td,
+    .table>thead>tr.success>th, .table>thead>tr>td.success, .table>thead>tr>th.success
+    {
+    background-color: #dff0d8;
+}
+
+.table>tbody>tr.warning>td, .table>tbody>tr.warning>th, .table>tbody>tr>td.warning,
+    .table>tbody>tr>th.warning, .table>tfoot>tr.warning>td, .table>tfoot>tr.warning>th,
+    .table>tfoot>tr>td.warning, .table>tfoot>tr>th.warning, .table>thead>tr.warning>td,
+    .table>thead>tr.warning>th, .table>thead>tr>td.warning, .table>thead>tr>th.warning
+    {
+    background-color: #fcf8e3;
+}
+
+.ilocal {
+    border: solid black;
+    border-width: 0 3px 3px 0;
+    display: inline-block;
+    padding: 3px;
+}
+
+.up {
+    transform: rotate(-135deg);
+    -webkit-transform: rotate(-135deg);
+}
+
+.down {
+    transform: rotate(45deg);
+    -webkit-transform: rotate(45deg);
+}
+</style>
+
+    <h1 class="heading-page">Blueprint Validation Results</h1>
+
+    <div ng-show="loadingResults">
+        <img src=" static/fusion/images/giphy.gif" />
+    </div>
+
+    <h2 class="heading-small"></h2>
+    <div ng-show="!loadingResults">
+        <label
+            style="float: left; margin-top: 10px; margin-right: 10px;">Blueprint
+            layer:</label>
+        <div
+            class="form-field form-field__glued pull-left size-onefifth"
+            style="float: left; width: 220px; margin-right: 20px;">
+            <input ng-model="filterLayer" type="text"
+                placeholder="Search for layer?"
+                style="margin-top: 5px; width: 220px;">
+        </div>
+
+        <label
+            style="float: left; margin-top: 10px; margin-right: 10px;">Result:</label>
+        <div
+            class="form-field form-field__glued pull-left size-onefifth"
+            style="float: left; width: 260px; margin-right: 40px;">
+            <input ng-model="filterResult" type="text"
+                placeholder="Search for result?"
+                style="margin-top: 5px; width: 260px;">
+        </div>
+
+        <label
+            style="float: left; margin-top: 10px; margin-right: 10px;">Timestamp:</label>
+        <div
+            class="form-field form-field__glued pull-left size-onefifth"
+            style="float: left; width: 260px; margin-right: 40px;">
+            <input ng-model="filtertimestamp.timestamp" type="text"
+                placeholder="Search for timestamp?"
+                style="margin-top: 5px; width: 260px;">
+        </div>
+
+        <div style="float: right;">
+            <button style="margin-left: 25px; margin-top: 4px;"
+                type="submit" class="btn btn-alt btn-small"
+                ng-click="refreshValidationResults();">Refresh</button>
+        </div>
+
+        <h2 class="heading-small"></h2>
+        <table class="table table-striped table-bordered">
+            <thead>
+                <tr style="background-color: grey;">
+                    <th class>Lab&nbsp;</th>
+                    <th class>Blueprint&nbsp;</th>
+                    <th class>Version</th>
+                    <th class>Timestamp&nbsp;</th>
+                    <th class>
+                        <p>Date/Time of result</p>
+                        <p>
+                            storage&nbsp; <i class="up ilocal"
+                                ng-click="descendingOrder()"></i> <i
+                                class="down ilocal"
+                                ng-click="ascendingOrder()"></i>
+                        </p>
+                    </th>
+                    <th class>Optional test cases&nbsp;</th>
+                    <th class>All layers&nbsp;</th>
+                    <th class>Layer(s)&nbsp;</th>
+                    <th class>Submission Id&nbsp;</th>
+                    <th class>Result&nbsp;</th>
+                </tr>
+            </thead>
+            <tbody>
+                <tr class="border_bottom"
+                    ng-repeat="validationNexusTestResult in filterWithResult(filterWithLayer(validationNexusTestResults,filterLayer), filterResult) | filter:filtertimestamp | orderBy:dateTimeSort:descending"
+                    ng-class="{success: (validationNexusTestResult.result===true), warning: (validationNexusTestResult.result===false)}">
+                    <td class
+                        style="padding-left: 10px; font-size: 15px; width: 13%;">
+                        {{ getLab(validationNexusTestResult.silo, silos)
+                        }}</td>
+                    <td class
+                        style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                        validationNexusTestResult.blueprintName }}</td>
+                    <td class
+                        style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                        validationNexusTestResult.version }}</td>
+                    <td class
+                        style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                        validationNexusTestResult.timestamp }}</td>
+                    <td class
+                        style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                        validationNexusTestResult.dateOfStorage }}</td>
+                    <td class
+                        style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                        validationNexusTestResult.optional }}</td>
+                    <td class
+                        style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                        validationNexusTestResult.allLayers }}</td>
+                    <td class
+                        style="padding-left: 10px; font-size: 15px; width: 13%;">
+                        <div
+                            ng-repeat="layer in  getBlueprintLayers(validationNexusTestResult.wRobotNexusTestResults)">
+                            {{layer}}</div>
+                    </td>
+                    <td class
+                        style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+                        validationNexusTestResult.submissionId }}</td>
+                    <td class
+                        style="padding-left: 10px; font-size: 15px; width: 13%;">
+                        <button
+                            style="margin-left: 25px; margin-top: 4px;"
+                            type="submit" class="btn btn-alt btn-small"
+                            ng-click="getTestSuiteResults(validationNexusTestResult);">{{
+                            mapResult(validationNexusTestResult)}}</button>
+                        </button>
+                    </td>
+                </tr>
+            </tbody>
+        </table>
+
+    </div>
+
+</div>
\ No newline at end of file
index 0d85329..05ee699 100644 (file)
@@ -16,13 +16,14 @@ limitations under the License.
 
 <!DOCTYPE HTML>
 <html lang="en-US">
+
 <head>
-<meta charset="UTF-8">
-<meta http-equiv="refresh"
- content="0; url=/AECBlueprintValidationUI/committedSubmissions">
-<script type="text/javascript">
-            window.location.href = location.host + "/AECBlueprintValidationUI/committedSubmissions"
-        </script>
-<title>Page Redirection</title>
+    <meta charset="UTF-8">
+    <meta http-equiv="refresh" content="0; url=/bluvalui/committedsubmissions">
+    <script type="text/javascript">
+        window.location.href = location.host + "/bluvalui/committedsubmissions"
+    </script>
+    <title>Page Redirection</title>
 </head>
+
 </html>
\ No newline at end of file