UI initial implementation. 35/735/17
authorIoakeim Samaras <ioaksamaras@gmail.com>
Fri, 17 May 2019 12:23:59 +0000 (15:23 +0300)
committerIoakeim Samaras <ioakeim.samaras@ericsson.com>
Mon, 10 Jun 2019 08:40:16 +0000 (11:40 +0300)
- A user can commit and be informed about
  submissions of blueprint validation requests.
- Appropriate dockerfiles have been added for the
  UI and the required postgreSQL db.
- .gitignore file has been updated
- Integration with Jenkins completed
- The URL of the result is retrieved and
  displayed
- Multi-threading is now supported
- Notification callback from Jenkins implemented
- Results are retrieved from Nexus
- Results are displayed
- UI and postgreSQL docker projects support the
  makefile automation build and push process
- README file is included
- CHANGELOG file is included
- Coala static code analysis was performed

JIRA: VAL-14

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

84 files changed:
.coafile
.gitignore
docker/README.rst
docker/postgresql/Dockerfile [new file with mode: 0644]
docker/postgresql/Makefile [new file with mode: 0644]
docker/postgresql/akraino-blueprint_validation_db.sql [new file with mode: 0644]
docker/postgresql/deploy.sh [new file with mode: 0755]
docker/ui/Dockerfile [new file with mode: 0644]
docker/ui/Makefile [new file with mode: 0644]
docker/ui/deploy.sh [new file with mode: 0755]
tox.ini
ui/CHANGELOG.md [new file with mode: 0644]
ui/README.rst [new file with mode: 0644]
ui/pom.xml [new file with mode: 0755]
ui/src/main/java/org/akraino/validation/ui/client/jenkins/JenkinsExecutorClient.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/CrumbResponse.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/IResource.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/Parameter.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/Parameters.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/QueueJobItem.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/client/nexus/NexusExecutorClient.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/IResource.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/RobotTestResult.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/Status.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/common/PropertyUtil.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/common/ServiceInitializationListener.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/common/SessionManagerFilter.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/config/AppConfig.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/config/AppInitializer.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/config/HibernateConfig.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/controller/BlueprintController.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/controller/BlueprintInstanceController.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/controller/JenkinsJobNotificationController.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/controller/ResultsController.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/controller/SubmissionController.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/controller/TimeSlotsController.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/dao/BlueprintDAO.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/dao/BlueprintInstanceDAO.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/dao/SubmissionDAO.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/dao/TimeslotDAO.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintDAOImpl.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintInstanceDAOImpl.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/daoimpl/SubmissionDAOImpl.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/daoimpl/TimeslotDAOImpl.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/data/BlueprintLayer.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/data/JnksJobNotify.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/data/Lab.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/data/SubmissionStatus.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/entity/Blueprint.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/entity/BlueprintInstance.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/entity/Submission.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/entity/Timeslot.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/service/BlueprintInstanceService.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/service/BlueprintService.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/service/JenkinsJobNotificationService.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/service/ResultService.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/service/SubmissionService.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/service/TimeslotService.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/service/utils/PrioritySupplier.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/service/utils/SubmissionHelper.java [new file with mode: 0644]
ui/src/main/java/org/akraino/validation/ui/service/utils/WithPriority.java [new file with mode: 0644]
ui/src/main/resources/app.properties [new file with mode: 0644]
ui/src/main/resources/hibernate.properties [new file with mode: 0644]
ui/src/main/resources/log4j.properties [new file with mode: 0644]
ui/src/main/webapp/.eslintrc [new file with mode: 0644]
ui/src/main/webapp/WEB-INF/views/welcome.jsp [new file with mode: 0755]
ui/src/main/webapp/WEB-INF/web.xml [new file with mode: 0755]
ui/src/main/webapp/index.html [new file with mode: 0755]
ui/src/main/webapp/resources/css/ngDialog-theme-default.css [new file with mode: 0644]
ui/src/main/webapp/resources/css/style.css [new file with mode: 0755]
ui/src/main/webapp/resources/images/logo_akraino_edge_stack.png [new file with mode: 0755]
ui/src/main/webapp/resources/js/AECCommittedSubmissionsController.js [new file with mode: 0644]
ui/src/main/webapp/resources/js/AECFindBySubmissionIdController.js [new file with mode: 0644]
ui/src/main/webapp/resources/js/AECNewSubmissionController.js [new file with mode: 0644]
ui/src/main/webapp/resources/js/App.Config.js [new file with mode: 0644]
ui/src/main/webapp/resources/js/App.Services.js [new file with mode: 0644]
ui/src/main/webapp/resources/js/App.js [new file with mode: 0755]
ui/src/main/webapp/resources/js/CommonController.js [new file with mode: 0644]
ui/src/main/webapp/reusable_chart.js [new file with mode: 0644]
ui/src/main/webapp/views/committedSubmissions.html [new file with mode: 0644]
ui/src/main/webapp/views/findBySubmissionId.html [new file with mode: 0644]
ui/src/main/webapp/views/indexMain.html [new file with mode: 0644]
ui/src/main/webapp/views/login.html [new file with mode: 0644]
ui/src/main/webapp/views/newSubmission.html [new file with mode: 0644]

index 6896103..95a31b4 100644 (file)
--- a/.coafile
+++ b/.coafile
@@ -27,6 +27,7 @@ bears = ShellCheckBear,SpaceConsistencyBear
 files = **.sh
 shell = bash
 use_spaces = true
+ignore = pmd-bin-6.15.0/**
 
 [all.YAML]
 bears = YAMLLintBear
@@ -39,3 +40,19 @@ ignore = tests/k8s/conformance/sonobuoy.yaml
 bears = PyLintBear
 files = **.py
 use_spaces = true
+
+[all.Java]
+bears = SpaceConsistencyBear,JavaPMDBear
+files = ui/**.java
+language = java
+use_spaces = true
+
+[all.JS]
+bears = ESLintBear,JSComplexityBear
+files = ui/**.js
+language = javascript
+javascript_strictness = False
+use_spaces = true
+ignore = ui/src/main/webapp/reusable_chart.js,
+    ui/bin/**,
+    ui/target/**
index 59230bc..fca7ab9 100644 (file)
@@ -1,2 +1,50 @@
 docker/manifest-tool
 *.sw?
+
+# Compiled class files
+*.class
+
+# Maven
+**/target/
+pom.xml.tag
+pom.xml.releaseBackup
+pom.xml.versionsBackup
+pom.xml.next
+release.properties
+dependency-reduced-pom.xml
+buildNumber.properties
+.mvn/timing.properties
+# Avoid ignoring Maven wrapper jar file (.jar files are usually ignored)
+!/.mvn/wrapper/maven-wrapper.jar
+bin/
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.tar.gz
+*.rar
+
+# IDE files
+/.settings/
+.classpath
+.project
+.idea
+*~
+
+.*
+!/.gitignore
+!/.coafile
+!/ui/src/main/webapp/.eslintrc
+
index 456354f..3a979af 100644 (file)
@@ -75,3 +75,61 @@ stored on the local server.
 
 By default, the container will run the k8s conformance test. If you want to
 enter the container, add */bin/sh* at the end of the command above
+
+
+The postgresql container
+=================
+
+Building and pushing the container
+----------------------------------
+
+To build just the postgresql container, use the command:
+
+.. code-block:: console
+
+   make postgresql-build [ REGISTRY=<dockerhub_registry> NAME=<image_name>]
+
+To both build and push the container, use the command:
+
+.. code-block:: console
+
+   make postgresql [ REGISTRY=<dockerhub_registry> NAME=<image_name>]
+
+Using the container
+-------------------
+If you want to deploy the container, you can run the corresponding deploy.sh script with the appropriate parameters.
+
+Example:
+
+.. code-block:: console
+    ./deploy.sh POSTGRES_PASSWORD=password
+
+
+The ui container
+=================
+
+Building and pushing the container
+----------------------------------
+
+To build just the ui container, you must first compile the ui project.
+Then use the command:
+
+.. code-block:: console
+
+   make ui-build [ REGISTRY=<dockerhub_registry> NAME=<image_name>]
+
+To both build and push the container, use the command:
+
+.. code-block:: console
+
+   make ui [ REGISTRY=<dockerhub_registry> NAME=<image_name>]
+
+Using the container
+-------------------
+If you want to deploy the container, you can run the corresponding deploy.sh script with the appropriate parameters.
+Note, that you must also build and run the postgresql container for a functional UI.
+
+Example:
+
+.. code-block:: console
+    ./deploy.sh postgres_db_user_pwd=password jenkins_url=http://192.168.2.2:8080 jenkins_user_name=name jenkins_user_pwd=jenkins_pwd jenkins_job_name=job1 nexus_results_url=https://nexus.akraino.org/content/sites/logs proxy_ip=172.28.40.9 proxy_port=3128
diff --git a/docker/postgresql/Dockerfile b/docker/postgresql/Dockerfile
new file mode 100644 (file)
index 0000000..0259da2
--- /dev/null
@@ -0,0 +1,21 @@
+##############################################################################
+# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.        #
+#                                                                            #
+# Licensed under the Apache License, Version 2.0 (the "License");            #
+# you maynot 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.                                             #
+##############################################################################
+
+FROM postgres:9.6.9
+
+COPY akraino-blueprint_validation_db.sql  /akraino-blueprint_validation_db.sql
+RUN chown -R postgres:postgres /var/lib/postgresql/data && \
+    chown -R postgres:postgres /akraino-blueprint_validation_db.sql
\ No newline at end of file
diff --git a/docker/postgresql/Makefile b/docker/postgresql/Makefile
new file mode 100644 (file)
index 0000000..db91c1e
--- /dev/null
@@ -0,0 +1,23 @@
+##############################################################################
+# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.        #
+#                                                                            #
+# Licensed under the Apache License, Version 2.0 (the "License");            #
+# you maynot 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.                                             #
+##############################################################################
+
+.PHONY: all
+all: .push_image .push_manifest
+
+.PHONY: build
+build: .build
+
+include ../build.mk
diff --git a/docker/postgresql/akraino-blueprint_validation_db.sql b/docker/postgresql/akraino-blueprint_validation_db.sql
new file mode 100644 (file)
index 0000000..fb27ad5
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ * 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.
+ */
+
+drop sequence IF EXISTS akraino.seq_timeslot;
+drop sequence IF EXISTS akraino.seq_blueprint;
+drop sequence IF EXISTS akraino.seq_blueprint_instance;
+drop sequence IF EXISTS akraino.seq_submission;
+
+drop table IF EXISTS akraino.submission;
+drop table IF EXISTS akraino.blueprint_instance;
+drop table IF EXISTS akraino.blueprint;
+drop table IF EXISTS akraino.timeslot;
+
+CREATE SCHEMA IF NOT EXISTS akraino
+ AUTHORIZATION postgres;
+
+CREATE TABLE akraino.timeslot
+(
+   timeslot_id bigint not NULL unique,
+   start_date_time text not NULL,
+   duration int not NULL,
+   lab text not NULL
+)
+WITH (
+  OIDS = FALSE
+)
+;
+ALTER TABLE akraino.timeslot
+  OWNER TO postgres;
+
+CREATE TABLE akraino.blueprint
+(
+   blueprint_id bigint not NULL,
+   blueprint_name text not NULL unique,
+   CONSTRAINT blueprint_id_pk PRIMARY KEY (blueprint_id)
+)
+WITH (
+  OIDS = FALSE
+)
+;
+ALTER TABLE akraino.blueprint
+  OWNER TO postgres;
+
+CREATE TABLE akraino.blueprint_instance
+(
+   blueprint_instance_id bigint not NULL,
+   blueprint_id bigint not NULL,
+   version text not NULL,
+   layer text not NULL,
+   layer_description text not NULL,
+   timeslot_id bigint not NULL unique,
+   CONSTRAINT blueprint_instance_id_pk PRIMARY KEY (blueprint_instance_id),
+   CONSTRAINT blueprint_id_fk FOREIGN KEY (blueprint_id)
+      REFERENCES akraino.blueprint (blueprint_id) MATCH SIMPLE
+      ON UPDATE NO ACTION ON DELETE NO ACTION,
+   CONSTRAINT timeslot_id_fk FOREIGN KEY (timeslot_id)
+      REFERENCES akraino.timeslot (timeslot_id) MATCH SIMPLE
+      ON UPDATE NO ACTION ON DELETE NO ACTION
+)
+WITH (
+  OIDS = FALSE
+)
+;
+ALTER TABLE akraino.blueprint_instance
+  OWNER TO postgres;
+
+CREATE TABLE akraino.submission
+(
+   submission_id bigint not NULL,
+   status text not NULL,
+   jenkins_queue_job_item_url text,
+   nexus_result_url text,
+   blueprint_instance_id bigint not NULL,
+   CONSTRAINT submission_id_pk PRIMARY KEY (submission_id),
+   CONSTRAINT blueprint_instance_id_fk FOREIGN KEY (blueprint_instance_id)
+      REFERENCES akraino.blueprint_instance (blueprint_instance_id) MATCH SIMPLE
+      ON UPDATE NO ACTION ON DELETE NO ACTION
+)
+WITH (
+  OIDS = FALSE
+)
+;
+ALTER TABLE akraino.submission
+  OWNER TO postgres;
+
+CREATE SEQUENCE akraino.seq_timeslot
+  START WITH 1 INCREMENT BY 1;
+
+CREATE SEQUENCE akraino.seq_blueprint
+  START WITH 1 INCREMENT BY 1;
+
+CREATE SEQUENCE akraino.seq_blueprint_instance
+  START WITH 1 INCREMENT BY 1;
+
+CREATE SEQUENCE akraino.seq_submission
+  START WITH 1 INCREMENT BY 1;
+
+insert into akraino.timeslot values(1, now(), 10, 0);  /* stands for AT&T lab */
+insert into akraino.timeslot values(2, now(), 1000, 0); /* stands for AT&T lab */
+insert into akraino.timeslot values(3, now(), 10000, 0); /* stands for AT&T lab */
+insert into akraino.timeslot values(4, now(), 100000, 0); /* stands for AT&T lab */
+insert into akraino.timeslot values(5, now(), 100000, 0); /* stands for AT&T lab */
+
+insert into akraino.blueprint (blueprint_id, blueprint_name) values(1, 'dummy');
+insert into akraino.blueprint (blueprint_id, blueprint_name) values(2, 'Unicycle');
+insert into akraino.blueprint (blueprint_id, blueprint_name) values(3, 'REC');
+
+insert into akraino.blueprint_instance (blueprint_instance_id, blueprint_id, version, layer, layer_description, timeslot_id) values(1, 1, '0.0.2-SNAPSHOT', 0, 'Dell Hardware', 1);  /* 0 Stands for hardware layer */
+insert into akraino.blueprint_instance (blueprint_instance_id, blueprint_id, version, layer, layer_description, timeslot_id) values(2, 2, '0.0.1-SNAPSHOT', 0, 'Dell Hardware', 2); /* 0 Stands for hardware layer */
+insert into akraino.blueprint_instance (blueprint_instance_id, blueprint_id, version, layer, layer_description, timeslot_id) values(3, 2, '0.0.7-SNAPSHOT', 1, 'CentOS Linux 7 (Core)', 3); /* 1 Stands for OS layer */
+insert into akraino.blueprint_instance (blueprint_instance_id, blueprint_id, version, layer, layer_description, timeslot_id) values(4, 3, '0.0.4-SNAPSHOT', 2, 'K8s with High Availability Ingress controller', 4); /* 2 Stands for k8s layer */
+insert into akraino.blueprint_instance (blueprint_instance_id, blueprint_id, version, layer, layer_description, timeslot_id) values(5, 3, '0.0.8-SNAPSHOT', 2, 'K8s with High Availability Ingress controller', 5); /* 2 Stands for k8s layer */
+
+commit;
diff --git a/docker/postgresql/deploy.sh b/docker/postgresql/deploy.sh
new file mode 100755 (executable)
index 0000000..60af84e
--- /dev/null
@@ -0,0 +1,54 @@
+#!/bin/bash
+#
+# Copyright (c) 2019 AT&T Intellectual Property.  All other 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.
+
+export DROOT=/var/lib
+CONTAINER_NAME="validation_postgresql"
+POSTGRES_HOST_PORT=6432
+REGISTRY=akraino
+NAME=validation
+TAG_PRE=`echo "${PWD##*/}"`
+TAG_VER=latest
+POSTGRES_PASSWORD=""
+HOST_ARCH=amd64
+
+# get the architecture of the host
+if [ "`uname -m`" = "aarch64" ]; then
+    HOST_ARCH=arm64
+fi
+
+for ARGUMENT in "$@"
+do
+    KEY=$(echo $ARGUMENT | cut -f1 -d=)
+    VALUE=$(echo $ARGUMENT | cut -f2 -d=)
+    case "$KEY" in
+            REGISTRY)              REGISTRY=${VALUE} ;;
+            NAME)    NAME=${VALUE} ;;
+            TAG_VER)    TAG_VER=${VALUE} ;;
+            POSTGRES_PASSWORD)    POSTGRES_PASSWORD=${VALUE} ;;
+            *)
+    esac
+done
+
+if [ -z "$POSTGRES_PASSWORD" ]
+  then
+    echo "ERROR: You must specify at least the postgreSQL database password"
+    exit 1
+fi
+
+IMAGE="$REGISTRY"/"$NAME":"$TAG_PRE"-"$HOST_ARCH"-"$TAG_VER"
+docker run --detach --name $CONTAINER_NAME --restart=always --publish $POSTGRES_HOST_PORT:5432 --volume $DROOT/postgres:/var/lib/postgresql/data --env POSTGRES_USER=admin --env POSTGRES_PASSWORD="$POSTGRES_PASSWORD" $IMAGE
+sleep 10
+docker exec $CONTAINER_NAME /bin/bash -c "psql -h localhost -p 5432 -U admin -f /akraino-blueprint_validation_db.sql"
diff --git a/docker/ui/Dockerfile b/docker/ui/Dockerfile
new file mode 100644 (file)
index 0000000..ee710a1
--- /dev/null
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+FROM tomcat:8.5.37
+COPY ./AECBlueprintValidationUI.war /usr/local/tomcat/webapps
\ No newline at end of file
diff --git a/docker/ui/Makefile b/docker/ui/Makefile
new file mode 100644 (file)
index 0000000..5e2d074
--- /dev/null
@@ -0,0 +1,27 @@
+##############################################################################
+# Copyright (c) 2019 AT&T Intellectual Property. All rights reserved.        #
+#                                                                            #
+# Licensed under the Apache License, Version 2.0 (the "License");            #
+# you maynot 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.                                             #
+##############################################################################
+
+.PHONY: prepare
+prepare:
+       ln -f ../../ui/target/AECBlueprintValidationUI.war AECBlueprintValidationUI.war
+
+.PHONY: all
+all: prepare .push_image .push_manifest
+
+.PHONY: build
+build: prepare .build
+
+include ../build.mk
\ No newline at end of file
diff --git a/docker/ui/deploy.sh b/docker/ui/deploy.sh
new file mode 100755 (executable)
index 0000000..fef0bed
--- /dev/null
@@ -0,0 +1,96 @@
+#!/bin/bash
+#
+# Copyright (c) 2019 AT&T Intellectual Property.  All other 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.
+
+CONTAINER_NAME="validation-ui"
+REGISTRY=akraino
+NAME=validation
+TAG_PRE=`echo "${PWD##*/}"`
+TAG_VER=latest
+HOST_ARCH=amd64
+postgres_db_user_pwd=""
+jenkins_url=""
+jenkins_user_name=""
+jenkins_user_pwd=""
+jenkins_job_name=""
+nexus_results_url=""
+proxy_ip=""
+proxy_port=""
+
+# get the architecture of the host
+if [ "`uname -m`" = "aarch64" ]
+  then
+    HOST_ARCH=arm64
+fi
+
+for ARGUMENT in "$@"
+do
+    KEY=$(echo $ARGUMENT | cut -f1 -d=)
+    VALUE=$(echo $ARGUMENT | cut -f2 -d=)
+    case "$KEY" in
+            REGISTRY)              REGISTRY=${VALUE} ;;
+            NAME)    NAME=${VALUE} ;;
+            TAG_VER)    TAG_VER=${VALUE} ;;
+            postgres_db_user_pwd)    postgres_db_user_pwd=${VALUE} ;;
+            jenkins_url)    jenkins_url=${VALUE} ;;
+            jenkins_user_name)    jenkins_user_name=${VALUE} ;;
+            jenkins_user_pwd)    jenkins_user_pwd=${VALUE} ;;
+            jenkins_job_name)    jenkins_job_name=${VALUE} ;;
+            nexus_results_url)    nexus_results_url=${VALUE} ;;
+            proxy_ip)    proxy_ip=${VALUE} ;;
+            proxy_port)    proxy_port=${VALUE} ;;
+            *)
+    esac
+done
+
+if [ -z "$postgres_db_user_pwd" ]
+  then
+    echo "ERROR: You must specify the postgresql root user password"
+    exit 1
+fi
+
+if [ -z "$jenkins_url" ]
+  then
+    echo "ERROR: You must specify the Jenkins Url"
+    exit 1
+fi
+
+if [ -z "$jenkins_user_name" ]
+  then
+    echo "ERROR: You must specify the Jenkins username"
+    exit 1
+fi
+
+if [ -z "$jenkins_user_pwd" ]
+  then
+    echo "ERROR: You must specify the Jenkins user password"
+    exit 1
+fi
+
+if [ -z "$jenkins_job_name" ]
+  then
+    echo "ERROR: You must specify the Jenkins job name"
+    exit 1
+fi
+
+if [ -z "$nexus_results_url" ]
+  then
+    echo "ERROR: You must specify the Nexus Url"
+    exit 1
+fi
+
+IMAGE="$REGISTRY"/"$NAME":"$TAG_PRE"-"$HOST_ARCH"-"$TAG_VER"
+docker run --name $CONTAINER_NAME --network="host" -it --rm -e postgres_db_user_pwd="$postgres_db_user_pwd" -e jenkins_url="$jenkins_url" -e jenkins_user_name="$jenkins_user_name" -e jenkins_user_pwd="$jenkins_user_pwd" -e jenkins_job_name="$jenkins_job_name" -e nexus_results_url="$nexus_results_url" -e proxy_ip="$proxy_ip" -e proxy_port="$proxy_port" $IMAGE
+sleep 10
diff --git a/tox.ini b/tox.ini
index 64c1486..a1cdceb 100644 (file)
--- a/tox.ini
+++ b/tox.ini
@@ -14,6 +14,11 @@ commands =
 
 [testenv:coala]
 basepython = python3
+whitelist_externals =
+   wget
+   unzip
+   bash
+
 passenv = http_proxy HTTP_PROXY https_proxy HTTPS_PROXY no_proxy NO_PROXY
 install_command = python -m pip install --no-cache-dir {opts} {packages}
 deps =
@@ -24,5 +29,7 @@ deps =
    nodeenv
 commands =
    nodeenv -p
-   npm install --global write-good
-   coala --non-interactive
+   npm install --global write-good eslint complexity-report@2.0.0-alpha
+   wget --timeout=120 -q https://github.com/pmd/pmd/releases/download/pmd_releases/6.15.0/pmd-bin-6.15.0.zip
+   unzip -q pmd-bin-6.15.0.zip
+   bash -c "export PATH=$PATH:$PWD/pmd-bin-6.15.0/bin/ && coala --non-interactive"
\ No newline at end of file
diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md
new file mode 100644 (file)
index 0000000..fd87d9b
--- /dev/null
@@ -0,0 +1,62 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+## [Unreleased]
+
+## [0.0.1-SNAPSHOT] - 4 June 2019
+### Added
+- A user can commit and be informed about submissions of blueprint validation requests.
+- Appropriate dockerfiles have been added for the UI and the required postgreSQL db.
+- .gitignore file has been updated
+- Integration with Jenkins completed
+- The URL of the result is retrieved and displayed
+- Multi-threading is now supported
+- Notification callback from Jenkins implemented
+- Results are retrieved from Nexus
+- Results are displayed
+- UI and postgreSQL docker projects support the makefile automation build and push process
+- README file is included
+- CHANGELOG is included
+- Coala static code analysis performed for Java and JS files
+
+### Changed
+
+### Removed
+
+## [0.0.1-SNAPSHOT] - 5 June 2019
+### Added
+
+### Changed
+- PostgreSQL database model has been refactored in order to support 4 tables, namely timeslot, blueprint, blueprint_instance, submission
+- Trailing spaces removed from comments in javascript files
+
+### Removed
+
+## [0.0.1-SNAPSHOT] - 6 June 2019
+### Added
+- Community lab is now supported
+
+### Changed
+- README file is updated.
+- Coala static analysis issues fixed for Javascript files
+- README.md has been renamed to README.rst
+
+### Removed
+
+## [0.0.1-SNAPSHOT] - 7 June 2019
+### Added
+- Arm lab is now supported
+
+### Changed
+- README file is updated.
+
+### Removed
+
+## [0.0.1-SNAPSHOT] - 10 June 2019
+### Added
+
+### Changed
+- Trailing spaces removed from all files.
+- README file is updated.
+
+### Removed
\ No newline at end of file
diff --git a/ui/README.rst b/ui/README.rst
new file mode 100644 (file)
index 0000000..73ec832
--- /dev/null
@@ -0,0 +1,177 @@
+
+Akraino Blueprint Validation UI
+========
+
+This project contains the source code of the Akraino Blueprint Validation UI.
+
+This UI consists of the front-end and back-end parts.
+The front-end part is based on HTML, CSS, and AngularJS technologies.
+The back-end part is based on Spring MVC and Apache Tomcat technologies.
+
+Based on these instructions, a user can provide the prerequisites, compile the source code and deploy the UI.
+
+Download the project
+--------------------
+
+.. code-block:: console
+
+    git clone "https://gerrit.akraino.org/r/validation"
+
+Prerequisites
+---------------
+
+- Database
+
+A PostgreSQL database instance is needed with the appropriate relations in order for the back-end system to store and retrieve data.
+Configure the postgreSQL root password in the variable POSTGRES_PASSWORD and execute the following commands in order to build and deploy this database container:
+
+.. code-block:: console
+
+    cd validation/docker/postgresql
+    make build
+    ./deploy.sh POSTGRES_PASSWORD=password
+
+Below, some data that is initialized in the aforementioned database is illustrated (note that this data is used mainly for testing purposes):
+
+.. code-block:: console
+
+    Timeslots:
+    id:1 , start date and time: now() (i.e. the time of the postgreSQL container deployment), duration: 10 (sec), lab: 0 (i.e. AT&T)
+    id:2 , start date and time: now() (i.e. the time of the postgreSQL container deployment), duration: 1000 (sec), lab: 0 (i.e. AT&T)
+
+    Blueprints:
+    id: 1 , name : 'dummy'
+    id: 2 , name : 'Unicycle'
+
+    Blueprint Instances:
+    id: 1, blueprint_id: 1 (i.e. dummy), version: "0.0.2-SNAPSHOT", layer: 0 (i.e. Hardware), layer_description: "Dell Hardware", timeslot id: 1
+    id: 2, blueprint_id: 2 (i.e. Unicycle), version: "0.0.1-SNAPSHOT", layer: 0 (i.e. Hardware), layer_description: "Dell Hardware", timeslot id: 2
+
+For more information about this data, please refer to the file:
+
+    validation/docker/postgresql/akraino-blueprint_validation_db.sql
+
+Based on this data, the UI enables the user to select an appropriate blueprint instance for validation.
+
+Currently, this data cannot be retrieved dynamically by the UI (see limitations subsection).
+
+For this reason, in cases of new blueprint data, a user should define new entries in this database.
+
+For example, if a user wants to define a new timeslot with the following data:
+
+    start date and time:now, duration: 123 in secs, lab: Community
+
+the following file should be created:
+
+name: dbscript
+content:
+    insert into akraino.timeslot values(5, now(), 123, 2);
+
+Then, the following command should be executed:
+
+.. code-block:: console
+
+    psql -h <IP of the postgreSQL container> -p 6432 -U admin -f ./dbscript
+
+Furthermore, if a user wants to define a new blueprint, namely "newBlueprint" and a new instance of this blueprint with the following data:
+
+    version: "0.0.1-SNAPSHOT", layer: 2 (i.e. K8s), layer_description: "K8s with High Availability Ingress controller", timeslot id: 5 (i.e. the new timeslot)
+
+the following file should be created:
+
+name: dbscript
+content:
+    insert into akraino.blueprint (blueprint_id, blueprint_name) values(4, 'newBlueprint');
+    insert into akraino.blueprint_instance (blueprint_instance_id, blueprint_id, version, layer, layer_description, timeslot_id) values(6, 4, '0.0.1-SNAPSHOT', 2, 'K8s with High Availability Ingress controller', 5);
+
+Then, the following command should be executed:
+
+.. code-block:: console
+
+    psql -h <IP of the postgreSQL container> -p 6432 -U admin -f ./dbscript
+
+The UI will automatically retrieve this new data and display it to the user.
+
+- Jenkins Configuration
+
+The Blueprint validation UI will trigger job executions in a Jenkins instance.
+
+This instance must have the following option enabled: "Manage Jenkins -> Configure Global Security -> Prevent Cross Site Request Forgery exploits".
+
+Also, currently corresponding Jenkins job should accept the following as input parameters: "SUBMISSION_ID", "BLUEPRINT", "LAYER" 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 backend part of the UI.
+The "BLUEPRINT" and "LAYER" 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 command at the end (Post-build Actions)
+
+.. code-block:: console
+
+    curl -v -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"'"}'
+
+Finally, the Jenkins instance must be accessible from the UI host without using system proxy.
+
+- Nexus server
+
+All the blueprint validation results are stored in Nexus server.
+
+These results must be available in the following url:
+
+    https://nexus.akraino.org/content/sites/logs/"lab"-blu-val/job/validation/"Jenkins job number"/results/"name_of_the_test_suite".
+
+where "lab" is the name of the lab (for example 'att'), "Jenkins job number" is the number of the Jenkins job that produced this result, and "name_of_the_test_suite" is the name of the test suite.
+If multiple test suites must run, multiple directories should be created.
+
+Moreover, the results should be stored in the 'output.xml' file using the following format:
+
+TBD
+
+Finally, the Nexus server must be accessible from the UI (with or without using system proxy).
+
+
+Compiling
+---------
+
+.. code-block:: console
+
+    cd validation/ui
+    mvn clean install
+
+Deploying
+---------
+
+In the context of deploying, the following data is needed:
+
+- The postgres root user password
+- The Jenkins url
+- The Jenkins username and password
+- The name of Jenkins Job
+- The Url of the Nexus results
+- The host system's proxy ip and port
+
+These variables must be configured as content of the deploy script input parameters. Execute the following commands in order to build and deploy the UI container:
+
+.. code-block:: console
+
+    cd validation/docker/ui
+    make build
+    ./deploy.sh postgres_db_user_pwd=password jenkins_url=http://192.168.2.2:8080 jenkins_user_name=name jenkins_user_pwd=jenkins_pwd jenkins_job_name=job1 nexus_results_url=https://nexus.akraino.org/content/sites/logs proxy_ip=172.28.40.9 proxy_port=3128
+
+If no proxy exists, just do not define proxy ip and port variables.
+
+The UI should be available in the following url:
+
+    http://localhost:8080/AECBlueprintValidationUI
+
+Limitations
+-----------
+
+- The UI has been tested using Chrome and Firefox browsers.
+- The UI is not connected to any LDAP server. Currently, any user can login.
+- The UI and postgreSQL containers must be deployed on the same server.
+- The back-end part of the UI does not take into account 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" and "LAYER" input parameters of the Jenkins job.
+- The available blueprints and timeslots must be manually configured in the PostgreSQL database.
+- The Jenkins instance must be accessible from the UI host without using system proxy.
\ No newline at end of file
diff --git a/ui/pom.xml b/ui/pom.xml
new file mode 100755 (executable)
index 0000000..85890da
--- /dev/null
@@ -0,0 +1,236 @@
+<!--
+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.
+-->
+
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+  <groupId>org.akraino.validation</groupId>
+  <artifactId>ui</artifactId>
+  <packaging>war</packaging>
+  <version>0.0.1-SNAPSHOT</version>
+  <name>AECBlueprintValidationUI Maven Webapp</name>
+  <url>http://maven.apache.org</url>
+  <properties>
+    <java-version>1.8</java-version>
+    <org.springframework-version>4.3.0.RELEASE</org.springframework-version>
+    <org.springframework.security.version>3.2.3.RELEASE</org.springframework.security.version>
+    <jackson.library>2.7.5</jackson.library>
+    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    <jersey-version>1.19.4</jersey-version>
+    <google.guava-version>27.1-jre</google.guava-version>
+  </properties>
+
+  <repositories>
+    <repository>
+      <id>central</id>
+      <name>Central Repository</name>
+      <url>http://repo.maven.apache.org/maven2</url>
+      <layout>default</layout>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+    </repository>
+  </repositories>
+
+  <pluginRepositories>
+    <pluginRepository>
+      <id>central</id>
+      <name>Maven Plugin Repository</name>
+      <url>http://repo1.maven.org/maven2</url>
+      <layout>default</layout>
+      <snapshots>
+        <enabled>false</enabled>
+      </snapshots>
+      <releases>
+        <updatePolicy>never</updatePolicy>
+      </releases>
+    </pluginRepository>
+  </pluginRepositories>
+
+  <dependencies>
+    <dependency>
+      <groupId>junit</groupId>
+      <artifactId>junit</artifactId>
+      <version>4.12</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>commons-codec</groupId>
+      <artifactId>commons-codec</artifactId>
+      <version>1.11</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-webmvc</artifactId>
+      <version>${org.springframework-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-context</artifactId>
+      <version>${org.springframework-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-orm</artifactId>
+      <version>${org.springframework-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-tx</artifactId>
+      <version>${org.springframework-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-fileupload</groupId>
+      <artifactId>commons-fileupload</artifactId>
+      <version>1.3.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.hibernate</groupId>
+      <artifactId>hibernate-core</artifactId>
+      <version>5.2.6.Final</version>
+    </dependency>
+    <dependency>
+      <groupId>org.javassist</groupId>
+      <artifactId>javassist</artifactId>
+      <version>3.18.2-GA</version>
+    </dependency>
+    <dependency>
+      <groupId>org.hibernate</groupId>
+      <artifactId>hibernate-c3p0</artifactId>
+      <version>5.2.6.Final</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-dbcp</groupId>
+      <artifactId>commons-dbcp</artifactId>
+      <version>1.4</version>
+    </dependency>
+    <dependency>
+      <groupId>com.mchange</groupId>
+      <artifactId>c3p0</artifactId>
+      <version>0.9.5.2</version>
+    </dependency>
+    <dependency>
+      <groupId>org.hibernate</groupId>
+      <artifactId>hibernate-validator</artifactId>
+      <version>5.4.1.Final</version>
+    </dependency>
+    <dependency>
+      <groupId>log4j</groupId>
+      <artifactId>log4j</artifactId>
+      <version>1.2.17</version>
+    </dependency>
+    <dependency>
+      <groupId>org.springframework</groupId>
+      <artifactId>spring-test</artifactId>
+      <version>${org.springframework-version}</version>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>javax.servlet-api</artifactId>
+      <version>3.0.1</version>
+      <scope>provided</scope>
+    </dependency>
+    <dependency>
+      <groupId>javax.servlet</groupId>
+      <artifactId>jstl</artifactId>
+      <version>1.2</version>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.core</groupId>
+      <artifactId>jackson-databind</artifactId>
+      <version>${jackson.library}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.dataformat</groupId>
+      <artifactId>jackson-dataformat-xml</artifactId>
+      <version>${jackson.library}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.dataformat</groupId>
+      <artifactId>jackson-dataformat-yaml</artifactId>
+      <version>${jackson.library}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.commons</groupId>
+      <artifactId>commons-lang3</artifactId>
+      <version>3.4</version>
+    </dependency>
+    <dependency>
+      <groupId>org.postgresql</groupId>
+      <artifactId>postgresql</artifactId>
+      <version>42.2.2</version>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-json</artifactId>
+      <version>${jersey-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.sun.jersey</groupId>
+      <artifactId>jersey-client</artifactId>
+      <version>${jersey-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>com.google.guava</groupId>
+      <artifactId>guava</artifactId>
+      <version>${google.guava-version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.json</groupId>
+      <artifactId>json</artifactId>
+      <version>20180813</version>
+    </dependency>
+    <dependency>
+      <groupId>org.jsoup</groupId>
+      <artifactId>jsoup</artifactId>
+      <version>1.12.1</version>
+    </dependency>
+    <dependency>
+      <groupId>commons-httpclient</groupId>
+      <artifactId>commons-httpclient</artifactId>
+      <version>3.1</version>
+    </dependency>
+
+  </dependencies>
+
+  <build>
+    <finalName>AECBlueprintValidationUI</finalName>
+    <pluginManagement>
+      <plugins>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-compiler-plugin</artifactId>
+          <version>2.3.2</version>
+          <configuration>
+            <source>${java-version}</source>
+            <target>${java-version}</target>
+          </configuration>
+        </plugin>
+        <plugin>
+          <groupId>org.apache.maven.plugins</groupId>
+          <artifactId>maven-war-plugin</artifactId>
+          <version>2.4</version>
+          <configuration>
+            <warSourceDirectory>src/main/webapp</warSourceDirectory>
+            <warName>AECBlueprintValidationUI</warName>
+            <failOnMissingWebXml>false</failOnMissingWebXml>
+          </configuration>
+        </plugin>
+      </plugins>
+    </pluginManagement>
+  </build>
+</project>
diff --git a/ui/src/main/java/org/akraino/validation/ui/client/jenkins/JenkinsExecutorClient.java b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/JenkinsExecutorClient.java
new file mode 100644 (file)
index 0000000..313ce89
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * 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.jenkins;
+
+import java.net.MalformedURLException;
+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;
+import org.akraino.validation.ui.client.jenkins.resources.Parameter;
+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.apache.log4j.Logger;
+
+import com.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+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.client.filter.HTTPBasicAuthFilter;
+import com.sun.jersey.api.json.JSONConfiguration;
+import com.sun.jersey.client.urlconnection.HTTPSProperties;
+
+public final class JenkinsExecutorClient {
+
+    private static final Logger LOGGER = Logger.getLogger(JenkinsExecutorClient.class);
+
+    private static final List<JenkinsExecutorClient> JENKINS_CLIENTS = new ArrayList<>();
+    private static final Object LOCK = new Object();
+    private final Client client;
+
+    private final String user;
+    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;
+        ClientConfig clientConfig = new DefaultClientConfig();
+        clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
+        this.client = Client.create(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() {
+        return this.user;
+    }
+
+    public String getPassword() {
+        return this.password;
+    }
+
+    public String getBaseUrl() {
+        return this.baseurl;
+    }
+
+    public QueueJobItem getQueueJobItem(URL queueJobItemUrl) throws HttpException, ClientHandlerException,
+            UniformInterfaceException, KeyManagementException, NoSuchAlgorithmException {
+        synchronized (LOCK) {
+            LOGGER.info("Trying to get a Jenkins resource");
+            String crumb = this.getCrumb();
+            LOGGER.debug("Jenkins crumb is: " + crumb);
+            WebResource webResource = this.client.resource(queueJobItemUrl + "/api/json");
+            LOGGER.debug("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);
+            if (response.getStatus() != 200) {
+                throw new HttpException("Get on Jenkins failed. HTTP error code : " + response.getStatus()
+                        + " and message: " + response.getEntity(String.class));
+            }
+            LOGGER.info("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 {
+        synchronized (LOCK) {
+            LOGGER.info("Trying to trigger a job to Jenkins");
+            String crumb = this.getCrumb();
+            LOGGER.debug("Jenkins crumb is: " + crumb);
+            String queryParams = "?";
+            for (Parameter parameter : parameters.getParameter()) {
+                queryParams = queryParams + parameter.getName() + "=" + parameter.getValue() + "&";
+            }
+            queryParams = queryParams.substring(0, queryParams.length() - 1);
+            WebResource webResource =
+                    this.client.resource(this.getBaseUrl() + "/job/" + jobName + "/buildWithParameters" + queryParams);
+            LOGGER.debug("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));
+            }
+            LOGGER.info("Jenkins job has been successfully triggered");
+            URL buildQueueUrl = null;
+            MultivaluedMap<String, String> responseValues = response.getHeaders();
+            Iterator<String> iter = responseValues.keySet().iterator();
+            while (iter.hasNext()) {
+                String key = iter.next();
+                if (key.equals("Location")) {
+                    buildQueueUrl = new URL(responseValues.getFirst(key));
+                }
+            }
+            return buildQueueUrl;
+        }
+    }
+
+    private String getCrumb() throws HttpException, ClientHandlerException, UniformInterfaceException,
+            KeyManagementException, NoSuchAlgorithmException {
+        LOGGER.info("Get crumb attempt");
+        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);
+        if (response.getStatus() == 201 || response.getStatus() == 200) {
+            CrumbResponse crumbResponse = response.getEntity(CrumbResponse.class);
+            LOGGER.info("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);
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/CrumbResponse.java b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/CrumbResponse.java
new file mode 100644 (file)
index 0000000..5cf4518
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.jenkins.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 CrumbResponse implements IResource {
+
+    @JsonProperty("_class")
+    private String classCrumb;
+
+    @JsonProperty("crumb")
+    private String crumb;
+
+    @JsonProperty("crumbRequestField")
+    private String crumbRequestField;
+
+    public CrumbResponse() {
+
+    }
+
+    public String getClassCrumb() {
+        return this.classCrumb;
+    }
+
+    public void setClassCrumb(String classCrumb) {
+        this.classCrumb = classCrumb;
+    }
+
+    public String getCrumb() {
+        return this.crumb;
+    }
+
+    public void setCrumb(String crumb) {
+        this.crumb = crumb;
+    }
+
+    public String getCrumbRequestField() {
+        return this.crumbRequestField;
+    }
+
+    public void setCrumbRequestField(String crumbRequestField) {
+        this.crumbRequestField = crumbRequestField;
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/IResource.java b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/IResource.java
new file mode 100644 (file)
index 0000000..ac00cbe
--- /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.
+ */
+package org.akraino.validation.ui.client.jenkins.resources;
+
+public interface IResource {
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/Parameter.java b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/Parameter.java
new file mode 100644 (file)
index 0000000..3557421
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * 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.jenkins.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 Parameter {
+    @JsonProperty("name")
+    private String name;
+
+    @JsonProperty("value")
+    private String value;
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getValue() {
+        return this.value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+}
+
+
diff --git a/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/Parameters.java b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/Parameters.java
new file mode 100644 (file)
index 0000000..8fad211
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * 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.jenkins.resources;
+
+import java.util.List;
+
+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 Parameters implements IResource {
+
+    @JsonProperty("parameter")
+    private List<Parameter> parameter;
+
+    public List<Parameter> getParameter() {
+        return this.parameter;
+    }
+
+    public void setParameter(List<Parameter> parameter) {
+        this.parameter = parameter;
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/QueueJobItem.java b/ui/src/main/java/org/akraino/validation/ui/client/jenkins/resources/QueueJobItem.java
new file mode 100644 (file)
index 0000000..9da3891
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * 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.jenkins.resources;
+
+import java.net.URL;
+
+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 QueueJobItem implements IResource {
+
+    @JsonProperty("_class")
+    private String classQueue;
+
+    @JsonProperty("executable")
+    private Executable executable;
+
+    public QueueJobItem() {
+
+    }
+
+    public String getClassQueue() {
+        return this.classQueue;
+    }
+
+    public void setClassQueue(String classQueue) {
+        this.classQueue = classQueue;
+    }
+
+    public Executable getExecutable() {
+        return this.executable;
+    }
+
+    public void setExecutable(Executable executable) {
+        this.executable = executable;
+    }
+
+    public class Executable {
+        @JsonProperty("_class")
+        private String classQueue;
+
+        @JsonProperty("number")
+        private Integer number;
+
+        @JsonProperty("url")
+        private URL url;
+
+        public String getClassQueue() {
+            return this.classQueue;
+        }
+
+        public void setClassQueue(String classQueue) {
+            this.classQueue = classQueue;
+        }
+
+        public Integer getNumber() {
+            return this.number;
+        }
+
+        public void setNumber(Integer number) {
+            this.number = number;
+        }
+
+        public URL getUrl() {
+            return this.url;
+        }
+
+        public void setUrl(URL url) {
+            this.url = url;
+        }
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/client/nexus/NexusExecutorClient.java b/ui/src/main/java/org/akraino/validation/ui/client/nexus/NexusExecutorClient.java
new file mode 100644 (file)
index 0000000..988685b
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * 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;
+
+import java.io.IOException;
+import java.net.HttpURLConnection;
+import java.net.InetSocketAddress;
+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.List;
+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.akraino.validation.ui.client.nexus.resources.RobotTestResult;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.log4j.Logger;
+import org.json.JSONObject;
+import org.json.XML;
+import org.jsoup.Jsoup;
+import org.jsoup.nodes.Document;
+import org.jsoup.nodes.Element;
+
+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.sun.jersey.api.client.Client;
+import com.sun.jersey.api.client.ClientHandlerException;
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.UniformInterfaceException;
+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;
+
+public final class NexusExecutorClient {
+
+    private static final Logger LOGGER = Logger.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;
+        ClientConfig clientConfig = new DefaultClientConfig();
+        clientConfig.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE);
+        client = new Client(new URLConnectionClientHandler(new HttpURLConnectionFactory() {
+            Proxy proxy = null;
+
+            @Override
+            public HttpURLConnection getHttpURLConnection(URL url) throws IOException {
+                try {
+                    String proxyIp = System.getenv("proxy_ip");
+                    String proxyPort = System.getenv("proxy_port");
+                    proxy = new Proxy(Proxy.Type.HTTP, new InetSocketAddress(proxyIp, Integer.parseInt(proxyPort)));
+                    return (HttpURLConnection) url.openConnection(proxy);
+                } catch (NumberFormatException ex) {
+                    return (HttpURLConnection) url.openConnection();
+                }
+            }
+        }), clientConfig);
+        // 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 String getBaseUrl() {
+        return this.baseurl;
+    }
+
+    public List<RobotTestResult> getRobotTestResults() throws ClientHandlerException, UniformInterfaceException,
+            JsonParseException, JsonMappingException, IOException, KeyManagementException, NoSuchAlgorithmException {
+        List<RobotTestResult> robotTestResults = new ArrayList<RobotTestResult>();
+        LOGGER.info("Trying to get Robot Test Results");
+        setProperties();
+        WebResource webResource = this.client.resource(this.baseurl + "/");
+        LOGGER.debug("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 : "
+                    + 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");
+        for (int i = 2; i < elements.size(); i++) {
+            String resultName = elements.get(i).getElementsByTag("td").get(0).getElementsByTag("a").get(0).text();
+            resultName = resultName.substring(0, resultName.length() - 1);
+            webResource = this.client.resource(this.baseurl + "/" + resultName + "/output.xml");
+            LOGGER.debug("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 : "
+                        + response.getStatus() + " and message: " + response.getEntity(String.class));
+            }
+            String result = response.getEntity(String.class);
+            JSONObject xmlJSONObj = XML.toJSONObject(result);
+            ObjectMapper mapper = new ObjectMapper();
+            mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
+            RobotTestResult robotTestResult = mapper.readValue(xmlJSONObj.toString(), RobotTestResult.class);
+            robotTestResult.setName(resultName);
+            robotTestResults.add(robotTestResult);
+        }
+        return robotTestResults;
+    }
+
+    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);
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/IResource.java b/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/IResource.java
new file mode 100644 (file)
index 0000000..2cfe00b
--- /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.
+ */
+package org.akraino.validation.ui.client.nexus.resources;
+
+public interface IResource {
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/RobotTestResult.java b/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/RobotTestResult.java
new file mode 100644 (file)
index 0000000..44ddc56
--- /dev/null
@@ -0,0 +1,283 @@
+/*
+ * 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;
+
+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 RobotTestResult implements IResource {
+
+    @JsonProperty("robot")
+    private Robot robot;
+
+    private String name;
+
+    public RobotTestResult() {
+
+    }
+
+    public Robot getRobot() {
+        return this.robot;
+    }
+
+    public void setRobot(Robot robot) {
+        this.robot = robot;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public class Robot {
+        @JsonProperty("suite")
+        private Suite suite;
+
+        @JsonProperty("statistics")
+        private Statistics statistics;
+
+        @JsonProperty("generated")
+        private String generated;
+
+        @JsonProperty("generator")
+        private String generator;
+
+        @JsonProperty("errors")
+        private String errors;
+
+        public Robot() {
+
+        }
+
+        public Suite getSuite() {
+            return this.suite;
+        }
+
+        public void setSuite(Suite suite) {
+            this.suite = suite;
+        }
+
+        public Statistics getStatistics() {
+            return this.statistics;
+        }
+
+        public void setStatistics(Statistics statistics) {
+            this.statistics = statistics;
+        }
+
+        public String getGenerated() {
+            return this.generated;
+        }
+
+        public void setGenerated(String generated) {
+            this.generated = generated;
+        }
+
+        public String getGenerator() {
+            return this.generator;
+        }
+
+        public void setGenerator(String generator) {
+            this.generator = generator;
+        }
+
+        public String getErrors() {
+            return this.errors;
+        }
+
+        public void setErrors(String errors) {
+            this.errors = errors;
+        }
+
+        public class Suite {
+            @JsonProperty("status")
+            private Suite.Status status;
+
+            @JsonProperty("_id")
+            private String suiteId;
+
+            @JsonProperty("_name")
+            private String name;
+
+            public Suite() {
+
+            }
+
+            public String getSuiteId() {
+                return this.suiteId;
+            }
+
+            public void setSuiteId(String suiteId) {
+                this.suiteId = suiteId;
+            }
+
+            public String getName() {
+                return this.name;
+            }
+
+            public void setName(String name) {
+                this.name = name;
+            }
+
+            public Suite.Status getStatus() {
+                return this.status;
+            }
+
+            public void setStatus(Suite.Status status) {
+                this.status = status;
+            }
+
+            public class Status {
+                @JsonProperty("_status")
+                private String statusValue;
+
+                @JsonProperty("_starttime")
+                private String startTime;
+
+                @JsonProperty("_endtime")
+                private String endTime;
+
+                public Status() {
+
+                }
+
+                public String getStatusValue() {
+                    return this.statusValue;
+                }
+
+                public void setStatusValue(String statusValue) {
+                    this.statusValue = statusValue;
+                }
+
+                public String getStartTime() {
+                    return this.startTime;
+                }
+
+                public void setStartTime(String startTime) {
+                    this.startTime = startTime;
+                }
+
+                public String getEndTime() {
+                    return this.endTime;
+                }
+
+                public void setEndTime(String endTime) {
+                    this.endTime = endTime;
+                }
+            }
+
+        }
+
+        public class Statistics {
+            @JsonProperty("suite")
+            private Suite suite;
+
+            @JsonProperty("total")
+            private Total total;
+
+            @JsonProperty("tag")
+            private TagStat tag;
+
+            public Statistics() {
+
+            }
+
+            public Suite getSuite() {
+                return this.suite;
+            }
+
+            public void setSuite(Suite suite) {
+                this.suite = suite;
+            }
+
+            public Total getTotal() {
+                return this.total;
+            }
+
+            public void setTotal(Total total) {
+                this.total = total;
+            }
+
+            public TagStat getTag() {
+                return this.tag;
+            }
+
+            public void setTag(TagStat tag) {
+                this.tag = tag;
+            }
+
+            public class Suite {
+                @JsonProperty("stat")
+                private List<Status> stat;
+
+                public Suite() {
+
+                }
+
+                public List<Status> getStat() {
+                    return this.stat;
+                }
+
+                public void setStat(List<Status> stat) {
+                    this.stat = stat;
+                }
+            }
+
+            public class Total {
+                @JsonProperty("stat")
+                private List<Status> stat;
+
+                public Total() {
+
+                }
+
+                public List<Status> getStat() {
+                    return this.stat;
+                }
+
+                public void setStat(List<Status> stat) {
+                    this.stat = stat;
+                }
+            }
+
+            public class TagStat {
+                @JsonProperty("stat")
+                private List<Status> stat;
+
+                public TagStat() {
+
+                }
+
+                public List<Status> getStat() {
+                    return this.stat;
+                }
+
+                public void setStat(List<Status> stat) {
+                    this.stat = stat;
+                }
+            }
+        }
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/Status.java b/ui/src/main/java/org/akraino/validation/ui/client/nexus/resources/Status.java
new file mode 100644 (file)
index 0000000..07639f2
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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 Status {
+    @JsonProperty("fail")
+    private int fail;
+
+    @JsonProperty("pass")
+    private int pass;
+
+    @JsonProperty("name")
+    private String name;
+
+    @JsonProperty("content")
+    private String content;
+
+    public Status() {
+
+    }
+
+    public int getFail() {
+        return this.fail;
+    }
+
+    public void setFail(int fail) {
+        this.fail = fail;
+    }
+
+    public int getPass() {
+        return this.pass;
+    }
+
+    public void setPass(int pass) {
+        this.pass = pass;
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getContent() {
+        return this.content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/common/PropertyUtil.java b/ui/src/main/java/org/akraino/validation/ui/common/PropertyUtil.java
new file mode 100644 (file)
index 0000000..d0e46b2
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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.common;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Properties;
+
+import org.akraino.validation.ui.config.AppConfig;
+import org.apache.log4j.Logger;
+
+public class PropertyUtil {
+    private static final Logger LOGGER = Logger.getLogger(PropertyUtil.class);
+    private static final String PROP_FILENAME = "app.properties";
+    private static PropertyUtil instance;
+
+    private Properties appProps;
+
+    /**
+     * Return the single instance of this object in the app.
+     *
+     * @return the singleton
+     */
+    public static synchronized PropertyUtil getInstance() {
+        if (instance == null) {
+            instance = new PropertyUtil();
+        }
+        return instance;
+    }
+
+    private PropertyUtil() {
+        InputStream input = AppConfig.class.getClassLoader().getResourceAsStream(PROP_FILENAME);
+        appProps = new Properties();
+        try {
+            appProps.load(input);
+        } catch (IOException e) {
+            LOGGER.error("Error loading properties file: " + PROP_FILENAME);
+        } finally {
+            try {
+                input.close();
+            } catch (IOException e) {
+                // ignore
+            }
+        }
+    }
+
+    /**
+     * Get a property from the PropertyUtil object. If the environment variable $IP is set, then any URL's referring to
+     * localhost will be rewritten to use this IP address instead.
+     *
+     * @param key the key to use to find the property
+     * @return the value
+     */
+    public String getProperty(String key) {
+        String property = appProps.getProperty(key);
+        if (property != null && property.indexOf("://localhost:") > 0) {
+            String ipAddr = System.getenv().get("IP");
+            if (ipAddr != null && !"".contentEquals(ipAddr)) {
+                property = property.replaceAll("://localhost:", "://" + ipAddr + ":");
+            }
+        }
+        return property;
+    }
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/common/ServiceInitializationListener.java b/ui/src/main/java/org/akraino/validation/ui/common/ServiceInitializationListener.java
new file mode 100644 (file)
index 0000000..e4836ad
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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.common;
+
+import org.springframework.context.ApplicationListener;
+import org.springframework.context.event.ContextRefreshedEvent;
+import org.springframework.stereotype.Component;
+
+@Component
+public class ServiceInitializationListener implements ApplicationListener<ContextRefreshedEvent> {
+
+    @Override
+    public void onApplicationEvent(ContextRefreshedEvent event) {
+
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/common/SessionManagerFilter.java b/ui/src/main/java/org/akraino/validation/ui/common/SessionManagerFilter.java
new file mode 100644 (file)
index 0000000..e0ddd91
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ * 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.common;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.log4j.Logger;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+public class SessionManagerFilter implements HandlerInterceptor {
+
+    private static final Logger LOGGER = Logger.getLogger(SessionManagerFilter.class);
+
+    @Override
+    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
+            throws Exception {
+
+        LOGGER.info("user authenticated");
+
+    }
+
+    @Override
+    public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
+            throws Exception {
+
+        LOGGER.info("user authenticated");
+
+    }
+
+    @Override
+    public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object data) throws Exception {
+
+        try {
+            return true;
+            /*
+             * if (StringUtil.notEmpty(req.getHeader("tokenId"))) {
+             *
+             * String clientToken = req.getHeader("tokenId");
+             *
+             * AccessService service = new AccessService();
+             *
+             * UserSession user = service.getUserSession(LoginUtil.decode(LoginUtil.getUserName(clientToken)));
+             *
+             * if (user.getTokenId()!= null && !sessionExpired(user)) {
+             *
+             * if (user.getTokenId().equals(LoginUtil.getPassword(clientToken))) { // user authorized return true;
+             *
+             * } else { // unauthorized access res.sendError(401); } } else { // session does not exist/expired,
+             * temporary re-direct, ask user to re-login res.sendError(307); }
+             *
+             * } else { // bad request, no authToken sent in the request res.sendError(400); }
+             */
+        } catch (Exception e) {
+            LOGGER.error(e);
+        }
+
+
+        return false;
+    }
+
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/config/AppConfig.java b/ui/src/main/java/org/akraino/validation/ui/config/AppConfig.java
new file mode 100644 (file)
index 0000000..6d55d42
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * 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.config;
+
+import javax.sql.DataSource;
+
+import org.akraino.validation.ui.common.PropertyUtil;
+import org.akraino.validation.ui.common.SessionManagerFilter;
+import org.apache.commons.dbcp.BasicDataSource;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.multipart.commons.CommonsMultipartResolver;
+import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
+import org.springframework.web.servlet.config.annotation.EnableWebMvc;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
+
+@Configuration
+@EnableWebMvc
+@ComponentScan(basePackages = "org.akraino.validation.ui")
+public class AppConfig extends WebMvcConfigurerAdapter {
+
+    @Bean
+    SessionManagerFilter getSessionManager() {
+        return new SessionManagerFilter();
+    }
+
+    @Override
+    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
+        configurer.enable();
+    }
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(getSessionManager()).addPathPatterns("/**").excludePathPatterns("/login", "/logout");
+
+    }
+
+    @Bean
+    public CommonsMultipartResolver multipartResolver() {
+
+        CommonsMultipartResolver cmr = new CommonsMultipartResolver();
+        cmr.setMaxUploadSize(1000000 * 2);
+        cmr.setMaxUploadSizePerFile(2000000); // bytes
+        return cmr;
+
+    }
+
+    @Bean(name = "dataSource")
+    public DataSource getDataSource() {
+        BasicDataSource dataSource = new BasicDataSource();
+        dataSource.setDriverClassName("org.postgresql.Driver");
+        dataSource.setUrl(PropertyUtil.getInstance().getProperty("postgres.db.url"));
+        dataSource.setUsername(PropertyUtil.getInstance().getProperty("postgres.db.user.name"));
+        dataSource.setPassword(System.getenv("postgres_db_user_pwd"));
+
+        return dataSource;
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/config/AppInitializer.java b/ui/src/main/java/org/akraino/validation/ui/config/AppInitializer.java
new file mode 100644 (file)
index 0000000..d79b2ae
--- /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.config;
+
+import java.lang.reflect.Field;
+import java.util.Comparator;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.PriorityBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRegistration;
+
+import org.springframework.web.WebApplicationInitializer;
+import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
+import org.springframework.web.servlet.DispatcherServlet;
+
+public class AppInitializer implements WebApplicationInitializer {
+
+    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
+    // 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
+    // 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);
+
+    @Override
+    public void onStartup(ServletContext container) throws ServletException {
+
+        AnnotationConfigWebApplicationContext ctx = new AnnotationConfigWebApplicationContext();
+        ctx.register(AppConfig.class);
+        ctx.setServletContext(container);
+
+        ServletRegistration.Dynamic servlet = container.addServlet("dispatcher", new DispatcherServlet(ctx));
+
+        servlet.setLoadOnStartup(1);
+        servlet.addMapping("/");
+
+    }
+
+    private static class CFRunnableComparator implements Comparator<Runnable> {
+        @Override
+        @SuppressWarnings("unchecked")
+        public int compare(Runnable runnable1, Runnable runnable2) {
+            // T might be AsyncSupply, UniApply, etc., but we want to
+            // compare our original Runnables.
+            return ((Comparable) unwrap(runnable1)).compareTo(unwrap(runnable2));
+        }
+
+        private Object unwrap(Runnable runnable) {
+            try {
+                Field field = runnable.getClass().getDeclaredField("fn");
+                field.setAccessible(true);
+                // NB: For performance-intensive contexts, you may want to
+                // cache these in a ConcurrentHashMap<Class<?>, Field>.
+                return field.get(runnable);
+            } catch (IllegalAccessException | NoSuchFieldException e) {
+                throw new IllegalArgumentException("Couldn't unwrap " + runnable, e);
+            }
+        }
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/config/HibernateConfig.java b/ui/src/main/java/org/akraino/validation/ui/config/HibernateConfig.java
new file mode 100644 (file)
index 0000000..03a91be
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ * 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.config;
+
+import java.util.Properties;
+
+import javax.sql.DataSource;
+
+import org.hibernate.SessionFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.orm.hibernate5.HibernateTransactionManager;
+import org.springframework.orm.hibernate5.LocalSessionFactoryBuilder;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@Configuration
+@EnableTransactionManagement
+@PropertySource(value = {"classpath:hibernate.properties"})
+public class HibernateConfig {
+
+    @Autowired
+    private Environment env;
+
+    @Autowired
+    @Bean(name = "sessionFactory")
+    public SessionFactory getSessionFactory(DataSource dataSource) {
+        LocalSessionFactoryBuilder sessionBuilder = new LocalSessionFactoryBuilder(dataSource);
+
+        sessionBuilder.scanPackages("org.akraino.validation.ui.entity");
+        sessionBuilder.addProperties(hibernateProperties());
+
+        return sessionBuilder.buildSessionFactory();
+
+    }
+
+    @Autowired
+    @Bean(name = "transactionManager")
+    public HibernateTransactionManager getTransactionManager(SessionFactory sessionFactory) {
+
+        return new HibernateTransactionManager(sessionFactory);
+
+    }
+
+    private Properties hibernateProperties() {
+
+        Properties properties = new Properties();
+
+        properties.put("hibernate.dialect", env.getProperty("hibernate.dialect"));
+        properties.put("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
+        properties.put("hibernate.c3p0.min_size", env.getProperty("hibernate.c3p0.min_size"));
+        properties.put("hibernate.c3p0.max_size", env.getProperty("hibernate.c3p0.max_size"));
+        properties.put("hibernate.c3p0.max_statements", env.getProperty("hibernate.c3p0.max_statements"));
+        properties.put("hibernate.c3p0.acquire_increment", env.getProperty("hibernate.c3p0.acquire_increment"));
+        properties.put("hibernate.jdbc.use_streams_for_binary",
+                env.getProperty("hibernate.jdbc.use_streams_for_binary"));
+
+        return properties;
+    }
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/controller/BlueprintController.java b/ui/src/main/java/org/akraino/validation/ui/controller/BlueprintController.java
new file mode 100644 (file)
index 0000000..22ae510
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.util.List;
+
+import org.akraino.validation.ui.entity.Blueprint;
+import org.akraino.validation.ui.service.BlueprintService;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/blueprint")
+public class BlueprintController {
+
+    @Autowired
+    BlueprintService service;
+
+    private static final Logger LOGGER = Logger.getLogger(BlueprintController.class);
+
+    @GetMapping("/")
+    public ResponseEntity<List<Blueprint>> getBlueprints() {
+        try {
+            return new ResponseEntity<>(service.getBlueprints(), HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(e);
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/controller/BlueprintInstanceController.java b/ui/src/main/java/org/akraino/validation/ui/controller/BlueprintInstanceController.java
new file mode 100644 (file)
index 0000000..6acdba8
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.util.List;
+
+import org.akraino.validation.ui.entity.BlueprintInstance;
+import org.akraino.validation.ui.service.BlueprintInstanceService;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/blueprintInstance")
+public class BlueprintInstanceController {
+
+    @Autowired
+    BlueprintInstanceService service;
+
+    private static final Logger LOGGER = Logger.getLogger(BlueprintInstanceController.class);
+
+    @GetMapping("/")
+    public ResponseEntity<List<BlueprintInstance>> getBlueprintInstances() {
+        try {
+            return new ResponseEntity<>(service.getBlueprintInstances(), HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(e);
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/controller/JenkinsJobNotificationController.java b/ui/src/main/java/org/akraino/validation/ui/controller/JenkinsJobNotificationController.java
new file mode 100644 (file)
index 0000000..1c0b3bc
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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 org.akraino.validation.ui.data.JnksJobNotify;
+import org.akraino.validation.ui.service.JenkinsJobNotificationService;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/jenkinsJobNotification")
+public class JenkinsJobNotificationController {
+
+    @Autowired
+    JenkinsJobNotificationService service;
+
+    private static final Logger LOGGER = Logger.getLogger(JenkinsJobNotificationController.class);
+
+    @PostMapping("/")
+    public ResponseEntity<Void> handle(@RequestBody JnksJobNotify jnksJobNotify) {
+        try {
+            service.handle(jnksJobNotify);
+            return new ResponseEntity<Void>(HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(e);
+        }
+        return new ResponseEntity<Void>(HttpStatus.INTERNAL_SERVER_ERROR);
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/controller/ResultsController.java b/ui/src/main/java/org/akraino/validation/ui/controller/ResultsController.java
new file mode 100644 (file)
index 0000000..3013948
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.util.List;
+
+import org.akraino.validation.ui.client.nexus.resources.RobotTestResult;
+import org.akraino.validation.ui.service.ResultService;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/results")
+public class ResultsController {
+
+    private static final Logger LOGGER = Logger.getLogger(ResultsController.class);
+
+    @Autowired
+    ResultService service;
+
+    @RequestMapping(value = "/findBySubmissionId/{id}")
+    public ResponseEntity<List<RobotTestResult>> findByBlueprintId(@PathVariable("id") String submissionId) {
+        try {
+            return new ResponseEntity<>(service.getRobotTestResults(submissionId), HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(e);
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/controller/SubmissionController.java b/ui/src/main/java/org/akraino/validation/ui/controller/SubmissionController.java
new file mode 100644 (file)
index 0000000..ca78b0d
--- /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.
+ */
+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.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/submission")
+public class SubmissionController {
+
+    @Autowired
+    SubmissionService service;
+
+    private static final Logger LOGGER = Logger.getLogger(SubmissionController.class);
+
+    @GetMapping("/")
+    public ResponseEntity<List<Submission>> getSubmissions() {
+        try {
+            return new ResponseEntity<>(service.getSubmissions(), HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(e);
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+    @PostMapping("/")
+    public ResponseEntity<Submission> postSubmission(@RequestBody Submission newSubmission) {
+        try {
+            return new ResponseEntity<>(service.saveSubmission(newSubmission), HttpStatus.CREATED);
+        } catch (Exception e) {
+            LOGGER.error(e);
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+    @DeleteMapping("/")
+    public ResponseEntity<Boolean> deleteSubmission(@RequestBody Submission submission) {
+        try {
+            service.deleteSubmission(submission.getSubmissionId());
+            return new ResponseEntity<>(true, HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(e);
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(false);
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/controller/TimeSlotsController.java b/ui/src/main/java/org/akraino/validation/ui/controller/TimeSlotsController.java
new file mode 100644 (file)
index 0000000..d6da8a9
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.util.List;
+
+import org.akraino.validation.ui.entity.Timeslot;
+import org.akraino.validation.ui.service.TimeslotService;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("/api/timeslots")
+public class TimeSlotsController {
+
+    @Autowired
+    TimeslotService service;
+
+    private static final Logger LOGGER = Logger.getLogger(TimeSlotsController.class);
+
+    @GetMapping("/")
+    public ResponseEntity<List<Timeslot>> getTimeSlots() {
+        try {
+            return new ResponseEntity<>(service.getTimeslots(), HttpStatus.OK);
+        } catch (Exception e) {
+            LOGGER.error(e);
+        }
+        return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(null);
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/dao/BlueprintDAO.java b/ui/src/main/java/org/akraino/validation/ui/dao/BlueprintDAO.java
new file mode 100644 (file)
index 0000000..537d298
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.Blueprint;
+
+public interface BlueprintDAO {
+
+    void saveOrUpdate(Blueprint blueprint);
+
+    void merge(Blueprint blueprint);
+
+    List<Blueprint> getBlueprints();
+
+    Blueprint getBlueprint(Integer blueprintId);
+
+    void deleteBlueprint(Blueprint blueprint);
+
+    void deleteAll();
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/dao/BlueprintInstanceDAO.java b/ui/src/main/java/org/akraino/validation/ui/dao/BlueprintInstanceDAO.java
new file mode 100644 (file)
index 0000000..5093681
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.BlueprintInstance;
+
+public interface BlueprintInstanceDAO {
+
+    void saveOrUpdate(BlueprintInstance blueprintInstance);
+
+    void merge(BlueprintInstance blueprintInstance);
+
+    List<BlueprintInstance> getBlueprintInstances();
+
+    BlueprintInstance getBlueprintInstance(Integer instId);
+
+    void deleteBlueprintInstance(BlueprintInstance blueprintInstance);
+
+    void deleteAll();
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/dao/SubmissionDAO.java b/ui/src/main/java/org/akraino/validation/ui/dao/SubmissionDAO.java
new file mode 100644 (file)
index 0000000..fc5e84f
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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.Submission;
+
+public interface SubmissionDAO {
+
+    void saveOrUpdate(Submission submission);
+
+    void merge(Submission submission);
+
+    List<Submission> getSubmissions();
+
+    Submission getSubmission(Integer submissionId);
+
+    void deleteSubmission(Submission submission);
+
+    void deleteSubmission(Integer submissionId);
+
+    void deleteAll();
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/dao/TimeslotDAO.java b/ui/src/main/java/org/akraino/validation/ui/dao/TimeslotDAO.java
new file mode 100644 (file)
index 0000000..c4dbbe1
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.Timeslot;
+
+public interface TimeslotDAO {
+
+    void saveOrUpdate(Timeslot timeslot);
+
+    void merge(Timeslot timeslot);
+
+    List<Timeslot> getTimeslots();
+
+    Timeslot getTimeslot(Integer timeslotId);
+
+    void deleteTimeslot(Timeslot timeslot);
+
+    void deleteAll();
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintDAOImpl.java b/ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintDAOImpl.java
new file mode 100644 (file)
index 0000000..5466c13
--- /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.
+ */
+package org.akraino.validation.ui.daoimpl;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Root;
+
+import org.akraino.validation.ui.dao.BlueprintDAO;
+import org.akraino.validation.ui.entity.Blueprint;
+import org.apache.log4j.Logger;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.query.Query;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class BlueprintDAOImpl implements BlueprintDAO {
+
+    private static final Logger LOGGER = Logger.getLogger(BlueprintDAOImpl.class);
+
+    @Autowired
+    private SessionFactory sessionFactory;
+
+    protected Session getSession() {
+        return sessionFactory.getCurrentSession();
+    }
+
+    @Override
+    public List<Blueprint> getBlueprints() {
+
+        CriteriaBuilder builder = getSession().getCriteriaBuilder();
+        CriteriaQuery<Blueprint> criteria = builder.createQuery(Blueprint.class);
+
+        Root<Blueprint> root = criteria.from(Blueprint.class);
+        criteria.select(root);
+
+        Query<Blueprint> query = getSession().createQuery(criteria);
+
+        return query.getResultList();
+
+    }
+
+    @Override
+    public Blueprint getBlueprint(Integer blueprintId) {
+
+        EntityManager entityManager = getSession().getEntityManagerFactory().createEntityManager();
+
+        return entityManager.find(Blueprint.class, blueprintId);
+    }
+
+    @Override
+    public void saveOrUpdate(Blueprint blueprint) {
+        getSession().saveOrUpdate(blueprint);
+
+    }
+
+    @Override
+    public void merge(Blueprint blueprint) {
+        getSession().merge(blueprint);
+
+    }
+
+    @Override
+    public void deleteBlueprint(Blueprint blueprint) {
+        getSession().delete(blueprint);
+
+    }
+
+    @Override
+    public void deleteAll() {
+
+        Query<?> query = getSession().createQuery("delete from Blueprint");
+
+        int result = query.executeUpdate();
+
+        if (result > 0) {
+            LOGGER.info("All blueprint entries are cleaned up");
+        }
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintInstanceDAOImpl.java b/ui/src/main/java/org/akraino/validation/ui/daoimpl/BlueprintInstanceDAOImpl.java
new file mode 100644 (file)
index 0000000..4bacb14
--- /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.
+ */
+package org.akraino.validation.ui.daoimpl;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Root;
+
+import org.akraino.validation.ui.dao.BlueprintInstanceDAO;
+import org.akraino.validation.ui.entity.BlueprintInstance;
+import org.apache.log4j.Logger;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.query.Query;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class BlueprintInstanceDAOImpl implements BlueprintInstanceDAO {
+
+    private static final Logger LOGGER = Logger.getLogger(BlueprintInstanceDAOImpl.class);
+
+    @Autowired
+    private SessionFactory sessionFactory;
+
+    protected Session getSession() {
+        return sessionFactory.getCurrentSession();
+    }
+
+    @Override
+    public List<BlueprintInstance> getBlueprintInstances() {
+
+        CriteriaBuilder builder = getSession().getCriteriaBuilder();
+        CriteriaQuery<BlueprintInstance> criteria = builder.createQuery(BlueprintInstance.class);
+
+        Root<BlueprintInstance> root = criteria.from(BlueprintInstance.class);
+        criteria.select(root);
+
+        Query<BlueprintInstance> query = getSession().createQuery(criteria);
+
+        return query.getResultList();
+
+    }
+
+    @Override
+    public BlueprintInstance getBlueprintInstance(Integer instId) {
+
+        EntityManager entityManager = getSession().getEntityManagerFactory().createEntityManager();
+
+        return entityManager.find(BlueprintInstance.class, instId);
+    }
+
+    @Override
+    public void saveOrUpdate(BlueprintInstance blueprintInstance) {
+        getSession().saveOrUpdate(blueprintInstance);
+
+    }
+
+    @Override
+    public void merge(BlueprintInstance blueprintInstance) {
+        getSession().merge(blueprintInstance);
+
+    }
+
+    @Override
+    public void deleteBlueprintInstance(BlueprintInstance blueprintInstance) {
+        getSession().delete(blueprintInstance);
+
+    }
+
+    @Override
+    public void deleteAll() {
+
+        Query<?> query = getSession().createQuery("delete from BlueprintInstance");
+
+        int result = query.executeUpdate();
+
+        if (result > 0) {
+            LOGGER.info("All blueprint instance entries are cleaned up");
+        }
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/daoimpl/SubmissionDAOImpl.java b/ui/src/main/java/org/akraino/validation/ui/daoimpl/SubmissionDAOImpl.java
new file mode 100644 (file)
index 0000000..fd4da86
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * 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.persistence.EntityManager;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Root;
+
+import org.akraino.validation.ui.dao.SubmissionDAO;
+import org.akraino.validation.ui.entity.Submission;
+import org.apache.log4j.Logger;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.query.Query;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class SubmissionDAOImpl implements SubmissionDAO {
+
+    private static final Logger LOGGER = Logger.getLogger(SubmissionDAOImpl.class);
+
+    @Autowired
+    private SessionFactory sessionFactory;
+
+    protected Session getSession() {
+        return sessionFactory.getCurrentSession();
+    }
+
+    @Override
+    public List<Submission> getSubmissions() {
+
+        CriteriaBuilder builder = getSession().getCriteriaBuilder();
+        CriteriaQuery<Submission> criteria = builder.createQuery(Submission.class);
+
+        Root<Submission> root = criteria.from(Submission.class);
+        criteria.select(root);
+
+        Query<Submission> query = getSession().createQuery(criteria);
+
+        return query.getResultList();
+
+    }
+
+    @Override
+    public Submission getSubmission(Integer submissionId) {
+
+        EntityManager entityManager = getSession().getEntityManagerFactory().createEntityManager();
+
+        return entityManager.find(Submission.class, submissionId);
+    }
+
+    @Override
+    public void saveOrUpdate(Submission submission) {
+        getSession().saveOrUpdate(submission);
+
+    }
+
+    @Override
+    public void merge(Submission submission) {
+        getSession().merge(submission);
+
+    }
+
+    @Override
+    public void deleteSubmission(Submission submission) {
+        getSession().delete(submission);
+
+    }
+
+    @Override
+    public void deleteSubmission(Integer submissionId) {
+        getSession().delete(this.getSubmission(submissionId));
+    }
+
+    @Override
+    public void deleteAll() {
+
+        Query<?> query = getSession().createQuery("delete from Submission");
+
+        int result = query.executeUpdate();
+
+        if (result > 0) {
+            LOGGER.info("All submission entries are cleaned up");
+        }
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/daoimpl/TimeslotDAOImpl.java b/ui/src/main/java/org/akraino/validation/ui/daoimpl/TimeslotDAOImpl.java
new file mode 100644 (file)
index 0000000..e49c37a
--- /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.
+ */
+package org.akraino.validation.ui.daoimpl;
+
+import java.util.List;
+
+import javax.persistence.EntityManager;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Root;
+
+import org.akraino.validation.ui.dao.TimeslotDAO;
+import org.akraino.validation.ui.entity.Timeslot;
+import org.apache.log4j.Logger;
+import org.hibernate.Session;
+import org.hibernate.SessionFactory;
+import org.hibernate.query.Query;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Repository;
+
+@Repository
+public class TimeslotDAOImpl implements TimeslotDAO {
+
+    private static final Logger LOGGER = Logger.getLogger(TimeslotDAOImpl.class);
+
+    @Autowired
+    private SessionFactory sessionFactory;
+
+    protected Session getSession() {
+        return sessionFactory.getCurrentSession();
+    }
+
+    @Override
+    public List<Timeslot> getTimeslots() {
+
+        CriteriaBuilder builder = getSession().getCriteriaBuilder();
+        CriteriaQuery<Timeslot> criteria = builder.createQuery(Timeslot.class);
+
+        Root<Timeslot> root = criteria.from(Timeslot.class);
+        criteria.select(root);
+
+        Query<Timeslot> query = getSession().createQuery(criteria);
+
+        return query.getResultList();
+
+    }
+
+    @Override
+    public Timeslot getTimeslot(Integer timeslotId) {
+
+        EntityManager entityManager = getSession().getEntityManagerFactory().createEntityManager();
+
+        return entityManager.find(Timeslot.class, timeslotId);
+    }
+
+    @Override
+    public void saveOrUpdate(Timeslot timeslot) {
+        getSession().saveOrUpdate(timeslot);
+
+    }
+
+    @Override
+    public void merge(Timeslot timeslot) {
+        getSession().merge(timeslot);
+
+    }
+
+    @Override
+    public void deleteTimeslot(Timeslot timeslot) {
+        getSession().delete(timeslot);
+
+    }
+
+    @Override
+    public void deleteAll() {
+
+        Query<?> query = getSession().createQuery("delete from Timeslot");
+
+        int result = query.executeUpdate();
+
+        if (result > 0) {
+            LOGGER.info("All timeslot entries are cleaned up");
+        }
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/data/BlueprintLayer.java b/ui/src/main/java/org/akraino/validation/ui/data/BlueprintLayer.java
new file mode 100644 (file)
index 0000000..75278c2
--- /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.
+ */
+package org.akraino.validation.ui.data;
+
+public enum BlueprintLayer {
+    Hardware, OS, K8s, Kubeless, OpenStack, VNF, Application
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/data/JnksJobNotify.java b/ui/src/main/java/org/akraino/validation/ui/data/JnksJobNotify.java
new file mode 100644 (file)
index 0000000..f72a307
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * 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.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 JnksJobNotify {
+
+    @JsonProperty("name")
+    private String name;
+
+    @JsonProperty("buildNumber")
+    private Integer buildNumber;
+
+    @JsonProperty("submissionId")
+    private Integer submissionId;
+
+    public JnksJobNotify() {
+
+    }
+
+    public String getName() {
+        return this.name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public Integer getbuildNumber() {
+        return this.buildNumber;
+    }
+
+    public void setbuildNumber(Integer buildNumber) {
+        this.buildNumber = buildNumber;
+    }
+
+    public Integer getSubmissionId() {
+        return this.submissionId;
+    }
+
+    public void setSubmissionId(Integer submissionId) {
+        this.submissionId = submissionId;
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/data/Lab.java b/ui/src/main/java/org/akraino/validation/ui/data/Lab.java
new file mode 100644 (file)
index 0000000..ae84d8e
--- /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.
+ */
+package org.akraino.validation.ui.data;
+
+public enum Lab {
+    ATT, Ericsson, Community, Arm
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/data/SubmissionStatus.java b/ui/src/main/java/org/akraino/validation/ui/data/SubmissionStatus.java
new file mode 100644 (file)
index 0000000..2e01d9b
--- /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.
+ */
+package org.akraino.validation.ui.data;
+
+public enum SubmissionStatus {
+    Submitted, Waiting, Running, Completed
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/entity/Blueprint.java b/ui/src/main/java/org/akraino/validation/ui/entity/Blueprint.java
new file mode 100644 (file)
index 0000000..05a27cc
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * 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.SequenceGenerator;
+import javax.persistence.Table;
+
+@Entity
+@Table(name = "akraino.blueprint")
+public class Blueprint implements Serializable {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "blueprint_id_generator")
+    @SequenceGenerator(name = "blueprint_id_generator", sequenceName = "akraino.seq_blueprint", allocationSize = 1)
+    @Column(name = "blueprint_id")
+    private int blueprintId;
+
+    @Column(name = "blueprint_name")
+    private String blueprintName;
+
+    public int getBlueprintId() {
+        return blueprintId;
+    }
+
+    public void setBlueprintId(int blueprintId) {
+        this.blueprintId = blueprintId;
+    }
+
+    public String getBlueprintName() {
+        return blueprintName;
+    }
+
+    public void setBlueprintName(String blueprintName) {
+        this.blueprintName = blueprintName;
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/entity/BlueprintInstance.java b/ui/src/main/java/org/akraino/validation/ui/entity/BlueprintInstance.java
new file mode 100644 (file)
index 0000000..93206db
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * 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.SequenceGenerator;
+import javax.persistence.Table;
+
+import org.akraino.validation.ui.data.BlueprintLayer;
+
+@Entity
+@Table(name = "akraino.blueprint_instance")
+public class BlueprintInstance implements Serializable {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "blueprint_instance_id_generator")
+    @SequenceGenerator(name = "blueprint_instance_id_generator", sequenceName = "akraino.seq_blueprint_instance",
+            allocationSize = 1)
+    @Column(name = "blueprint_instance_id")
+    private int blueprintInstId;
+
+    @ManyToOne
+    @JoinColumn(name = "blueprint_id")
+    private Blueprint blueprint;
+
+    @Column(name = "version")
+    private String version;
+
+    @Column(name = "layer")
+    private BlueprintLayer layer;
+
+    @Column(name = "layer_description")
+    private String layerDescription;
+
+    @OneToOne
+    @JoinColumn(name = "timeslot_id")
+    private Timeslot timeslot;
+
+    public int getBlueprintInstanceId() {
+        return blueprintInstId;
+    }
+
+    public void setBlueprintInstanceId(int blueprintInstId) {
+        this.blueprintInstId = blueprintInstId;
+    }
+
+    public Blueprint getBlueprint() {
+        return blueprint;
+    }
+
+    public void setBlueprint(Blueprint blueprint) {
+        this.blueprint = blueprint;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public BlueprintLayer getLayer() {
+        return layer;
+    }
+
+    public void setLayer(BlueprintLayer layer) {
+        this.layer = layer;
+    }
+
+    public void setLayerDescription(String layerDescription) {
+        this.layerDescription = layerDescription;
+    }
+
+    public String getLayerDescription() {
+        return layerDescription;
+    }
+
+    public void setTimeslot(Timeslot timeslot) {
+        this.timeslot = timeslot;
+    }
+
+    public Timeslot getTimeslot() {
+        return this.timeslot;
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/entity/Submission.java b/ui/src/main/java/org/akraino/validation/ui/entity/Submission.java
new file mode 100644 (file)
index 0000000..1d5d157
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * 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 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.SequenceGenerator;
+import javax.persistence.Table;
+
+import org.akraino.validation.ui.data.SubmissionStatus;
+
+@Entity
+@Table(name = "akraino.submission")
+public class Submission {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "submission_id_generator")
+    @SequenceGenerator(name = "submission_id_generator", sequenceName = "akraino.seq_submission", allocationSize = 1)
+    @Column(name = "submission_id")
+    private int submissionId;
+
+    @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_id")
+    private BlueprintInstance blueprintInstance;
+
+    public void setSubmissionId(int submissionId) {
+        this.submissionId = submissionId;
+    }
+
+    public int getSubmissionId() {
+        return submissionId;
+    }
+
+    public SubmissionStatus getSubmissionStatus() {
+        return this.status;
+    }
+
+    public void setSubmissionStatus(SubmissionStatus submissionStatus) {
+        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 setBlueprintInstance(BlueprintInstance blueprintInstance) {
+        this.blueprintInstance = blueprintInstance;
+    }
+
+    public BlueprintInstance getBlueprintInstance() {
+        return this.blueprintInstance;
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/entity/Timeslot.java b/ui/src/main/java/org/akraino/validation/ui/entity/Timeslot.java
new file mode 100644 (file)
index 0000000..c53fa49
--- /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.SequenceGenerator;
+import javax.persistence.Table;
+
+import org.akraino.validation.ui.data.Lab;
+
+@Entity
+@Table(name = "akraino.timeslot")
+public class Timeslot implements Serializable {
+
+    /**
+     *
+     */
+    private static final long serialVersionUID = 1L;
+
+    @Id
+    @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "timeslot_id_generator")
+    @SequenceGenerator(name = "timeslot_id_generator", sequenceName = "akraino.seq_timeslot", allocationSize = 1)
+    @Column(name = "timeslot_id")
+    private int timeslotId;
+
+    @Column(name = "start_date_time")
+    private String startDateTime;
+
+    @Column(name = "duration")
+    private int duration;
+
+    @Column(name = "lab")
+    private Lab lab;
+
+    public void setTimeslotId(int timeslotId) {
+        this.timeslotId = timeslotId;
+    }
+
+    public int getTimeslotId() {
+        return timeslotId;
+    }
+
+    public void setStartDateTime(String startDateTime) {
+        this.startDateTime = startDateTime;
+    }
+
+    public String getStartDateTime() {
+        return startDateTime;
+    }
+
+    public void setDuration(int duration) {
+        this.duration = duration;
+    }
+
+    public int getDuration() {
+        return duration;
+    }
+
+    public void setLab(Lab lab) {
+        this.lab = lab;
+    }
+
+    public Lab getLab() {
+        return lab;
+    }
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/service/BlueprintInstanceService.java b/ui/src/main/java/org/akraino/validation/ui/service/BlueprintInstanceService.java
new file mode 100644 (file)
index 0000000..33914a4
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.util.List;
+
+import org.akraino.validation.ui.dao.BlueprintInstanceDAO;
+import org.akraino.validation.ui.entity.BlueprintInstance;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Transactional
+public class BlueprintInstanceService {
+
+    @Autowired
+    private BlueprintInstanceDAO blueprintInstDAO;
+
+    public void saveBlueprintInstance(BlueprintInstance blueprintInstance) {
+
+        blueprintInstDAO.saveOrUpdate(blueprintInstance);
+
+    }
+
+    public List<BlueprintInstance> getBlueprintInstances() {
+
+        return blueprintInstDAO.getBlueprintInstances();
+
+    }
+
+    public void deleteAll() {
+        blueprintInstDAO.deleteAll();
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/service/BlueprintService.java b/ui/src/main/java/org/akraino/validation/ui/service/BlueprintService.java
new file mode 100644 (file)
index 0000000..019802c
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.util.List;
+
+import org.akraino.validation.ui.dao.BlueprintDAO;
+import org.akraino.validation.ui.entity.Blueprint;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Transactional
+public class BlueprintService {
+
+    @Autowired
+    private BlueprintDAO blueprintDAO;
+
+    public void saveBlueprint(Blueprint blueprint) {
+
+        blueprintDAO.saveOrUpdate(blueprint);
+
+    }
+
+    public List<Blueprint> getBlueprints() {
+
+        return blueprintDAO.getBlueprints();
+
+    }
+
+    public void deleteAll() {
+        blueprintDAO.deleteAll();
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/service/JenkinsJobNotificationService.java b/ui/src/main/java/org/akraino/validation/ui/service/JenkinsJobNotificationService.java
new file mode 100644 (file)
index 0000000..0a50ad8
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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 org.akraino.validation.ui.data.JnksJobNotify;
+import org.akraino.validation.ui.data.SubmissionStatus;
+import org.akraino.validation.ui.entity.Submission;
+import org.akraino.validation.ui.service.utils.SubmissionHelper;
+import org.apache.log4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Transactional
+public class JenkinsJobNotificationService {
+
+    @Autowired
+    private SubmissionHelper submissionHelper;
+
+    @Autowired
+    private SubmissionService submissionService;
+
+    private static final Logger LOGGER = Logger.getLogger(JenkinsJobNotificationService.class);
+
+    public void handle(JnksJobNotify jnksJobNotify) {
+        String jenkinsJobName = System.getenv("jenkins_job_name");
+        if (!jenkinsJobName.equals(jnksJobNotify.getName())) {
+            return;
+        }
+        Submission submission = submissionService.getSubmission(Integer.toString(jnksJobNotify.getSubmissionId()));
+        if (submission == null) {
+            LOGGER.debug("No related submission was found.");
+            return;
+        }
+        submission.setNexusResultUrl(System.getenv("nexus_results_url") + "/"
+                + submission.getBlueprintInstance().getTimeslot().getLab().name().toLowerCase() + "-blu-val"
+                + "/job/validation/" + String.valueOf(jnksJobNotify.getbuildNumber()));
+        LOGGER.info("Updating submission with id: " + submission.getSubmissionId());
+        submission.setSubmissionStatus(SubmissionStatus.Completed);
+        submissionHelper.saveSubmission(submission);
+    }
+
+}
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
new file mode 100644 (file)
index 0000000..1deffa0
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ * 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.MalformedURLException;
+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.RobotTestResult;
+import org.akraino.validation.ui.entity.Submission;
+import org.apache.commons.httpclient.HttpException;
+import org.apache.log4j.Logger;
+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 Logger LOGGER = Logger.getLogger(ResultService.class);
+
+    @Autowired
+    private SubmissionService submissionService;
+
+    @Deprecated
+    public URL getNexusResultUrl(Submission submission)
+            throws MalformedURLException, KeyManagementException, HttpException, ClientHandlerException,
+            UniformInterfaceException, NoSuchAlgorithmException, InterruptedException {
+
+        String url = System.getenv("jenkins_url");
+        String userName = System.getenv("jenkins_user_name");
+        String password = System.getenv("jenkins_user_pwd");
+
+        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);
+        }
+        return new URL(System.getenv("nexus_results_url") + "/"
+                + submission.getBlueprintInstance().getTimeslot().getLab().name().toLowerCase() + "-blu-val"
+                + "/job/validation/" + String.valueOf(executable.getNumber()));
+    }
+
+    public List<RobotTestResult> getRobotTestResults(String submissionId)
+            throws JsonParseException, JsonMappingException, KeyManagementException, ClientHandlerException,
+            UniformInterfaceException, NoSuchAlgorithmException, IOException {
+        Submission submission = submissionService.getSubmission(submissionId);
+        if (submission == null) {
+            LOGGER.info("Requested submission does not exist");
+            return null;
+        }
+        String nexusUrl = submission.getNexusResultUrl();
+        NexusExecutorClient client = new NexusExecutorClient(nexusUrl + "/results");
+        return client.getRobotTestResults();
+    }
+
+}
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
new file mode 100644 (file)
index 0000000..a6b1fca
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * 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.config.AppInitializer;
+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.apache.log4j.Logger;
+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 Logger LOGGER = Logger.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), AppInitializer.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_user_name");
+            String userPassword = System.getenv("jenkins_user_pwd");
+            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.getBlueprintInstance().getBlueprint().getBlueprintName());
+            listOfParameters.add(parameter);
+            parameter = new Parameter();
+            parameter.setName("LAYER");
+            parameter.setValue(submission.getBlueprintInstance().getLayer().name());
+            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();
+            } catch (SocketException | UnknownHostException e1) {
+                LOGGER.error(e1);
+                return null;
+            }
+            parameter.setValue(localIP);
+            listOfParameters.add(parameter);
+            parameters.setParameter(listOfParameters);
+            JenkinsExecutorClient client;
+            try {
+                client = JenkinsExecutorClient.getInstance(userName, userPassword, url);
+                submission.setJnksQueueJobItemUrl(client.postJobWithQueryParams(jobName, parameters).toString());
+            } catch (MalformedURLException | KeyManagementException | HttpException | ClientHandlerException
+                    | UniformInterfaceException | NoSuchAlgorithmException e) {
+                LOGGER.error(e);
+                return null;
+            }
+            return submission;
+        }
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/service/TimeslotService.java b/ui/src/main/java/org/akraino/validation/ui/service/TimeslotService.java
new file mode 100644 (file)
index 0000000..421c2b6
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * 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.util.List;
+
+import org.akraino.validation.ui.dao.TimeslotDAO;
+import org.akraino.validation.ui.entity.Timeslot;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Transactional
+public class TimeslotService {
+
+    @Autowired
+    private TimeslotDAO timeslotDAO;
+
+    public void saveTimeslot(Timeslot timeslot) {
+
+        timeslotDAO.saveOrUpdate(timeslot);
+
+    }
+
+    public List<Timeslot> getTimeslots() {
+
+        return timeslotDAO.getTimeslots();
+
+    }
+
+    public void deleteAll() {
+        timeslotDAO.deleteAll();
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/service/utils/PrioritySupplier.java b/ui/src/main/java/org/akraino/validation/ui/service/utils/PrioritySupplier.java
new file mode 100644 (file)
index 0000000..e1c53d5
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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.utils;
+
+import java.util.function.Supplier;
+
+public class PrioritySupplier<T> implements Supplier<T>, WithPriority {
+    private final int priorityField;
+    private final Supplier<T> supplier;
+
+    public PrioritySupplier(int priorityField, Supplier<T> supplier) {
+        this.priorityField = priorityField;
+        this.supplier = supplier;
+    }
+
+    @Override
+    public T get() {
+        return supplier.get();
+    }
+
+    @Override
+    public int priority() {
+        return priorityField;
+    }
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/service/utils/SubmissionHelper.java b/ui/src/main/java/org/akraino/validation/ui/service/utils/SubmissionHelper.java
new file mode 100644 (file)
index 0000000..7a36b23
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ * 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.utils;
+
+import org.akraino.validation.ui.dao.SubmissionDAO;
+import org.akraino.validation.ui.entity.Submission;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+@Service
+@Transactional
+public class SubmissionHelper {
+
+    @Autowired
+    private SubmissionDAO submissionDAO;
+
+    public Submission saveSubmission(Submission submission) {
+        submissionDAO.saveOrUpdate(submission);
+        return submission;
+    }
+
+}
diff --git a/ui/src/main/java/org/akraino/validation/ui/service/utils/WithPriority.java b/ui/src/main/java/org/akraino/validation/ui/service/utils/WithPriority.java
new file mode 100644 (file)
index 0000000..25ea9f6
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ * 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.utils;
+
+public interface WithPriority extends Comparable<WithPriority> {
+    int priority();
+
+    @Override
+    default int compareTo(WithPriority withPriority) {
+        // Reverse comparison so higher priority comes first.
+        return Integer.compare(withPriority.priority(), priority());
+    }
+}
diff --git a/ui/src/main/resources/app.properties b/ui/src/main/resources/app.properties
new file mode 100644 (file)
index 0000000..76281ca
--- /dev/null
@@ -0,0 +1,21 @@
+# 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.
+
+#LDAP details for authentication & authorization
+apacheds.ldap.url = ldap://localhost:10389/dc=akraino,dc=org
+
+#DB connection properties
+postgres.db.url = jdbc:postgresql://localhost:6432/admin
+postgres.db.user.name = admin
+
diff --git a/ui/src/main/resources/hibernate.properties b/ui/src/main/resources/hibernate.properties
new file mode 100644 (file)
index 0000000..a66c68f
--- /dev/null
@@ -0,0 +1,21 @@
+# 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.
+
+hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect
+hibernate.show_sql = true
+hibernate.c3p0.min_size = 5
+hibernate.c3p0.max_size = 20
+hibernate.c3p0.acquire_increment = 2
+hibernate.c3p0.max_statements = 150
+hibernate.jdbc.use_streams_for_binary = true
\ No newline at end of file
diff --git a/ui/src/main/resources/log4j.properties b/ui/src/main/resources/log4j.properties
new file mode 100644 (file)
index 0000000..4484b3f
--- /dev/null
@@ -0,0 +1,34 @@
+# 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.
+
+# Direct log messages to a log file
+log4j.rootLogger=INFO, stdout, file
+log4j.logger.org.hibernate.SQL=TRACE, stdout
+
+# Redirect log messages to console
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.Threshold=WARN
+log4j.appender.stdout.Target=System.out
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
+
+# Redirect log messages to a log file, support file rolling.
+log4j.appender.file=org.apache.log4j.RollingFileAppender
+log4j.appender.stdout.Threshold=DEBUG
+#log4j.appender.file.File=C:\\Users\\ld261v\\Downloads\\ak1.log
+log4j.appender.file.File=/usr/local/tomcat/logs/akraino.log
+log4j.appender.file.MaxFileSize=5MB
+log4j.appender.file.MaxBackupIndex=10
+log4j.appender.file.layout=org.apache.log4j.PatternLayout
+log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
\ No newline at end of file
diff --git a/ui/src/main/webapp/.eslintrc b/ui/src/main/webapp/.eslintrc
new file mode 100644 (file)
index 0000000..53fe50e
--- /dev/null
@@ -0,0 +1,9 @@
+{
+  "globals": {
+    "angular": 1,
+    "console": 1,
+    "confirm":1,
+    "localStorage":1,
+    "window":1
+  }
+}
\ No newline at end of file
diff --git a/ui/src/main/webapp/WEB-INF/views/welcome.jsp b/ui/src/main/webapp/WEB-INF/views/welcome.jsp
new file mode 100755 (executable)
index 0000000..0f3d695
--- /dev/null
@@ -0,0 +1,28 @@
+<!--
+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.
+-->
+<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
+<!DOCTYPE html>
+<html>
+<head>
+       <title>Spring 4 MVC Hello World Example with Maven Eclipse</title>
+       <link rel='stylesheet' href='<c:url value="/resources/css/style.css" />' type='text/css' media='all' /> 
+</head>
+<body>
+       <h2>Hello World, Spring MVC</h2>
+
+       <p>Welcome, ${name}</p>
+</body>
+</html>
\ No newline at end of file
diff --git a/ui/src/main/webapp/WEB-INF/web.xml b/ui/src/main/webapp/WEB-INF/web.xml
new file mode 100755 (executable)
index 0000000..0ef6de8
--- /dev/null
@@ -0,0 +1,25 @@
+<!--
+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 web-app PUBLIC
+ "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+ "http://java.sun.com/dtd/web-app_2_3.dtd" >
+
+<web-app>
+  <display-name>Archetype Created Web Application</display-name>
+
+
+</web-app>
diff --git a/ui/src/main/webapp/index.html b/ui/src/main/webapp/index.html
new file mode 100755 (executable)
index 0000000..cb23409
--- /dev/null
@@ -0,0 +1,115 @@
+<!--
+<!--
+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>
+<html ng-app="BlueprintValidationUIManagement">
+
+<head>
+<title>AKRAINO Blueprint Validation UI</title>
+<meta charset="utf-8">
+<meta http-equiv="Pragma" content="no-cache">
+<meta http-equiv="Cache-Control"
+ content="no-store, no-cache, must-revalidate">
+<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+<meta name="viewport"
+ content="width=device-width, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
+<meta name="apple-mobile-web-app-capable" content="yes">
+<meta name="apple-mobile-web-app-status-bar-style" content="black">
+<link rel="stylesheet" href="./resources/css/style.css">
+
+<script
+ src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.1/angular.min.js"></script>
+<link rel="stylesheet" href="./resources/css/style.css">
+<link rel="stylesheet"
+ href="http://maxcdn.bootstrapcdn.com/bootswatch/3.2.0/sandstone/bootstrap.min.css">
+<link rel="stylesheet"
+ href="http://maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css">
+<link rel="stylesheet" href="./resources/css/ngDialog-theme-default.css">
+<link rel="stylesheet"
+ href="https://cdnjs.cloudflare.com/ajax/libs/ng-dialog/1.4.0/css/ngDialog.css">
+<link rel="stylesheet"
+ href="https://cdnjs.cloudflare.com/ajax/libs/ng-dialog/1.4.0/css/ngDialog-theme-plain.css">
+<script
+ src="https://cdnjs.cloudflare.com/ajax/libs/ng-dialog/1.4.0/js/ngDialog.min.js"></script>
+<script
+ src="https://cdnjs.cloudflare.com/ajax/libs/angular-base64/2.0.5/angular-base64.js"></script>
+<script
+ src="https://cdnjs.cloudflare.com/ajax/libs/angular-base64/2.0.5/angular-base64.min.js"></script>
+
+<!-- Insert custom controllers here -->
+<script type="text/javascript" src="./resources/js/App.Config.js"></script>
+<script type="text/javascript" src="./resources/js/App.js"></script>
+<script type="text/javascript" src="./resources/js/App.Services.js"></script>
+<script type="text/javascript" src="./resources/js/CommonController.js"></script>
+<script type="text/javascript"
+ src="./resources/js/AECNewSubmissionController.js"></script>
+<script type="text/javascript"
+ src="./resources/js/AECCommittedSubmissionsController.js"></script>
+<script type="text/javascript"
+ src="./resources/js/AECFindBySubmissionIdController.js"></script>
+
+<script
+ src="https://cdnjs.cloudflare.com/ajax/libs/bootbox.js/4.4.0/bootbox.min.js"></script>
+
+<script
+ src="https://cdnjs.cloudflare.com/ajax/libs/danialfarid-angular-file-upload/11.2.3/ng-file-upload-shim.min.js"></script>
+<script
+ src="https://cdnjs.cloudflare.com/ajax/libs/danialfarid-angular-file-upload/11.2.3/ng-file-upload.min.js"></script>
+
+<script
+ src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
+
+
+<script
+ src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script>
+
+<script type="text/javascript"></script>
+
+<script
+ src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-router/1.0.18/angular-ui-router.min.js"></script>
+<script src="https://cdn.jsdelivr.net/ngstorage/0.3.10/ngStorage.min.js"></script>
+<script src="http://code.angularjs.org/1.4.8/angular-resource.js"></script>
+<!--  <script src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.11.0.js"></script> -->
+<script data-require="ui-bootstrap@*" data-semver="0.13.3"
+ src="https://cdnjs.cloudflare.com/ajax/libs/angular-ui-bootstrap/0.13.3/ui-bootstrap.min.js"></script>
+<script
+ src="//angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.13.4.js"></script>
+
+<script
+ src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-animate.min.js"></script>
+<script
+ src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-aria.min.js"></script>
+<script
+ src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular-messages.min.js"></script>
+<script
+ src="https://ajax.googleapis.com/ajax/libs/angular_material/1.0.0/angular-material.min.js"></script>
+<link rel="stylesheet"
+ href="https://fonts.googleapis.com/icon?family=Material+Icons">
+<script type="text/javascript" src="http://d3js.org/d3.v3.min.js"></script>
+<script type="text/javascript"
+ src="https://cdn.plot.ly/plotly-latest.min.js"></script>
+<script src="reusable_chart.js"></script>
+
+</head>
+
+
+<body ng-controller="Login">
+
+ <div ui-view=""></div>
+</body>
+
+</html>
\ No newline at end of file
diff --git a/ui/src/main/webapp/resources/css/ngDialog-theme-default.css b/ui/src/main/webapp/resources/css/ngDialog-theme-default.css
new file mode 100644 (file)
index 0000000..5845704
--- /dev/null
@@ -0,0 +1,211 @@
+/* 
+ * 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.
+ */
+@-webkit-keyframes ngdialog-flyin {
+  0% {
+    opacity: 0;
+    -webkit-transform: translateY(-40px);
+    transform: translateY(-40px);
+  }
+
+  100% {
+    opacity: 1;
+    -webkit-transform: translateY(0);
+    transform: translateY(0);
+  }
+}
+
+@keyframes ngdialog-flyin {
+  0% {
+    opacity: 0;
+    -webkit-transform: translateY(-40px);
+    -ms-transform: translateY(-40px);
+    transform: translateY(-40px);
+  }
+
+  100% {
+    opacity: 1;
+    -webkit-transform: translateY(0);
+    -ms-transform: translateY(0);
+    transform: translateY(0);
+  }
+}
+
+@-webkit-keyframes ngdialog-flyout {
+  0% {
+    opacity: 1;
+    -webkit-transform: translateY(0);
+    transform: translateY(0);
+  }
+
+  100% {
+    opacity: 0;
+    -webkit-transform: translateY(-40px);
+    transform: translateY(-40px);
+  }
+}
+
+@keyframes ngdialog-flyout {
+  0% {
+    opacity: 1;
+    -webkit-transform: translateY(0);
+    -ms-transform: translateY(0);
+    transform: translateY(0);
+  }
+
+  100% {
+    opacity: 0;
+    -webkit-transform: translateY(-40px);
+    -ms-transform: translateY(-40px);
+    transform: translateY(-40px);
+  }
+}
+
+.ngdialog.ngdialog-theme-default {
+  padding-bottom: 160px;
+  padding-top: 160px;
+}
+
+.ngdialog.ngdialog-theme-default.ngdialog-closing .ngdialog-content {
+  -webkit-animation: ngdialog-flyout .5s;
+  animation: ngdialog-flyout .5s;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-content {
+  -webkit-animation: ngdialog-flyin .5s;
+  animation: ngdialog-flyin .5s;
+  background: #F9F4E5;
+  border-radius: 5px;
+  color: #444;
+  font-family: 'Helvetica',sans-serif;
+  font-size: 1.1em;
+  line-height: 1.5em;
+  margin: 0 auto;
+  max-width: 100%;
+  padding: 1em;
+  position: relative;
+  width: 450px;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-close {
+  border-radius: 5px;
+  cursor: pointer;
+  position: absolute;
+  right: 0;
+  top: 0;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-close:before {
+  background: transparent;
+  border-radius: 3px;
+  color: #bbb;
+  content: '\00D7';
+  font-size: 26px;
+  font-weight: 400;
+  height: 30px;
+  line-height: 26px;
+  position: absolute;
+  right: 3px;
+  text-align: center;
+  top: 3px;
+  width: 30px;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-close:hover:before,
+.ngdialog.ngdialog-theme-default .ngdialog-close:active:before {
+  color: #777;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-message {
+  margin-bottom: .5em;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-input {
+  margin-bottom: 1em;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-input textarea,
+.ngdialog.ngdialog-theme-default .ngdialog-input input[type="text"],
+.ngdialog.ngdialog-theme-default .ngdialog-input input[type="password"],
+.ngdialog.ngdialog-theme-default .ngdialog-input input[type="email"],
+.ngdialog.ngdialog-theme-default .ngdialog-input input[type="url"] {
+  background: #fff;
+  border: 0;
+  border-radius: 3px;
+  font-family: inherit;
+  font-size: inherit;
+  font-weight: inherit;
+  margin: 0 0 .25em;
+  min-height: 2.5em;
+  padding: .25em .67em;
+  width: 100%;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-input textarea:focus,
+.ngdialog.ngdialog-theme-default .ngdialog-input input[type="text"]:focus,
+.ngdialog.ngdialog-theme-default .ngdialog-input input[type="password"]:focus,
+.ngdialog.ngdialog-theme-default .ngdialog-input input[type="email"]:focus,
+.ngdialog.ngdialog-theme-default .ngdialog-input input[type="url"]:focus {
+  -webkit-box-shadow: inset 0 0 0 2px #8dbdf1;
+  box-shadow: inset 0 0 0 2px #8dbdf1;
+  outline: none;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-buttons {
+  *zoom: 1;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-buttons:after {
+  content: '';
+  display: table;
+  clear: both;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-button {
+  border: 0;
+  border-radius: 3px;
+  cursor: pointer;
+  float: right;
+  font-family: inherit;
+  font-size: .8em;
+  letter-spacing: .1em;
+  line-height: 1em;
+  margin: 0 0 0 .5em;
+  padding: .75em 2em;
+  text-transform: uppercase;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-button:focus {
+  -webkit-animation: ngdialog-pulse 1.1s infinite;
+  animation: ngdialog-pulse 1.1s infinite;
+  outline: none;
+}
+
+@media (max-width: 568px) {
+  .ngdialog.ngdialog-theme-default .ngdialog-button:focus {
+    -webkit-animation: none;
+    animation: none;
+  }
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-button.ngdialog-button-primary {
+  background: #3288e6;
+  color: #fff;
+}
+
+.ngdialog.ngdialog-theme-default .ngdialog-button.ngdialog-button-secondary {
+  background: #e0e0e0;
+  color: #777;
+}
\ No newline at end of file
diff --git a/ui/src/main/webapp/resources/css/style.css b/ui/src/main/webapp/resources/css/style.css
new file mode 100755 (executable)
index 0000000..7680da0
--- /dev/null
@@ -0,0 +1,611 @@
+/* 
+ * 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.
+ */
+
+.img-arredondadaSide {
+     border-radius: 100%;
+    w overflow: hidden;
+     height: 100px;
+     width:100px;
+     background:#6495ED;
+     margin-top:10px;
+     margin-left: 5px;
+}
+ .img-arredondadaChat {
+     border-radius: 100%;
+     overflow: hidden;
+     height: 50px;
+     width:50px;
+     background: black;
+}
+ .tema{
+     color:red;
+}
+ .chat-container {
+     width: 400px;
+     height: 100%;
+     margin: 0 auto;
+}
+ .corStatusFinalizado{
+     color:green;
+}
+ .corNormal{
+     color:#3366FF;
+}
+ .corStatusNaoFinalizado{
+     color:red;
+}
+ .alinharCentro{
+     text-align: center;
+}
+ .user-panel {
+     padding: 10px;
+}
+ .user-panel:before, .user-panel:after {
+     display: table;
+     content: " ";
+}
+ .user-panel:after {
+     clear: both;
+}
+ .user-panel > .image > img {
+     width: 45px;
+     height: 45px;
+}
+ .user-panel > .info {
+     font-weight: 600;
+     padding: 5px 5px 5px 15px;
+     font-size: 14px;
+     line-height: 1;
+}
+ .user-panel > .info > p {
+     margin-bottom: 9px;
+}
+ .user-panel > .info > a {
+     text-decoration: none;
+     padding-right: 5px;
+     margin-top: 3px;
+     font-size: 11px;
+     font-weight: normal;
+}
+ .user-panel > .info > a > .fa, .user-panel > .info > a > .ion, .user-panel > .info > a > .glyphicon {
+     margin-right: 3px;
+}
+ #wrapper {
+     padding-left: 0;
+     -webkit-transition: all 0.5s ease;
+     -moz-transition: all 0.5s ease;
+     -o-transition: all 0.5s ease;
+     transition: all 0.5s ease;
+     margin-top: -20px;
+}
+ #wrapper.toggled {
+     padding-left: 250px;
+}
+ #sidebar-wrapper {
+     z-index: 1000;
+     position: absolute;
+     left: 250px;
+     width: 0;
+      height:100vh;
+     margin-left: -250px;
+     overflow-y: auto;
+     background: #cccccc;
+     -webkit-transition: all 0.5s ease;
+     -moz-transition: all 0.5s ease;
+     -o-transition: all 0.5s ease;
+     transition: all 0.5s ease;
+}
+ #wrapper.toggled #sidebar-wrapper {
+     width: 250px;
+}
+ #page-content-wrapper {
+     width: 100%;
+}
+ #wrapper.toggled #page-content-wrapper {
+     position: absolute;
+     margin-right: -250px;
+}
+/* Sidebar Styles */
+ .sidebar-nav {
+     position: absolute;
+     top: 0;
+     width: 250px;
+     margin: 0;
+     padding: 0;
+     list-style: none;
+}
+ .sidebar-nav li {
+     text-indent: 20px;
+     line-height: 40px;
+     margin-left: -25px;
+      color:   #000000;
+}
+ .logo{
+     color: rgb(105, 183, 105);
+     font-size: 36px;
+     font-weight: 700;
+     line-height: 39.6px;
+     margin-left:20px;
+     margin-top:10px 
+}
+ .fa {
+     display: inline-block;
+     font-family: FontAwesome;
+     font-style: normal;
+     font-weight: normal;
+     line-height: 1;
+     font-size-adjust: none;
+     font-stretch: normal;
+     font-feature-settings: normal;
+     font-language-override: normal;
+     font-kerning: auto;
+     font-synthesis: weight style;
+     font-variant: normal;
+     font-size: inherit;
+     text-rendering: auto;
+     padding-right: 10px;
+}
+ .containerLogin{
+     padding-right: 15px;
+     padding-left: 15px;
+     margin-right: auto;
+     margin-top: 100px;
+     margin-left: auto;
+     width: 30%;
+}
+ .sidebar-nav li a {
+     display: block;
+     text-decoration: none;
+     color:    #000000;
+}
+
+ .sidebar-nav li a:hover {
+     text-decoration: none;
+     color: #fff;
+     background: rgba(255,255,255,0.2);
+}
+
+ .sidebar-nav li a.example{
+     text-decoration: none;
+     color: #fff;
+     background: #999999;
+}
+sidebar-nav > .sidebar-brand {
+     height: 65px;
+     font-size: 18px;
+     line-height: 60px;
+}
+ .sidebar-nav > .sidebar-brand a {
+     color: #999999;
+}
+ .sidebar-nav > .sidebar-brand a:hover {
+     color: #fff;
+     background: none;
+}
+ .sidebar-nav > .sidebar-brand a:active {
+     color: #fff;
+     background: none;
+}
+ @media only screen and (max-height: 650px) and (min-width:768px){
+     #sidebar-wrapper {
+         width: 250px;
+         position: absolute;
+         height:200%;
+    }
+}
+ @media only screen and (max-height: 450px) and (min-width:768px){
+     #sidebar-wrapper {
+         width: 250px;
+         position: absolute;
+         height:160%;
+    }
+}
+ @media only screen and (max-height: 1200px) and (min-width:1366px){
+     #sidebar-wrapper {
+         width: 250px;
+         position: absolute;
+         height:100%;
+    }
+}
+ @media(min-width:768px) {
+     #wrapper {
+         padding-left: 120px;
+    }
+     #wrapper.toggled {
+         padding-left: 0;
+    }
+     #sidebar-wrapper {
+         width: 250px;
+    }
+     #wrapper.toggled #sidebar-wrapper {
+         width: 0;
+    }
+     #page-content-wrapper {
+         position: relative;
+    }
+     #wrapper.toggled #page-content-wrapper {
+         position: relative;
+         margin-right: 0;
+    }
+}
+
+ * {
+    box-sizing: border-box;
+}
+ body {
+     margin: 0;
+     padding:0;
+     
+     font-family: Arial;
+    height:calc(100% - 70px);
+    height:-moz-calc(100% - 70px);
+    height:-webkit-calc(100% - 70px);
+    
+}
+html{margin:0;padding:0;}
+
+ .header {
+     overflow: hidden;
+     background-color: #000000;
+     padding: 8px 10px;
+}
+ .header a {
+     float: left;
+     color: white;
+     text-align: center;
+     padding: 12px;
+     text-decoration: none;
+     font-size: 18px;
+     line-height: 25px;
+     border-radius: 4px;
+}
+ .header a.logo {
+     font-size: 25px;
+     font-weight: bold;
+}
+ .header-right {
+     float: right;
+}
+ .akrbutton {
+     background-color: #4d4d4d;
+     border: none;
+     color: white;
+     padding: 8px 15px;
+     text-align: center;
+     text-decoration: none;
+     display: inline-block;
+     font-size: 12px;
+     margin: 3% 2%;
+     cursor: pointer;
+     border-radius: 5px;
+}
+ .refreshbutton {
+     background-color: #4d4d4d;
+     border: none;
+     color: white;
+     padding: 7px 14px;
+     text-align: center;
+     text-decoration: none;
+     display: inline-block;
+     cursor: pointer;
+     border-radius: 5px;
+      
+}
+ .akrtheader {
+     padding-top: 12px;
+     padding-bottom: 12px;
+     text-align: left;
+     background-color: #4CAF50 
+}
+ table, td {
+     border: 1px solid #ddd;
+}
+ table {
+     border-collapse: collapse;
+     width: 100%;}
+
+ .siteStatusTable th {
+     padding: 5px;
+     text-align: left;
+     background-color: #cccccc;
+     border: 1px solid #ddd;
+}
+ .siteStatusTable td {
+     padding-top: 5px;
+     padding-bottom:5px;
+}
+.nodeTable th {
+     padding: 10px;
+     text-align: left;
+     background-color: #cccccc;
+     border: 0px solid #ddd;
+}
+ .nodeTable td {
+     padding-top: 5px;
+     padding-bottom:5px;
+}
+ .siteaddOnsTable th {
+     padding: 10px;
+     text-align: left;
+     background-color: #cccccc;
+     border: 1px solid #ddd;
+}
+ .siteaddOnsTable td {
+     padding-top: 5px;
+     padding-bottom:5px;
+}
+
+
+ .sitetempestsTable th {
+     padding: 10px;
+     text-align: left;
+     background-color: #cccccc;
+     border: 1px solid #ddd;
+}
+ .sitetempestsTable td {
+     padding-top: 5px;
+     padding-bottom:5px;
+}
+
+
+.shardwareTable th {
+     padding: 5px;
+     text-align: left;
+     background-color: #cccccc;
+     border: 1px solid #ddd;
+}
+ .shardwareTable td {
+     padding-top: 3px;
+     padding-bottom:3px;
+}
+.rackTable th {
+     padding: 10px;
+     text-align: left;
+     background-color: #cccccc;
+     border: 1px solid #ddd;
+}
+ .rackTable td {
+     padding-top: 5px;
+     padding-bottom:5px;
+}
+
+.sitebuildTable th {
+     padding: 10px;
+     text-align: left;
+     background-color: #cccccc;
+     border: 1px solid #ddd;
+}
+ .sitebuildTable td {
+     padding-top: 5px;
+     padding-bottom:5px;
+}
+
+ .softwareTable th {
+     padding: 10px;
+     text-align: left;
+     background-color: #cccccc;
+     border: 1px solid #ddd;
+}
+ .softwareTable td {
+     padding-top: 5px;
+     padding-bottom:5px;
+}
+.popUpTable th {
+     padding: 10px;
+     text-align: left;
+     background-color: #cccccc;
+     border: 1px solid #ddd;
+}
+ .popUpTable td {
+     padding-top: 5px;
+     padding-bottom:5px;
+}
+/*.pagination {
+     display: inline-block;
+     float:right;
+}
+ .pagination li {
+     list-style-type:none;
+     color: white;
+     float: left;
+     padding: 8px 16px;
+     text-decoration: none;
+     transition: background-color .3s;
+     border: 1px solid #ddd;
+}
+ .pagination li.active {
+     background-color: #DCDCDC;
+     color: white;
+     border: 1px solid #ddd;
+}*/
+ button:disabled {
+     background: #dddddd;
+}
+ .select-style {
+     border: 1px solid #ccc;
+     width: 240px;
+     height: 40px;
+     border-radius: 3px;
+     overflow: hidden;
+     background-position: right;
+}
+ .select-style select {
+     
+     width: 100%;
+     border: 0px;
+     box-shadow: none;
+     background:none;
+     background-image: none;
+     -webkit-appearance: none;
+     outline: 0px;
+     
+}
+.selectStyle select option{
+       height:30px;
+       padding-top:5px;
+}
+@-moz-document url-prefix() {
+  select.example {
+    padding-right: 25px;
+
+     height:40px;
+      
+    background-image: url("data:image/svg+xml,\
+      <svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='14px'\
+           height='14px' viewBox='0 0 1200 1000' fill='rgb(51,51,51)'>\
+        <path d='M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z'/>\
+      </svg>");
+    background-repeat: no-repeat;
+    background-position: calc(100% - 7px) 50%;
+    -moz-appearance: none;
+    appearance: none;
+   
+  }
+}
+@-moz-document url-prefix() {
+  select.exampleTable {
+    
+     
+     height:25px;
+     
+    background-image: url("data:image/svg+xml,\
+      <svg version='1.1' xmlns='http://www.w3.org/2000/svg' width='14px'\
+           height='14px' viewBox='0 0 1200 1000' fill='rgb(51,51,51)'>\
+        <path d='M1100 411l-198 -199l-353 353l-353 -353l-197 199l551 551z'/>\
+      </svg>");
+    background-repeat: no-repeat;
+    background-position: calc(100% - 7px) 50%;
+    -moz-appearance: none;
+    appearance: none;
+   
+  }
+}
+ .select-style select:focus {
+     outline: none;
+}
+ .child_div_1{
+     float:left;
+     margin-right:50px;
+}
+ .child_div_2{
+     float:right;
+     margin-right:50%;
+}
+ .ngdialog {
+     margin-top:-100px;
+     padding-top:10px;
+     overflow-y: auto;
+}
+ .addOnForm input[type=text], select, textarea {
+     width: 40%;
+     padding: 3px;
+     border: 0.5px solid #ccc;
+     border-radius: 4px;
+     box-sizing: border-box;
+     margin-top: 3px;
+     margin-bottom: 3px;
+     resize: vertical;
+}
+ .tempestclassForm input[type=text], select, textarea {
+     width: 40%;
+     padding: 3px;
+     border: 0.5px solid #ccc;
+     border-radius: 4px;
+     box-sizing: border-box;
+     margin-top: 3px;
+     margin-bottom: 3px;
+     resize: vertical;
+}
+.hardwareForm input[type=text], select, textarea {
+     width: 40%;
+     padding: 3px;
+     border: 0.5px solid #ccc;
+     border-radius: 4px;
+     box-sizing: border-box;
+     margin-top: 3px;
+     margin-bottom: 3px;
+     resize: vertical;
+}
+.podForm input[type=text], select, textarea {
+     width: 40%;
+     padding: 3px;
+     border: 0.5px solid #ccc;
+     border-radius: 4px;
+     box-sizing: border-box;
+     margin-top: 3px;
+     margin-bottom: 3px;
+     resize: vertical;
+}
+.uploadForm input[type=text], select, textarea {
+     width: 40%;
+     padding: 3px;
+     border: 0.5px solid #ccc;
+     border-radius: 4px;
+     box-sizing: border-box;
+     margin-top: 3px;
+     margin-bottom: 3px;
+     resize: vertical;
+}
+.vnfForm input[type=text], select, textarea {
+     width: 40%;
+     padding: 3px;
+     border: 0.5px solid #ccc;
+     border-radius: 4px;
+     box-sizing: border-box;
+     margin-top: 3px;
+     margin-bottom: 3px;
+     resize: vertical;
+}
+.siteForm input[type=text], select, textarea {
+     width: 40%;
+     padding: 3px;
+     border: 0.5px solid #ccc;
+     border-radius: 4px;
+     box-sizing: border-box;
+     margin-top: 3px;
+     margin-bottom: 3px;
+     resize: vertical;
+}
+.siteForm li input[type=text], select, textarea {
+     width: 40%;
+     padding: 3px;
+     border: 0.5px solid #ccc;
+     border-radius: 4px;
+     box-sizing: border-box;
+     margin-top: 3px;
+     margin-bottom: 3px;
+     resize: vertical;
+}
+ label {
+     font-weight: normal !important;
+}
+.ngdialog-custom{
+       background: #e6e6e6;
+}
+#footerlogo{
+       position:absolute;
+       display:inline-block;
+       bottom:0;
+        width: 250px;
+}
+.borderFrame{
+       margin-top:2px;
+       border:2px solid #cdcdcd;
+       /*border-radius: 0.1px;
+       /*-moz-border-radius: 0.1px;
+       -webkit-border-radius:0.1px;*/
+}
diff --git a/ui/src/main/webapp/resources/images/logo_akraino_edge_stack.png b/ui/src/main/webapp/resources/images/logo_akraino_edge_stack.png
new file mode 100755 (executable)
index 0000000..c81bb53
Binary files /dev/null and b/ui/src/main/webapp/resources/images/logo_akraino_edge_stack.png differ
diff --git a/ui/src/main/webapp/resources/js/AECCommittedSubmissionsController.js b/ui/src/main/webapp/resources/js/AECCommittedSubmissionsController.js
new file mode 100644 (file)
index 0000000..9690793
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * 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 AECBlueprintValidationUIApp = angular
+        .module('BlueprintValidationUIManagement');
+
+AECBlueprintValidationUIApp.controller('AECCommittedSubmissionsController',
+        function($scope, restAPISvc, $interval, refreshPeriod) {
+
+            $scope.submissionIdList = [];
+
+            restAPISvc.getRestAPI("/api/submission/", function(data) {
+                $scope.submissions = data;
+            });
+
+            $scope.refreshCommittedSubmissions = function() {
+                restAPISvc.getRestAPI("/api/submission/", function(data) {
+                    $scope.submissions = data;
+                });
+            }
+
+            $scope.modifySubmissionIdList = function(id) {
+                if ($scope.submissionIdList.indexOf(id) === -1) {
+                    $scope.submissionIdList.push(id);
+                } else {
+                    $scope.submissionIdList.splice($scope.submissionIdList
+                            .indexOf(id), 1);
+                }
+            }
+
+            $scope.deleteSubmissions = function() {
+                var confirmation = confirm("Are you sure?");
+                if (confirmation == true) {
+                    angular.forEach($scope.submissionIdList, function(id) {
+                        var submission = {
+                            "submissionId" : id
+                        };
+                        restAPISvc
+                                .deleteRestAPI("/api/submission/", submission);
+                    });
+                }
+            }
+
+            $interval(function() {
+                $scope.refreshCommittedSubmissions();
+            }, refreshPeriod);
+
+        });
diff --git a/ui/src/main/webapp/resources/js/AECFindBySubmissionIdController.js b/ui/src/main/webapp/resources/js/AECFindBySubmissionIdController.js
new file mode 100644 (file)
index 0000000..2d1a99c
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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 AECBlueprintValidationUIApp = angular
+        .module('BlueprintValidationUIManagement');
+
+AECBlueprintValidationUIApp
+        .controller(
+                'AECFindBySubmissionIdController',
+                function($scope, restAPISvc) {
+
+                    initialize();
+
+                    function initialize() {
+                        $scope.results = [];
+                        restAPISvc
+                                .getRestAPI(
+                                        "/api/submission/",
+                                        function(data) {
+                                            $scope.submissions = data;
+                                            $scope.submissionsForDisplay = [];
+                                            angular
+                                                    .forEach(
+                                                            $scope.submissions,
+                                                            function(
+                                                                    submissionData) {
+                                                                var temp = "id: "
+                                                                        + submissionData.submissionId
+                                                                        + " blueprint: "
+                                                                        + submissionData.blueprintInstance.blueprint.blueprintName
+                                                                        + " version: "
+                                                                        + submissionData.blueprintInstance.version
+                                                                        + " layer: "
+                                                                        + submissionData.blueprintInstance.layer
+                                                                        + " lab: "
+                                                                        + submissionData.blueprintInstance.timeslot.lab
+                                                                        + " Start date and time: "
+                                                                        + submissionData.blueprintInstance.timeslot.startDateTime
+                                                                        + " duration: "
+                                                                        + submissionData.blueprintInstance.timeslot.duration;
+                                                                $scope.submissionsForDisplay
+                                                                        .push(temp);
+                                                            });
+                                        });
+                    }
+                    $scope.selectedSubmissionChange = function(
+                            selectedSubmission) {
+                        $scope.results = [];
+                        var id = selectedSubmission.substring(
+                                selectedSubmission.indexOf("id:") + 4,
+                                selectedSubmission.indexOf("blueprint") - 1);
+                        restAPISvc.getRestAPI(
+                                "/api/results/findBySubmissionId/" + id,
+                                function(data) {
+                                    $scope.results = data;
+                                });
+                    }
+
+                });
\ No newline at end of file
diff --git a/ui/src/main/webapp/resources/js/AECNewSubmissionController.js b/ui/src/main/webapp/resources/js/AECNewSubmissionController.js
new file mode 100644 (file)
index 0000000..1cfafc4
--- /dev/null
@@ -0,0 +1,151 @@
+/*
+ * 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 AECBlueprintValidationUIApp = angular
+        .module('BlueprintValidationUIManagement');
+
+AECBlueprintValidationUIApp
+        .controller(
+                'AECNewSubmissionController',
+                function($scope, appContext, restAPISvc) {
+
+                    initialize();
+
+                    function initialize() {
+                        restAPISvc
+                                .getRestAPI(
+                                        "/api/blueprintInstance/",
+                                        function(data) {
+                                            $scope.blueprintInstances = data;
+                                            $scope.blueprintNames = [];
+                                            angular
+                                                    .forEach(
+                                                            $scope.blueprintInstances,
+                                                            function(
+                                                                    blueprintInstance) {
+                                                                if ($scope.blueprintNames
+                                                                        .indexOf(blueprintInstance["blueprint"]["blueprintName"]) === -1) {
+                                                                    $scope.blueprintNames
+                                                                            .push(blueprintInstance["blueprint"]["blueprintName"]);
+                                                                }
+                                                            });
+                                        });
+                    }
+                    $scope.selectedBluePrintNameChange = function() {
+                        $scope.blueprintVersions = [];
+                        $scope.blueprintLayers = [];
+                        $scope.declerativeTimeslots = [];
+                        angular
+                                .forEach(
+                                        $scope.blueprintInstances,
+                                        function(blueprintInstance) {
+                                            if ($scope.selectedBlueprintName === blueprintInstance["blueprint"]["blueprintName"]) {
+                                                if ($scope.blueprintVersions
+                                                        .indexOf(blueprintInstance["version"]) === -1) {
+                                                    $scope.blueprintVersions
+                                                            .push(blueprintInstance["version"]);
+                                                }
+                                            }
+                                        });
+                    }
+                    $scope.selectedBluePrintVersionChange = function() {
+                        $scope.blueprintLayers = [];
+                        $scope.declerativeTimeslots = [];
+                        angular
+                                .forEach(
+                                        $scope.blueprintInstances,
+                                        function(blueprintInstance) {
+                                            if ($scope.selectedBlueprintName === blueprintInstance["blueprint"]["blueprintName"]) {
+                                                if ($scope.selectedBlueprintVersion === blueprintInstance["version"]) {
+                                                    if ($scope.blueprintLayers
+                                                            .indexOf(blueprintInstance["layer"]) === -1) {
+                                                        $scope.blueprintLayers
+                                                                .push(blueprintInstance["layer"]);
+                                                    }
+                                                }
+                                            }
+                                        });
+                    }
+                    $scope.selectedBluePrintLayerChange = function() {
+                        $scope.declerativeTimeslots = [];
+                        angular
+                                .forEach(
+                                        $scope.blueprintInstances,
+                                        function(blueprintInstance) {
+                                            if ($scope.selectedBlueprintName === blueprintInstance["blueprint"]["blueprintName"]) {
+                                                if ($scope.selectedBlueprintVersion === blueprintInstance["version"]) {
+                                                    if ($scope.selectedBlueprintLayer === blueprintInstance["layer"]) {
+                                                        var temp = "id: "
+                                                                + blueprintInstance["timeslot"].timeslotId
+                                                                + " Start date and time: "
+                                                                + blueprintInstance["timeslot"].startDateTime
+                                                                + " duration(in sec) :"
+                                                                + blueprintInstance["timeslot"].duration
+                                                                + " lab :"
+                                                                + blueprintInstance["timeslot"].lab;
+                                                        if ($scope.declerativeTimeslots
+                                                                .indexOf(temp) === -1) {
+                                                            $scope.declerativeTimeslots
+                                                                    .push(temp);
+                                                        }
+                                                    }
+                                                }
+                                            }
+                                        });
+                    }
+                    $scope.submit = function() {
+                        var finalBlueprint;
+                        angular
+                                .forEach(
+                                        $scope.blueprintInstances,
+                                        function(blueprintInstance) {
+                                            if (blueprintInstance["blueprint"]["blueprintName"] === $scope.selectedBlueprintName) {
+                                                if (blueprintInstance["version"] === $scope.selectedBlueprintVersion) {
+                                                    if (blueprintInstance["layer"] === $scope.selectedBlueprintLayer) {
+                                                        var selectedDeclerativeTimeslotId = $scope.selectedDeclerativeTimeslot
+                                                                .substring(
+                                                                        $scope.selectedDeclerativeTimeslot
+                                                                                .indexOf("id:") + 4,
+                                                                        $scope.selectedDeclerativeTimeslot
+                                                                                .indexOf("Start date and time:") - 1);
+                                                        if (selectedDeclerativeTimeslotId
+                                                                .toString()
+                                                                .trim() === blueprintInstance["timeslot"]["timeslotId"]
+                                                                .toString()
+                                                                .trim()) {
+                                                            finalBlueprint = blueprintInstance;
+                                                        }
+                                                    }
+                                                }
+                                            }
+                                        });
+                        var submission = {
+                            "blueprintInstance" : finalBlueprint
+                        };
+                        restAPISvc
+                                .postRestAPI(
+                                        "/api/submission/",
+                                        submission,
+                                        function(data) {
+                                            if (data !== undefined) {
+                                                confirm("Submission committed successfully");
+                                            } else {
+                                                confirm("Error when committing the submission");
+                                            }
+                                        });
+                    }
+
+                });
diff --git a/ui/src/main/webapp/resources/js/App.Config.js b/ui/src/main/webapp/resources/js/App.Config.js
new file mode 100644 (file)
index 0000000..8fb450a
--- /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 config_module = angular.module('App.config', []);
+config_module.constant('appContext', '/AECBlueprintValidationUI');
+config_module.constant('refreshPeriod', '5000'); // in msecs
diff --git a/ui/src/main/webapp/resources/js/App.Services.js b/ui/src/main/webapp/resources/js/App.Services.js
new file mode 100644 (file)
index 0000000..f0887ad
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+ * 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 AECBlueprintValidationUIApp = angular
+        .module('BlueprintValidationUIManagement');
+
+AECBlueprintValidationUIApp.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/resources/js/App.js b/ui/src/main/webapp/resources/js/App.js
new file mode 100755 (executable)
index 0000000..1bc514c
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ * 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 AECBlueprintValidationUIApp = angular.module('BlueprintValidationUIManagement', ['ngDialog', 'ui.router', 'base64','App.config','ngStorage','ui.bootstrap', 'ngResource','ngFileUpload','ngMaterial']);
+
+AECBlueprintValidationUIApp.config(function($stateProvider, $urlRouterProvider) {
+    $urlRouterProvider.otherwise('/login')
+    $stateProvider
+        .state('common', {
+            templateUrl: 'views/indexMain.html',
+            abstract: true
+        })
+        .state('login', {
+            url: "/login",
+            controller: 'Login',
+            templateUrl: 'views/login.html'
+        })
+        .state('newSubmission', {
+            url: "/newSubmission",
+            parent: "common",
+            views: {
+                "main": {
+                    controller: 'AECNewSubmissionController',
+                    templateUrl: 'views/newSubmission.html'
+                }
+            }
+        })
+        .state('committedSubmissions', {
+            url: "/committedSubmissions",
+            parent: "common",
+            views: {
+                "main": {
+                    controller: 'AECCommittedSubmissionsController',
+                    templateUrl: 'views/committedSubmissions.html'
+                }
+            }
+        })
+        .state('findBySubmissionId', {
+            url: "/findBySubmissionId",
+            parent: "common",
+            views: {
+                "main": {
+                    controller: 'AECFindBySubmissionIdController',
+                    templateUrl: 'views/findBySubmissionId.html'
+                }
+            }
+        })
+});
+
+AECBlueprintValidationUIApp.controller('Login',function($scope, $http, $filter, filterFilter, $state, $base64,$rootScope,$controller,appContext) {
+    $rootScope.tokenId ="";
+    $scope.usernameVal = '';
+    $scope.passwordVal = '';
+    $rootScope.message = "Please enter credentials";
+    $scope.$state = $state;
+
+    var baseURL = window.location.protocol + '//' + window.location.host;
+    /* eslint-disable no-console */
+    console.log('Base URL for current frame is: ' + baseURL);
+    /* eslint-enable no-console */
+    $scope.goLogin = function() {
+        var arr = $scope.passwordVal;
+        if ($scope.usernameVal == '' && $scope.passwordVal == '') {
+            $scope.userMessage = 'Please enter a username.';
+            $scope.passwordMessage = 'Please enter a password.';
+        } else if ($scope.usernameVal == '') {
+            $scope.userMessage = 'Please enter a username.';
+            $scope.passwordMessage = '';
+        } else if ($scope.passwordVal == '') {
+            $scope.passwordMessage = 'Please enter a password.';
+            $scope.userMessage = '';
+        } else if (arr.length < 6) {
+            $scope.passwordMessage = 'Please enter a valid password.';
+            $scope.userMessage = '';
+        }
+       else {
+            $scope.passwordMessage = '';
+            $scope.userMessage ='';
+            // var userPwd = $scope.usernameVal + ":" + $scope.passwordVal;
+            // var auth = $base64.encode(userPwd);
+            /*
+             * $http({ method: 'POST', url: appContext+'/login', //url:
+             * 'http://'+hostUrl+'/AECPortalMgmt/login', headers: {
+             * 'Authorization': "Basic " + auth, 'Content-Type':
+             * "application/json", 'Accept': "application/json" }, data: { } }).
+             * then(function(response) { if (response.data.statusCode == 200) {
+             * $rootScope.tokenId = response.data.tokenId;
+             * localStorage.setItem("tokenId",response.data.tokenId);
+             * $state.transitionTo('sites'); } else if (response.data.statusCode ==
+             * 401){ $scope.passwordVal= null; $scope.passwordMessage = 'Invalid
+             * Credentials, please try again...';
+             *
+             * localStorage.removeItem("tokenId"); } }, function(error) { if
+             * (error.status == 401) { $scope.passwordMessage = 'Invalid
+             * Credentials, please try again...'; $scope.passwordVal ="";
+             * localStorage.removeItem("tokenId"); } else if (error.status ==
+             * 400) { $scope.passwordMessage = 'Session Invalid, please login
+             * again...'; $scope.passwordVal ="";
+             * localStorage.removeItem("tokenId"); } else if (error.status ==
+             * 307) { $scope.passwordMessage = 'Session expired,Please try
+             * again...'; $scope.passwordVal ="";
+             * localStorage.removeItem("tokenId"); } });
+             */
+            $state.transitionTo('committedSubmissions');
+        }
+    }
+    $scope.goLogout = function() {
+        $http({
+            method: 'POST',
+            url: appContext+'/logout',
+            headers: {
+                'Content-Type': "application/json",
+                'Accept': "application/json",
+                'tokenId' : $rootScope.tokenId
+            },
+        data:{
+        }
+            /*
+             * data: { 'username': $scope.usernameVal, 'passowrd':
+             * $scope.passwordVal }
+             */
+        }).then(function(response) {
+            if (response.data.statusCode == 200) {
+                $rootScope.tokenId ="";
+                localStorage.removeItem("tokenId");
+                $state.transitionTo('login');
+                $rootScope.message = 'User logged out, please login again...';
+            }
+        }, function(response) {
+            $scope.message = 'Unknown error,Try again later' + response.status;
+        });
+    }
+});
+
diff --git a/ui/src/main/webapp/resources/js/CommonController.js b/ui/src/main/webapp/resources/js/CommonController.js
new file mode 100644 (file)
index 0000000..dda7718
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * 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 AECBlueprintValidationUIApp = angular
+        .module('BlueprintValidationUIManagement');
+
+AECBlueprintValidationUIApp.controller('CommonController', function($scope,
+        $http, $sce, ngDialog, $filter, $rootScope, $state, $templateCache) {
+    $scope.errorHandle = function(error) {
+        if (error.status == 400) {
+            localStorage.removeItem("tokenId");
+            $state.transitionTo('login');
+            localStorage.removeItem("tokenId");
+            $rootScope.message = 'Session Invalid, please login again...';
+        } else if (error.status == 401) {
+            localStorage.removeItem("tokenId");
+            $state.transitionTo('login');
+            $rootScope.message = 'Invalid Credentials, please try again...';
+        } else if (error.status == 307) {
+            localStorage.removeItem("tokenId");
+            $state.transitionTo('login');
+            $rootScope.message = 'Session expired,Please try again...';
+        }
+    }
+
+    $scope.$on('onBeforeUnload', function(e, confirmation) {
+        var e2 = e || window.event;
+        if (e2) {
+            confirmation.message = "All data willl be lost.";
+            e2.preventDefault();
+        }
+    });
+    $scope.$on('onUnload', function() {
+        $templateCache.removeAll();
+    });
+
+    $scope.cmp = function(x, y) {
+        return x > y ? 1 : x < y ? -1 : 0;
+    };
+
+});
\ No newline at end of file
diff --git a/ui/src/main/webapp/reusable_chart.js b/ui/src/main/webapp/reusable_chart.js
new file mode 100644 (file)
index 0000000..01ab32d
--- /dev/null
@@ -0,0 +1,127 @@
+d3.custom = {};
+
+d3.custom.barChart = function module() {
+    var margin = {
+        top : 20,
+        right : 20,
+        bottom : 40,
+        left : 40
+    }, width = 500, height = 500, gap = 0, ease = 'cubic-in-out';
+    var svg, duration = 500;
+
+    var dispatch = d3.dispatch('customHover');
+    function exports(_selection) {
+        _selection
+                .each(function(_data) {
+
+                    var chartW = width - margin.left - margin.right, chartH = height
+                            - margin.top - margin.bottom;
+
+                    var x1 = d3.scale.ordinal().domain(
+                            _data.map(function(d, i) {
+                                return i;
+                            })).rangeRoundBands([ 0, chartW ], .1);
+
+                    var y1 = d3.scale.linear().domain(
+                            [ 0, d3.max(_data, function(d, i) {
+                                return d;
+                            }) ]).range([ chartH, 0 ]);
+
+                    var xAxis = d3.svg.axis().scale(x1).orient('bottom');
+
+                    var yAxis = d3.svg.axis().scale(y1).orient('left');
+
+                    var barW = chartW / _data.length;
+
+                    if (!svg) {
+                        svg = d3.select(this).append('svg').classed('chart',
+                                true);
+                        var container = svg.append('g').classed(
+                                'container-group', true);
+                        container.append('g').classed('chart-group', true);
+                        container.append('g')
+                                .classed('x-axis-group axis', true);
+                        container.append('g')
+                                .classed('y-axis-group axis', true);
+                    }
+
+                    svg.transition().duration(duration).attr({
+                        width : width,
+                        height : height
+                    })
+                    svg.select('.container-group').attr(
+                            {
+                                transform : 'translate(' + margin.left + ','
+                                        + margin.top + ')'
+                            });
+
+                    svg.select('.x-axis-group.axis').transition().duration(
+                            duration).ease(ease).attr({
+                        transform : 'translate(0,' + (chartH) + ')'
+                    }).call(xAxis);
+
+                    svg.select('.y-axis-group.axis').transition().duration(
+                            duration).ease(ease).call(yAxis);
+
+                    var gapSize = x1.rangeBand() / 100 * gap;
+                    var barW = x1.rangeBand() - gapSize;
+                    var bars = svg.select('.chart-group').selectAll('.bar')
+                            .data(_data);
+                    bars.enter().append('rect').classed('bar', true).attr({
+                        x : chartW,
+                        width : barW,
+                        y : function(d, i) {
+                            return y1(d);
+                        },
+                        height : function(d, i) {
+                            return chartH - y1(d);
+                        }
+                    }).on('mouseover', dispatch.customHover);
+                    bars.transition().duration(duration).ease(ease).attr({
+                        width : barW,
+                        x : function(d, i) {
+                            return x1(i) + gapSize / 2;
+                        },
+                        y : function(d, i) {
+                            return y1(d);
+                        },
+                        height : function(d, i) {
+                            return chartH - y1(d);
+                        }
+                    });
+                    bars.exit().transition().style({
+                        opacity : 0
+                    }).remove();
+
+                    duration = 500;
+
+                });
+    }
+    exports.width = function(_x) {
+        if (!arguments.length)
+            return width;
+        width = parseInt(_x);
+        return this;
+    };
+    exports.height = function(_x) {
+        if (!arguments.length)
+            return height;
+        height = parseInt(_x);
+        duration = 0;
+        return this;
+    };
+    exports.gap = function(_x) {
+        if (!arguments.length)
+            return gap;
+        gap = _x;
+        return this;
+    };
+    exports.ease = function(_x) {
+        if (!arguments.length)
+            return ease;
+        ease = _x;
+        return this;
+    };
+    d3.rebind(exports, dispatch, 'on');
+    return exports;
+};
\ No newline at end of file
diff --git a/ui/src/main/webapp/views/committedSubmissions.html b/ui/src/main/webapp/views/committedSubmissions.html
new file mode 100644 (file)
index 0000000..a3d1072
--- /dev/null
@@ -0,0 +1,196 @@
+<!--
+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 script PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html ng-app="BlueprintValidationUIManagement">
+<head>
+<style>
+.formfield * {
+       vertical-align: top;
+}
+
+.pagination {
+       display: inline-block;
+       float: right;
+}
+
+.pagination li {
+       list-style-type: none;
+       color: white;
+       float: left;
+       padding: 8px 16px;
+       text-decoration: none;
+       transition: background-color .3s;
+       border: 1px solid #ddd;
+}
+
+.pagination li.active {
+       background-color: #DCDCDC;
+       color: white;
+       border: 1px solid #ddd;
+}
+
+input[type="file"] {
+       display: inline-block;
+}
+
+.md-backdrop {
+       display: none;
+}
+/*.md-sidenav-right .md-theme-indigo, .md-sidenav-right .nav-theme {
+         background-color: #cccccc;
+         }*/
+/*.md-sidenav-backdrop md-opaque{
+         opacity:0;
+         }*/
+md-backdrop.md-opaque.md-default-theme, md-backdrop.md-opaque {
+       background-color: rgba(0, 0, 0, 0);
+}
+
+md-content.md-default-theme, md-content {
+       background-color: #cccccc;
+}
+
+md-sidenav.md-default-theme, md-sidenav {
+       background-color: #cccccc;
+}
+
+.vertical-menu {
+       width: 200px;
+       height: 150px;
+       overflow-y: auto;
+}
+
+input[type=text], select, textarea {
+       width: 40%;
+       padding: 3px;
+       border: 0.5px solid #ccc;
+       border-radius: 4px;
+       box-sizing: border-box;
+       margin-top: 3px;
+       margin-bottom: 3px;
+       resize: vertical;
+}
+
+pre {
+       font-size: 15px;
+       color: black;
+}
+</style>
+</head>
+<body ng-controller="AECCommittedSubmissionsController">
+ <div id="akrainocontent"
+  style="padding-left: 20px; padding-right: 20px; float: left; width: 90%;">
+  <div>
+   <h1>Committed Submissions</h1>
+  </div>
+  <!-- <label>Select Submissions: </label> -->
+  <br>
+  <div class="selectStyle">
+   <select class="exampleTable" style="width: 200px; height: 40px;">
+    <option value="">All submissions</option>
+   </select>
+  </div>
+  <div id="commandTable" style="padding-bottom: 1px; padding-top: 30px">
+   <form>
+    <div class="form-group">
+     <div class="input-group">
+      <div class="input-group-addon">
+       <i class="fa fa-search"> </i>
+      </div>
+      <input type="text" style="width: 300px" class="form-control"
+       placeholder="Search Committed Submissions" ng-model="q">
+      <div style="float: right;">
+       <a
+        style="padding-left: 5px; font-size: 16px; cursor: pointer; margin-top: 20px; color: #4d4d4d"
+        ng-click="refreshCommittedSubmissions()"> Refresh </a>
+       <button class="refreshbutton" style="margin-left: 5px;"
+        ng-click="deleteSubmissions()">Delete selected
+        submissions</button>
+       <button class="refreshbutton" style="margin-left: 5px;">Delete
+        all submissions</button>
+      </div>
+     </div>
+    </div>
+   </form>
+  </div>
+  <table cellspacing="0" cellpadding="10" class="siteStatusTable">
+   <thead>
+    <tr>
+     <th>&nbsp;</th>
+     <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">
+     <td><input type="checkbox" name="name1" ng-model="temp"
+      ng-change="modifySubmissionIdList(submission.submissionId)" />&nbsp;</td>
+     <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.blueprintInstance.blueprint.blueprintName }}</td>
+     <td style="padding-left: 10px; font-size: 15px; width: 13%;">{{
+      submission.blueprintInstance.version }}</td>
+     <td style="padding-left: 10px; font-size: 15px; width: 13%;">
+      <a href="#" data-toggle="tooltip"
+      title="{{submission.blueprintInstance.layer_description }}">{{
+       submission.blueprintInstance.layer }}</a>
+     </td>
+     <td style="padding-left: 10px; font-size: 15px; width: 13%;">Lab:
+      {{ submission.blueprintInstance.timeslot.lab }} Start date and
+      time: {{ submission.blueprintInstance.timeslot.startDateTime }}
+      duration(in sec) :
+      {{submission.blueprintInstance.timeslot.duration}}</td>
+     <td style="padding-left: 10px; font-size: 15px; width: 13%;">
+      <a href="{{submission.nexusResultUrl }}">{{
+       submission.nexusResultUrl }}</a>
+     </td>
+    </tr>
+   </tbody>
+  </table>
+  <p></p>
+  <div class="pagination">
+   <ul>
+    <li ng-class="{disabled: currentPage == 0}"><a href
+     ng-click="prevPage()"> Prev </a></li>
+    <li ng-repeat="n in range(pagedItems.length)"
+     ng-class="{active: n == currentPage}" ng-click="setPage()"><a
+     href ng-bind="n + 1">1 </a></li>
+    <li ng-class="{disabled: currentPage == pagedItems.length - 1}">
+     <a href ng-click="nextPage()">Next </a>
+    </li>
+   </ul>
+  </div>
+ </div>
+
+ <script>
+       $(document).ready(function(){
+               $('[data-toggle="tooltip"]').tooltip(); 
+       });
+       </script>
+
+</body>
+
+
+</html>
\ No newline at end of file
diff --git a/ui/src/main/webapp/views/findBySubmissionId.html b/ui/src/main/webapp/views/findBySubmissionId.html
new file mode 100644 (file)
index 0000000..2900b25
--- /dev/null
@@ -0,0 +1,182 @@
+<!--
+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 script PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html ng-app="BlueprintValidationUIManagement">
+<head>
+<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%;
+}
+</style>
+</head>
+<body ng-controller="AECFindBySubmissionIdController">
+ <div id="akrainofindbysubmissionidform"
+  style="padding-left: 20px; padding-right: 20px">
+  <div>
+   <h1>Find results by submission</h1>
+  </div>
+
+  <label>Select Submission: </label>
+  <div class="selectStyle">
+   <select class="exampleTable" ng-model="selectedSubmission"
+    ng-init="selectedSubmission=submissionsForDisplay[0]"
+    ng-change="selectedSubmissionChange(selectedSubmission)"
+    ng-options="n for n in submissionsForDisplay">
+   </select>
+  </div>
+
+  <div ng-repeat="result in results">
+
+   <h2>Test info</h2>
+   <p></p>
+   <p>Name: {{result.name}}</p>
+   <p>Generated: {{result.robot.generated}}</p>
+   <p>Generator: {{result.robot.generator}}</p>
+   <p>Errors: {{result.robot.errors}}</p>
+
+   <h2>Test Statistics</h2>
+   <p></p>
+   <table cellspacing="0" cellpadding="10" class="siteStatusTable">
+    <caption>
+     <h3></h3>
+    </caption>
+    <thead>
+     <th>&nbsp;Total statistics&nbsp;</th>
+     <th>Total&nbsp;</th>
+     <th>Pass&nbsp;</th>
+     <th>Fail&nbsp;</th>
+     <th>Pass / Fail&nbsp;</th>
+     </tr>
+    </thead>
+    <tbody>
+     <tr class="border_bottom"
+      ng-repeat="stat in result.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>
+
+   <table cellspacing="0" cellpadding="10" class="siteStatusTable">
+    <caption>
+     <h3></h3>
+    </caption>
+    <thead>
+     <th>&nbsp;Statistics by Tag&nbsp;</th>
+     <th>Total&nbsp;</th>
+     <th>Pass&nbsp;</th>
+     <th>Fail&nbsp;</th>
+     <th>Pass / Fail&nbsp;</th>
+     </tr>
+    </thead>
+    <tbody>
+     <tr class="border_bottom"
+      ng-repeat="stat in results.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>
+
+   <table cellspacing="0" cellpadding="10" class="siteStatusTable">
+    <caption>
+     <h3></h3>
+    </caption>
+    <thead>
+     <th>&nbsp;Statistics by Suite&nbsp;</th>
+     <th>Total&nbsp;</th>
+     <th>Pass&nbsp;</th>
+     <th>Fail&nbsp;</th>
+     <th>Pass / Fail&nbsp;</th>
+     </tr>
+    </thead>
+    <tbody>
+     <tr class="border_bottom"
+      ng-repeat="stat in result.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>
+ </div>
+</body>
+
+</html>
+
diff --git a/ui/src/main/webapp/views/indexMain.html b/ui/src/main/webapp/views/indexMain.html
new file mode 100644 (file)
index 0000000..758bb3a
--- /dev/null
@@ -0,0 +1,117 @@
+<!--
+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>
+ <div class="header" style="width: 100%"
+  style="padding-top:5px; padding-bottom:5px;background-color:#000000;">
+  <a href="https://www.akraino.org/"> <img
+   src="./resources/images/logo_akraino_edge_stack.png" alt="Akraino"
+   width="200" height="57" border="0">
+  </a>
+  <p></p>
+  <p style="color: white;">
+   <b> <font size="14">&emsp;Blueprint Validation UI</font></b>
+  </p>
+  <div class="header-right">
+   <a class="active" href="#home">Home</a> <a href="#"
+    style="font-color: #FFFFFF">Documentation</a> <a href="#"
+    style="font-color: #FFFFFF"
+    ng-show="$state.current.name == 'undefined' || $state.current.name != 'login'"
+    ng-click="goLogout()">Sign Out</a>
+  </div>
+ </div>
+ <div id="wrapper" style="margin-top: 0.1px;">
+  <div id="sidebar-wrapper"
+   ng-show="$state.current.name == 'undefined' || $state.current.name != 'login'"
+   ng-cloak>
+   <ul class="sidebar-nav">
+    <li><a
+     ng-class="{example : $state.current.name == 'committedSubmissions'}"
+     ui-sref="committedSubmissions"> <i class="fa fa-home"></i> <span>Committed
+       Submissions</span>
+    </a></li>
+    <li><a
+     ng-class="{example : $state.current.name == 'newSubmission'}"
+     ui-sref="newSubmission"> <i class="fa fa-home"></i> <span>New
+       Submission</span>
+    </a></li>
+    <li class="dropdown"><a class="dropdown-toggle"
+     data-toggle="collapse" data-target="#configuracoes1" role="button"
+     aria-haspopup="true" aria-expanded="false"><i class="fa fa-cog"></i>Blueprint
+      Validation Results<span class="caret"> </span></a>
+     <ul id="configuracoes1" class="collapse">
+      <li><a
+       ng-class="{example : $state.current.name == 'eteTest'}"
+       ui-sref="eteTest"> <i class="fa fa-check"></i><span>Get
+         all</span>
+      </a></li>
+      <li><a
+       ng-class="{example : $state.current.name == 'eteChomp'}"
+       ui-sref="eteChomp"> <i class="fa fa-check"></i><span>Get
+         by blueprint name</span>
+      </a></li>
+      <li><a
+       ng-class="{example : $state.current.name == 'eteChomp'}"
+       ui-sref="eteChomp"> <i class="fa fa-check"></i><span>Get
+         by layer</span>
+      </a></li>
+      <li><a
+       ng-class="{example : $state.current.name == 'findBySubmission'}"
+       ui-sref="findBySubmissionId"> <i class="fa fa-check"></i><span>Get
+         by submission id</span>
+      </a></li>
+      <li><a
+       ng-class="{example : $state.current.name == 'eteChomp'}"
+       ui-sref="eteChomp"> <i class="fa fa-check"></i><span>Get
+         by execution dates</span>
+      </a></li>
+      <li><a
+       ng-class="{example : $state.current.name == 'eteChomp'}"
+       ui-sref="eteChomp"> <i class="fa fa-check"></i><span>Get
+         by # of successful runs</span>
+      </a></li>
+      <li><a
+       ng-class="{example : $state.current.name == 'eteChomp'}"
+       ui-sref="eteChomp"> <i class="fa fa-check"></i><span>Get
+         by # of successful last runs</span>
+      </a></li>
+      <li><a
+       ng-class="{example : $state.current.name == 'eteChomp'}"
+       ui-sref="eteChomp"> <i class="fa fa-check"></i><span>Get
+         by # of failed last runs</span>
+      </a></li>
+     </ul></li>
+   </ul>
+  </div>
+  <!-- /#sidebar-wrapper -->
+  <!-- Page Content -->
+  <div id="page-content-wrapper"
+   ng-show="$state.current.name == 'undefined' || $state.current.name != 'login'"
+   style="overflow: auto;" ng-cloak>
+   <div class="container-fluid">
+    <div class="row">
+     <div class="col-lg-12" style="padding-right: 0px;">
+      <div id="wrapper">
+       <!-- Carrega todas as p�ginas-->
+       <div ui-view="main"></div>
+      </div>
+     </div>
+    </div>
+   </div>
+  </div>
+  <!-- /#page-content-wrapper -->
+ </div>
+</div>
diff --git a/ui/src/main/webapp/views/login.html b/ui/src/main/webapp/views/login.html
new file mode 100644 (file)
index 0000000..daf5454
--- /dev/null
@@ -0,0 +1,98 @@
+<!--
+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.
+-->
+-->
+
+<html ng-app="BlueprintValidationUIManagement">
+<head>
+<style>
+.form_bg {
+       background-color: #eee;
+       color: #666;
+       padding: 20px;
+       border-radius: 10px;
+       position: absolute;
+       border: 1px solid #fff;
+       top: 0;
+       right: 0;
+       bottom: 0;
+       left: 0;
+       margin: auto;
+       width: 400px;
+       height: 320px;
+}
+
+.form-control {
+       width: 320px;
+}
+
+.align-center {
+       text-align: center;
+}
+</style>
+</head>
+<body ng-controller="Login">
+ <div>
+  <div class="header" style="width: 100%"
+   style="padding-top:10px; padding-bottom:10px">
+   <a href="https://www.akraino.org/"> <img
+    src="./resources/images/logo_akraino_edge_stack.png" alt="Akraino"
+    width="200" height="57" border="0">
+   </a>
+   <div class="header-right">
+    <a class="active" href="#home">Home</a> <a href="#"
+     style="font-color: #FFFFFF">Documentation</a> <a href="#"
+     style="font-color: #FFFFFF"
+     ng-show="$state.current.name == 'undefined' || $state.current.name != 'login'"
+     ng-click="goLogout()">Sign Out</a>
+   </div>
+  </div>
+ </div>
+ <div class="container">
+  <div class="row">
+   <h1 style="color: blue;" class="align-center">Blueprint
+    Validation UI</h1>
+   <h2 class="align-center">Sign In Page</h2>
+   <div class="form_bg" style="margin-top: 230px;">
+    <form>
+     <br />
+     <div class="form-group">
+      <label
+       style="margin-left: auto; margin-right: auto; padding-left: 15px;">{{message}}</label>
+      <input type="text" style="margin-left: auto; margin-right: auto;"
+       class="form-control" id="userid" placeholder="User name"
+       ng-model="usernameVal"> <label
+       style="display: block; text-align: center; color: red;">{{
+       userMessage }}</label>
+     </div>
+     <div class="form-group">
+      <input type="password"
+       style="margin-left: auto; margin-right: auto;"
+       class="form-control" id="pwd" placeholder="Password"
+       ng-model="passwordVal"> <label
+       style="display: block; text-align: center; color: red;">{{
+       passwordMessage }}</label>
+     </div>
+     <br />
+     <div class="align-center">
+      <button type="submit" class="btn btn-default" id="login"
+       ng-click="goLogin()">Login</button>
+     </div>
+    </form>
+   </div>
+  </div>
+ </div>
+</body>
+<html>
\ No newline at end of file
diff --git a/ui/src/main/webapp/views/newSubmission.html b/ui/src/main/webapp/views/newSubmission.html
new file mode 100644 (file)
index 0000000..11c8afa
--- /dev/null
@@ -0,0 +1,68 @@
+<!--
+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 script PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html ng-app="BlueprintValidationUIManagement">
+<head>
+</head>
+<body ng-controller="AECNewSubmissionController">
+ <div id="akrainonewsubmissionform"
+  style="padding-left: 20px; padding-right: 20px">
+  <div>
+   <h1>Submission form</h1>
+  </div>
+
+  <label>Select Blueprint: </label>
+  <div class="selectStyle">
+   <select class="exampleTable" ng-model="selectedBlueprintName"
+    ng-init="selectedBlueprintName=blueprintNames[0]"
+    ng-change="selectedBluePrintNameChange()"
+    ng-options="n for n in blueprintNames">
+   </select>
+  </div>
+
+  <label>Select Blueprint Version: </label>
+  <div class="selectStyle">
+   <select class="exampleTable" ng-model="selectedBlueprintVersion"
+    ng-change="selectedBluePrintVersionChange()"
+    ng-options="y for y in blueprintVersions">
+   </select>
+  </div>
+
+  <label>Select Blueprint Layer: </label>
+  <div class="selectStyle">
+   <select class="exampleTable" ng-model="selectedBlueprintLayer"
+    ng-change="selectedBluePrintLayerChange()"
+    ng-options="l for l in blueprintLayers">
+   </select>
+  </div>
+
+  <label>Select Blueprint Timeslot: </label>
+  <div class="selectStyle">
+   <select class="exampleTable" ng-model="selectedDeclerativeTimeslot"
+    ng-options="v for v in declerativeTimeslots">
+   </select>
+  </div>
+
+  <br>
+  <button class="refreshbutton" style="float: left" ng-click="submit();">Submit</button>
+ </div>
+</body>
+
+</html>
+
+
+