Merge "Fix static web resource paths in gui-editor-apex"
diff --git a/README.md b/README.md
index 17bbf95..6322319 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,45 @@
+# Summary
+
 Copyright 2017-2018 AT&T Intellectual Property. All rights reserved.
+Copyright (C) 2021 Nordix Foundation.
 This file is licensed under the CREATIVE COMMONS ATTRIBUTION 4.0 INTERNATIONAL LICENSE
 Full license text at https://creativecommons.org/licenses/by/4.0/legalcode
 
 This source repository contains the ONAP Policy GUI code.
 
-To build it using Maven 3, run: mvn clean install
+To build it using Maven 3, run: mvn clean install -P docker
+
+
+# Docker image
+
+Maven produces a single docker image containing the policy GUIs. These are exposed on
+the same port (8080) using different URLs:
+- Apex Policy Editor: http://localhost:8080/apex-editor
+- PDP Monitoring UI: http://localhost:8080/pdp-monitoring
+- CLAMP Designer UI: http://localhost:8080/clamp
+
+## Building
+You can use the following command to build the policy-gui docker image:
+```
+mvn clean install -P docker
+```
+
+## Deployment
+Currently, the policy-gui docker image can be deployed with minimal configuration. As
+the clamp backend is required to use the clamp GUI, you can use the CLAMP_REST_URL
+environment variable to set its location.
+
+By default, CLAMP_REST_URL is set to an invalid address (0.0.0.0), meaning the CLAMP GUI
+will not work without specifying CLAMP_REST_URL.
+
+If running clamp as part of a docker network, where `policy-clamp-backend` is the CLAMP
+backend, then CLAMP_REST_URL should be set to `https://policy-clamp-backend:8443`.
+
+If running clamp backend on localhost port 8443, the policy-gui docker image would be
+started like this:
+```
+docker run -p 8080:8080 \
+    --add-host host.docker.internal:host-gateway \
+    --env CLAMP_REST_URL=https://host.docker.internal:8443 \
+    onap/policy-gui
+```
diff --git a/gui-clamp/pom.xml b/gui-clamp/pom.xml
index 8d29ce4..a19d1ca 100644
--- a/gui-clamp/pom.xml
+++ b/gui-clamp/pom.xml
@@ -147,6 +147,17 @@
                         </configuration>
                     </execution>
                     <execution>
+                        <id>npm_build</id>
+                        <goals>
+                            <goal>npm</goal>
+                        </goals>
+                        <phase>package</phase>
+                        <configuration>
+                            <workingDirectory>${project.build.directory}/${ui.react.src}</workingDirectory>
+                            <arguments>run build</arguments>
+                        </configuration>
+                    </execution>
+                    <execution>
                         <id>npm_test</id>
                         <goals>
                             <goal>npm</goal>
@@ -158,6 +169,7 @@
                             <workingDirectory>${project.build.directory}/${ui.react.src}</workingDirectory>
                         </configuration>
                     </execution>
+                    <!-- XXX Are these deploy steps using npm desirable given docker image generation? -->
                     <execution>
                         <id>npm_install_lib</id>
                         <goals>
@@ -228,6 +240,25 @@
                 <artifactId>versions-maven-plugin</artifactId>
                 <version>1.3.1</version>
             </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <id>generate-gui-clamp-tar</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/main/assembly/clamp-build.xml</descriptor>
+                            </descriptors>
+                            <finalName>${project.artifactId}-${project.version}</finalName>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 </project>
diff --git a/gui-clamp/src/main/assembly/clamp-build.xml b/gui-clamp/src/main/assembly/clamp-build.xml
new file mode 100644
index 0000000..215b646
--- /dev/null
+++ b/gui-clamp/src/main/assembly/clamp-build.xml
@@ -0,0 +1,34 @@
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2021 Nordix Foundation.
+  ================================================================================
+  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.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+
+<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+          xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
+    <id>clamp-build</id>
+    <formats>
+        <format>tar.gz</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+    <fileSets>
+        <fileSet>
+            <directory>${project.build.directory}/${ui.react.src}/build</directory>
+            <outputDirectory>clamp</outputDirectory>
+        </fileSet>
+    </fileSets>
+</assembly>
diff --git a/gui-editors/gui-editor-apex/pom.xml b/gui-editors/gui-editor-apex/pom.xml
index b52631a..1854166 100644
--- a/gui-editors/gui-editor-apex/pom.xml
+++ b/gui-editors/gui-editor-apex/pom.xml
@@ -300,6 +300,28 @@
                     </transformers>
                 </configuration>
             </plugin>
+            <plugin>
+                <groupId>org.codehaus.mojo</groupId>
+                <artifactId>build-helper-maven-plugin</artifactId>
+                <version>3.0.0</version>
+                <executions>
+                    <execution>
+                        <id>attach-artifacts</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>attach-artifact</goal>
+                        </goals>
+                        <configuration>
+                            <artifacts>
+                                <artifact>
+                                    <file>${project.build.directory}/${project.artifactId}-uber-${project.version}.jar</file>
+                                    <type>uber.jar</type>
+                                </artifact>
+                            </artifacts>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
         </plugins>
     </build>
 </project>
diff --git a/gui-editors/gui-editor-apex/src/main/resources/webapp/js/ApexContextSchemaTab.js b/gui-editors/gui-editor-apex/src/main/resources/webapp/js/ApexContextSchemaTab.js
index c5c7daa..fa5ed6f 100644
--- a/gui-editors/gui-editor-apex/src/main/resources/webapp/js/ApexContextSchemaTab.js
+++ b/gui-editors/gui-editor-apex/src/main/resources/webapp/js/ApexContextSchemaTab.js
@@ -22,7 +22,7 @@
 const {ajax_get} = require("./ApexAjax");
 const {createTable} = require('./ApexTable');
 const {rightClickMenu_scopePreserver} = require('./contextMenu');
-const {apexUtils_removeElement} = require('./ApexUtils');
+const {apexUtils_escapeHtml, apexUtils_removeElement} = require('./ApexUtils');
 
 function contextSchemaTab_reset() {
     contextSchemaTab_deactivate();
diff --git a/gui-editors/gui-editor-apex/src/main/resources/webapp/js/ApexPolicyEditForm.js b/gui-editors/gui-editor-apex/src/main/resources/webapp/js/ApexPolicyEditForm.js
index 59af8f5..edaf7b7 100644
--- a/gui-editors/gui-editor-apex/src/main/resources/webapp/js/ApexPolicyEditForm.js
+++ b/gui-editors/gui-editor-apex/src/main/resources/webapp/js/ApexPolicyEditForm.js
@@ -334,10 +334,10 @@
     triggerLabel.innerHTML = "Policy Trigger Event: ";
     var triggerevent = null;
     if (policy != null && policy.firstState != null && policy.firstState != "" && policy.state != null) {
-        for (i = 0; i < policy.state.entry.length; i++) {
-            if (policy.state.entry[i] != null && policy.state.entry[i].key != null) {
-                statename = policy.state.entry[i].key;
-                var state = policy.state.entry[i].value;
+        for (let entry of policy.state.entry) {
+            if (entry != null && entry.key != null) {
+                statename = entry.key;
+                var state = entry.value;
                 if (statename != null && statename == policy.firstState) {
                     triggerevent = {
                         "name" : state.trigger.name,
diff --git a/gui-editors/gui-editor-apex/src/main/resources/webapp/js/ApexPolicyTab.js b/gui-editors/gui-editor-apex/src/main/resources/webapp/js/ApexPolicyTab.js
index c6ef0db..2aa96e4 100644
--- a/gui-editors/gui-editor-apex/src/main/resources/webapp/js/ApexPolicyTab.js
+++ b/gui-editors/gui-editor-apex/src/main/resources/webapp/js/ApexPolicyTab.js
@@ -81,9 +81,9 @@
                     "</td>";
 
                 policyTableRow += "<td><table class='ebTable'><thead><tr class='headerRow'><th>Task Reference</th><th>Output Type</th><th>Output</th></thead><tbody>";
-                for (let entry of state.taskReferences.entry) {
-                    var taskKey = entry.key;
-                    var taskRef = entry.value;
+                for (let taskEntry of state.taskReferences.entry) {
+                    var taskKey = taskEntry.key;
+                    var taskRef = taskEntry.value;
 
                     policyTableRow +=
                         "<tr><td>"                +
diff --git a/gui-pdp-monitoring/src/webapp/js/MonitoringUtils.js b/gui-pdp-monitoring/src/webapp/js/MonitoringUtils.js
index 9c6e076..2f2b044 100644
--- a/gui-pdp-monitoring/src/webapp/js/MonitoringUtils.js
+++ b/gui-pdp-monitoring/src/webapp/js/MonitoringUtils.js
@@ -1,6 +1,7 @@
 /*-
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2020 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. 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.
@@ -309,11 +310,11 @@
 
 function getPdpList(data) {
     const pdpArray = [];
-    for (let i = 0; i < data.groups.length; i++) {
+    for (let value of data.groups) {
         var map = {};
-        map.title = data.groups[i].name;
+        map.title = value.name;
         map.children = [];
-        (data.groups[i].pdpSubgroups).forEach((pdpSubgroup, index) => {
+        (value.pdpSubgroups).forEach((pdpSubgroup, index) => {
             map.children[index] = {};
             map.children[index].title = pdpSubgroup.pdpType;
             const instanceId = [];
diff --git a/gui-pdp-monitoring/src/webapp/js/PdpListView.js b/gui-pdp-monitoring/src/webapp/js/PdpListView.js
index 9ae5c23..1e248ce 100644
--- a/gui-pdp-monitoring/src/webapp/js/PdpListView.js
+++ b/gui-pdp-monitoring/src/webapp/js/PdpListView.js
@@ -1,6 +1,7 @@
 /*-
  * ============LICENSE_START=======================================================
  *  Copyright (C) 2020-2021 Nordix Foundation.
+ *  Modifications Copyright (C) 2021 Bell Canada. 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.
@@ -26,20 +27,20 @@
         var isNode=false
     function insertChildren(parentNode, traverseArr, subGroup) {
 
-        for(let i = 0; i < traverseArr.length; i++) {
+        for(let value of traverseArr) {
             if(parentNode === root) {
                 childLevel = 0
             }
             var currentLi = document.createElement('li')
             currentLi.setAttribute('level', childLevel)
-            if(traverseArr[i].children && traverseArr[i].children.length > 0) {
+            if(value.children && value.children.length > 0) {
                 var title = document.createElement('div')
                 var triangle = document.createElement('i')
                 var text = document.createElement('p')
                 currentLi.classList.add('parentNode')
                 title.classList.add('title')
                 triangle.classList.add('triangle')
-                text.innerText = traverseArr[i].title
+                text.innerText = value.title
                 title.appendChild(triangle)
                 title.appendChild(text)
                 currentLi.appendChild(title)
@@ -48,12 +49,12 @@
                 if(subGroup !== null){
                     index+= subGroup+"/"
                 }
-                insertChildren(currentLi, traverseArr[i].children, traverseArr[i].title)
+                insertChildren(currentLi, value.children, value.title)
             }else {
                 var a = document.createElement('a')
-                a.setAttribute('href',"#"+index+subGroup+"/"+traverseArr[i].title)
+                a.setAttribute('href',"#"+index+subGroup+"/"+value.title)
                 a.classList.add('pdps__link')
-                a.textContent= traverseArr[i].title
+                a.textContent= value.title
                 currentLi.appendChild(a)
                 isNode=true
             }
diff --git a/packages/policy-gui-docker/pom.xml b/packages/policy-gui-docker/pom.xml
new file mode 100644
index 0000000..94453ce
--- /dev/null
+++ b/packages/policy-gui-docker/pom.xml
@@ -0,0 +1,184 @@
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2021 Nordix Foundation.
+  ================================================================================
+  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.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+
+<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/xsd/maven-4.0.0.xsd">
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onap.policy.gui</groupId>
+        <artifactId>gui-packages</artifactId>
+        <version>2.1.0-SNAPSHOT</version>
+    </parent>
+
+    <packaging>pom</packaging>
+    <artifactId>policy-gui-docker</artifactId>
+    <name>${project.artifactId}</name>
+    <description>Policy gui docker image</description>
+
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <dist.project.version>${project.version}</dist.project.version>
+        <docker.skip>false</docker.skip>
+        <docker.skip.build>false</docker.skip.build>
+        <docker.skip.push>false</docker.skip.push>
+        <docker.pull.registry>nexus3.onap.org:10001</docker.pull.registry>
+        <docker.push.registry>nexus3.onap.org:10003</docker.push.registry>
+        <maven.build.timestamp.format>yyyyMMdd'T'HHmm</maven.build.timestamp.format>
+    </properties>
+
+    <build>
+        <finalName>${project.artifactId}-${project.version}</finalName>
+        <plugins>
+            <plugin>
+                <groupId>org.codehaus.gmaven</groupId>
+                <artifactId>groovy-maven-plugin</artifactId>
+                <version>2.1.1</version>
+                <executions>
+                    <execution>
+                        <phase>validate</phase>
+                        <goals>
+                            <goal>execute</goal>
+                        </goals>
+                        <configuration>
+                            <source>https://github.com/onap/policy-docker/raw/master/utils/groovy/docker-tag.groovy</source>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>io.fabric8</groupId>
+                <artifactId>docker-maven-plugin</artifactId>
+
+                <configuration>
+                    <verbose>true</verbose>
+                    <apiVersion>1.23</apiVersion>
+                    <pullRegistry>${docker.pull.registry}</pullRegistry>
+                    <pushRegistry>${docker.push.registry}</pushRegistry>
+
+                    <images>
+                        <image>
+                            <name>onap/policy-gui</name>
+                            <build>
+                                <cleanup>try</cleanup>
+                                <dockerFile>Dockerfile</dockerFile>
+                                <tags>
+                                    <tag>${project.version}</tag>
+                                    <tag>${project.version}-${maven.build.timestamp}</tag>
+                                    <tag>${project.docker.latest.minmax.tag.version}</tag>
+                                </tags>
+                                <assembly>
+                                    <inline>
+                                        <dependencySets>
+                                            <dependencySet>
+                                                <includes>
+                                                    <include>org.onap.policy.gui:gui-clamp:tar.gz:clamp-build:${project.version}</include>
+                                                </includes>
+                                                <outputFileNameMapping>gui-clamp.tar.gz</outputFileNameMapping>
+                                            </dependencySet>
+                                            <dependencySet>
+                                                <includes>
+                                                    <include>org.onap.policy.gui:gui-pdp-monitoring:uber.jar:${project.version}</include>
+                                                </includes>
+                                                <outputFileNameMapping>gui-pdp-monitoring-uber.jar</outputFileNameMapping>
+                                            </dependencySet>
+                                            <dependencySet>
+                                                <includes>
+                                                    <include>org.onap.policy.gui.editors:gui-editor-apex:uber.jar:${project.version}</include>
+                                                </includes>
+                                                <outputFileNameMapping>gui-editor-apex-uber.jar</outputFileNameMapping>
+                                            </dependencySet>
+                                        </dependencySets>
+                                    </inline>
+                                </assembly>
+                            </build>
+                        </image>
+                    </images>
+                </configuration>
+
+                <executions>
+                    <execution>
+                        <id>clean-images</id>
+                        <phase>pre-clean</phase>
+                        <goals>
+                            <goal>remove</goal>
+                        </goals>
+                        <configuration>
+                            <removeAll>true</removeAll>
+                        </configuration>
+                    </execution>
+
+                    <execution>
+                        <id>generate-images</id>
+                        <phase>generate-sources</phase>
+                        <goals>
+                            <goal>build</goal>
+                        </goals>
+                    </execution>
+
+                    <execution>
+                        <id>push-images</id>
+                        <phase>deploy</phase>
+                        <goals>
+                            <goal>build</goal>
+                            <goal>push</goal>
+                        </goals>
+                        <configuration>
+                            <image>onap/policy-gui</image>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-deploy-plugin</artifactId>
+                <configuration>
+                    <skip>true</skip>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.onap.policy.gui</groupId>
+            <artifactId>gui-clamp</artifactId>
+            <version>${project.version}</version>
+            <classifier>clamp-build</classifier>
+            <type>tar.gz</type>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.policy.gui</groupId>
+            <artifactId>gui-pdp-monitoring</artifactId>
+            <version>${project.version}</version>
+            <type>uber.jar</type>
+        </dependency>
+        <dependency>
+            <groupId>org.onap.policy.gui.editors</groupId>
+            <artifactId>gui-editor-apex</artifactId>
+            <version>${project.version}</version>
+            <type>uber.jar</type>
+        </dependency>
+    </dependencies>
+</project>
diff --git a/packages/policy-gui-docker/src/main/docker/Dockerfile b/packages/policy-gui-docker/src/main/docker/Dockerfile
new file mode 100644
index 0000000..e58c9ea
--- /dev/null
+++ b/packages/policy-gui-docker/src/main/docker/Dockerfile
@@ -0,0 +1,54 @@
+#-------------------------------------------------------------------------------
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2021 Nordix Foundation.
+# ================================================================================
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#-------------------------------------------------------------------------------
+
+FROM onap/policy-jre-alpine:2.3.0
+
+LABEL maintainer="Policy Team"
+
+ARG POLICY_LOGS=/var/log/onap/policy/gui
+
+ENV POLICY_LOGS=$POLICY_LOGS
+ENV POLICY_HOME=$POLICY_HOME/gui
+ENV CLAMP_REST_URL=http://0.0.0.0
+
+RUN mkdir -p $POLICY_HOME $POLICY_LOGS $POLICY_HOME/bin $POLICY_HOME/lib && \
+    chown -R policy:policy $POLICY_HOME $POLICY_LOGS && \
+    apk update && \
+    apk add --no-cache gettext nginx
+
+WORKDIR $POLICY_HOME
+COPY policy-gui.sh ./bin/
+COPY /maven/gui-editor-apex-uber.jar ./lib/
+COPY /maven/gui-pdp-monitoring-uber.jar ./lib/
+COPY nginx/nginx.conf /etc/nginx/nginx.conf
+COPY nginx/default.conf.template /etc/nginx/templates/default.conf.template
+COPY nginx/index.html /usr/share/nginx/html/
+ADD /maven/gui-clamp.tar.gz /usr/share/nginx/html/
+RUN rm /etc/nginx/conf.d/default.conf && \
+    ln -sf /dev/stdout /var/log/nginx/access.log && \
+    ln -sf /dev/stderr /var/log/nginx/error.log && \
+    touch /var/run/nginx.pid && \
+    chown -R policy:policy . /etc/nginx /usr/share/nginx /var/lib/nginx /var/log/nginx /var/run/nginx.pid && \
+    chmod 755 bin/*.sh
+
+USER policy
+WORKDIR $POLICY_HOME/bin
+ENTRYPOINT [ "./policy-gui.sh" ]
+EXPOSE 8080
diff --git a/packages/policy-gui-docker/src/main/docker/nginx/default.conf.template b/packages/policy-gui-docker/src/main/docker/nginx/default.conf.template
new file mode 100644
index 0000000..a12f34b
--- /dev/null
+++ b/packages/policy-gui-docker/src/main/docker/nginx/default.conf.template
@@ -0,0 +1,30 @@
+server {
+  listen 8080;
+
+  location / {
+    root /usr/share/nginx/html;
+    index index.html index.htm;
+    try_files $uri $uri/ =404;
+  }
+
+  location /clamp/restservices/clds/ {
+    proxy_pass ${CLAMP_REST_URL}/restservices/clds/;
+  }
+
+  location /apex-editor/ {
+    proxy_pass http://localhost:18989/;
+    proxy_set_header Host $host;
+    proxy_set_header If-Modified-Since $http_if_modified_since;
+  }
+
+  location /pdp-monitoring/ {
+    proxy_pass http://localhost:18999/;
+    proxy_set_header Host $host;
+    proxy_set_header If-Modified-Since $http_if_modified_since;
+  }
+
+  location = /50x.html {
+    root /var/lib/nginx/html;
+  }
+  error_page  500 502 503 504  /50x.html;
+}
diff --git a/packages/policy-gui-docker/src/main/docker/nginx/index.html b/packages/policy-gui-docker/src/main/docker/nginx/index.html
new file mode 100644
index 0000000..98742ae
--- /dev/null
+++ b/packages/policy-gui-docker/src/main/docker/nginx/index.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+    <meta charset="utf-8">
+    <title>ONAP Policy GUI</title>
+</head>
+<body>
+    <ul>
+        <li><a href="/apex-editor">Apex Policy Editor</a></li>
+        <li><a href="/pdp-monitoring">PDP Monitoring</a></li>
+        <li><a href="/clamp">CLAMP Designer UI</a></li>
+    </ul>
+</body>
+</html>
diff --git a/packages/policy-gui-docker/src/main/docker/nginx/nginx.conf b/packages/policy-gui-docker/src/main/docker/nginx/nginx.conf
new file mode 100644
index 0000000..aac9bb6
--- /dev/null
+++ b/packages/policy-gui-docker/src/main/docker/nginx/nginx.conf
@@ -0,0 +1,18 @@
+worker_processes  1;
+pid /var/run/nginx.pid;
+error_log /dev/stdout info;
+events {
+}
+http {
+  include       /etc/nginx/mime.types;
+  default_type  application/octet-stream;
+  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
+                    '$status $body_bytes_sent "$http_referer" '
+                    '"$http_user_agent" "$http_x_forwarded_for"';
+  access_log  /var/log/nginx/access.log  main;
+  sendfile        on;
+  #tcp_nopush     on;
+  keepalive_timeout  65;
+  #gzip  on;
+  include /etc/nginx/conf.d/*.conf;
+}
diff --git a/packages/policy-gui-docker/src/main/docker/policy-gui.sh b/packages/policy-gui-docker/src/main/docker/policy-gui.sh
new file mode 100644
index 0000000..4d4cbee
--- /dev/null
+++ b/packages/policy-gui-docker/src/main/docker/policy-gui.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env sh
+#
+# ============LICENSE_START=======================================================
+#  Copyright (C) 2021 Nordix Foundation.
+# ================================================================================
+# 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.
+#
+# SPDX-License-Identifier: Apache-2.0
+# ============LICENSE_END=========================================================
+#
+
+trap 'exit 0' SIGTERM
+
+JAVA_HOME=/usr/lib/jvm/java-11-openjdk/
+
+echo "Starting gui-editor-apex"
+$JAVA_HOME/bin/java -jar "$POLICY_HOME/lib/gui-editor-apex-uber.jar" -p 18989 &
+
+echo "Starting gui-pdp-monitoring"
+$JAVA_HOME/bin/java -jar "$POLICY_HOME/lib/gui-pdp-monitoring-uber.jar" -p 18999 &
+
+echo "Starting nginx"
+envsubst '${CLAMP_REST_URL}' < /etc/nginx/templates/default.conf.template > /etc/nginx/conf.d/default.conf
+nginx -g "daemon on;"
+
+wait
diff --git a/packages/pom.xml b/packages/pom.xml
new file mode 100644
index 0000000..eb789ce
--- /dev/null
+++ b/packages/pom.xml
@@ -0,0 +1,51 @@
+<!--
+  ============LICENSE_START=======================================================
+   Copyright (C) 2021 Nordix Foundation.
+  ================================================================================
+  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.
+
+  SPDX-License-Identifier: Apache-2.0
+  ============LICENSE_END=========================================================
+-->
+<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/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.onap.policy.gui</groupId>
+        <artifactId>policy-gui</artifactId>
+        <version>2.1.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>gui-packages</artifactId>
+    <packaging>pom</packaging>
+
+    <name>${project.artifactId}</name>
+    <description>[${project.parent.artifactId}] packaging</description>
+
+    <properties>
+        <!-- There is no code in this sub-module, only holds interfaces. So skip sonar. -->
+        <sonar.skip>true</sonar.skip>
+    </properties>
+
+    <profiles>
+        <profile>
+            <id>docker</id>
+            <modules>
+                <module>policy-gui-docker</module>
+            </modules>
+            <properties>
+                <docker.skip.push>false</docker.skip.push>
+            </properties>
+        </profile>
+    </profiles>
+</project>
+
diff --git a/pom.xml b/pom.xml
index 439f018..fc1abf4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -51,6 +51,7 @@
         <module>gui-pdp-monitoring</module>
         <module>gui-editors</module>
         <module>gui-clamp</module>
+        <module>packages</module>
     </modules>
 
     <dependencies>