aboutsummaryrefslogtreecommitdiffstats
path: root/client/client-deployment
diff options
context:
space:
mode:
authorramverma <ram.krishna.verma@ericsson.com>2018-07-11 14:21:13 +0100
committerramverma <ram.krishna.verma@ericsson.com>2018-07-12 17:40:19 +0100
commitc6d74e6cee17405b9d26506b06259ccb2f38c737 (patch)
tree9f5dabe5ceffe0e6b99a2bf77be812657953ae9b /client/client-deployment
parentb461c6505afddacbef90e3dc0bfa9d49609a626b (diff)
Adding client deployment module to apex-pdp
Change-Id: Idd74e9846c3fa75d305a9dde98a98d92dd0520a9 Issue-ID: POLICY-864 Signed-off-by: ramverma <ram.krishna.verma@ericsson.com>
Diffstat (limited to 'client/client-deployment')
-rw-r--r--client/client-deployment/pom.xml191
-rw-r--r--client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRest.java84
-rw-r--r--client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestMain.java192
-rw-r--r--client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestParameterException.java49
-rw-r--r--client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestParameterParser.java116
-rw-r--r--client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestParameters.java115
-rw-r--r--client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestResource.java146
-rw-r--r--client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ParameterCheck.java211
-rw-r--r--client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/package-info.java27
-rw-r--r--client/client-deployment/src/main/resources/webapp/WEB-INF/web.xml46
-rw-r--r--client/client-deployment/src/main/resources/webapp/index.html87
-rw-r--r--client/client-deployment/src/main/resources/webapp/js/ApexAjax.js84
-rw-r--r--client/client-deployment/src/main/resources/webapp/js/ApexEngineService.js101
-rw-r--r--client/client-deployment/src/main/resources/webapp/js/ApexModelLoading.js63
-rw-r--r--client/client-deployment/src/main/resources/webapp/js/ApexServicesMain.js147
-rw-r--r--client/client-deployment/src/main/resources/webapp/js/ApexTable.js59
-rw-r--r--client/client-deployment/src/main/resources/webapp/js/ApexUtils.js212
-rw-r--r--client/client-deployment/src/main/resources/webapp/resources/16px/rowCollapsed_black_16px.svg19
-rw-r--r--client/client-deployment/src/main/resources/webapp/resources/16px/rowExpanded_black_16px.svg18
-rw-r--r--client/client-deployment/src/main/resources/webapp/resources/16px/settings_black_16px.svg20
-rw-r--r--client/client-deployment/src/main/resources/webapp/resources/systemBar/help_black.svg19
-rw-r--r--client/client-deployment/src/main/resources/webapp/resources/systemBar/logout_black.svg15
22 files changed, 2021 insertions, 0 deletions
diff --git a/client/client-deployment/pom.xml b/client/client-deployment/pom.xml
new file mode 100644
index 000000000..f4ecfe7af
--- /dev/null
+++ b/client/client-deployment/pom.xml
@@ -0,0 +1,191 @@
+<!--
+ ============LICENSE_START=======================================================
+ Copyright (C) 2018 Ericsson. 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.
+
+ 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.apex-pdp.client</groupId>
+ <artifactId>client</artifactId>
+ <version>2.0.0-SNAPSHOT</version>
+ </parent>
+
+ <artifactId>client-deployment</artifactId>
+ <name>${project.artifactId}</name>
+ <description>Web client for deploying models in Apex engine</description>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.onap.policy.apex-pdp.core</groupId>
+ <artifactId>core-deployment</artifactId>
+ <version>${project.version}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.onap.policy.apex-pdp.client</groupId>
+ <artifactId>client-common</artifactId>
+ <version>${project.version}</version>
+ <classifier>resources</classifier>
+ <type>zip</type>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.containers</groupId>
+ <artifactId>jersey-container-grizzly2-http</artifactId>
+ <version>${version.jersey}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.media</groupId>
+ <artifactId>jersey-media-multipart</artifactId>
+ <version>${version.jersey}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.containers</groupId>
+ <artifactId>jersey-container-servlet-core</artifactId>
+ <version>${version.jersey}</version>
+ </dependency>
+ <dependency>
+ <groupId>org.glassfish.jersey.inject</groupId>
+ <artifactId>jersey-hk2</artifactId>
+ <version>${version.jersey}</version>
+ </dependency>
+ <dependency>
+ <groupId>commons-cli</groupId>
+ <artifactId>commons-cli</artifactId>
+ <version>${version.commons-cli}</version>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <defaultGoal>install</defaultGoal>
+ <outputDirectory>${project.build.directory}/classes</outputDirectory>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-dependency-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>unpack-client-deployment-shared-resources</id>
+ <goals>
+ <goal>unpack-dependencies</goal>
+ </goals>
+ <phase>generate-resources</phase>
+ <configuration>
+ <outputDirectory>${project.build.directory}/${project.artifactId}-${project.version}</outputDirectory>
+ <includeArtifacIds>client-common</includeArtifacIds>
+ <includeGroupIds>${project.groupId}</includeGroupIds>
+ <excludeTransitive>true</excludeTransitive>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-shade-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>package</phase>
+ <goals>
+ <goal>shade</goal>
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <finalName>${project.artifactId}-uber-${project.version}</finalName>
+ <shadedArtifactAttached>true</shadedArtifactAttached>
+ <shadedClassifierName>deployment</shadedClassifierName>
+ <artifactSet>
+ <includes>
+ <include>*:*</include>
+ </includes>
+ </artifactSet>
+ <filters>
+ <filter>
+ <artifact>*:*</artifact>
+ <excludes>
+ <exclude>META-INF/*.SF</exclude>
+ <exclude>META-INF/*.DSA</exclude>
+ <exclude>META-INF/*.RSA</exclude>
+ </excludes>
+ </filter>
+ </filters>
+ <transformers>
+ <transformer
+ implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer" />
+ <transformer
+ implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+ <resource>reference.conf</resource>
+ </transformer>
+ <transformer
+ implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
+ <resource>log4j.properties</resource>
+ </transformer>
+ <transformer
+ implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+ <mainClass>org.onap.policy.apex.client.deployment.rest.ApexDeploymentRestMain</mainClass>
+ </transformer>
+ </transformers>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-war-plugin</artifactId>
+ <version>2.6</version>
+ <configuration>
+ <classifier>ui</classifier>
+ <warSourceDirectory>src/main/resources/webapp</warSourceDirectory>
+ <webXml>src/main/resources/webapp/WEB-INF/web.xml</webXml>
+ </configuration>
+ <executions>
+ <execution>
+ <phase>prepare-package</phase>
+ <goals>
+ <goal>war</goal>
+ </goals>
+ </execution>
+ </executions>
+ </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}-${project.version}-ui.war</file>
+ <type>war</type>
+ </artifact>
+ <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> \ No newline at end of file
diff --git a/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRest.java b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRest.java
new file mode 100644
index 000000000..b6ed37d80
--- /dev/null
+++ b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRest.java
@@ -0,0 +1,84 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.client.deployment.rest;
+
+import org.glassfish.grizzly.http.server.HttpServer;
+import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory;
+import org.glassfish.jersey.media.multipart.MultiPartFeature;
+import org.glassfish.jersey.server.ResourceConfig;
+import org.onap.policy.apex.model.utilities.Assertions;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * This class is used to launch the services. It creates a Grizzly embedded web server and runs the services.
+ */
+public class ApexDeploymentRest {
+ // Logger for this class
+ private static final XLogger logger = XLoggerFactory.getXLogger(ApexDeploymentRest.class);
+
+ // The HTTP server exposing JAX-RS resources defined in this application.
+ private HttpServer server;
+
+ /**
+ * Starts the HTTP server for the Apex services client on the default base URI and with the default REST packages
+ */
+ public ApexDeploymentRest() {
+ this(new ApexDeploymentRestParameters());
+ }
+
+ /**
+ * Starts the HTTP server for the Apex services client
+ *
+ * @param parameters: The Apex parameters to use to start the server
+ */
+ public ApexDeploymentRest(final ApexDeploymentRestParameters parameters) {
+ Assertions.argumentNotNull(parameters, "parameters may not be null");
+
+ logger.debug("Apex services RESTful client starting . . .");
+
+ // Create a resource configuration that scans for JAX-RS resources and providers
+ // in org.onap.policy.apex.client.deployment.rest package
+ final ResourceConfig rc = new ResourceConfig().packages(parameters.getRESTPackages());
+
+ // Add MultiPartFeature class for jersey-media-multipart
+ rc.register(MultiPartFeature.class);
+
+ // create and start a new instance of grizzly http server
+ // exposing the Jersey application at BASE_URI
+ server = GrizzlyHttpServerFactory.createHttpServer(parameters.getBaseURI(), rc);
+
+ // Add static content
+ server.getServerConfiguration().addHttpHandler(new org.glassfish.grizzly.http.server.CLStaticHttpHandler(
+ ApexDeploymentRestMain.class.getClassLoader(), "/webapp/"), parameters.getStaticPath());
+
+ logger.debug("Apex services RESTful client started");
+ }
+
+ /**
+ * Shut down the web server
+ */
+ public void shutdown() {
+ logger.debug("Apex services RESTful client shutting down . . .");
+ server.shutdown();
+ logger.debug("Apex services RESTful client shut down");
+ }
+}
diff --git a/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestMain.java b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestMain.java
new file mode 100644
index 000000000..6e7220487
--- /dev/null
+++ b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestMain.java
@@ -0,0 +1,192 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.client.deployment.rest;
+
+import java.io.PrintStream;
+
+/**
+ * User: ewatkmi Date: 31 Jul 2017
+ */
+public class ApexDeploymentRestMain {
+ // Services state
+ public enum ServicesState {
+ STOPPED, READY, INITIALIZING, RUNNING
+ };
+
+ private ServicesState state = ServicesState.STOPPED;
+
+ // The parameters for the client
+ private ApexDeploymentRestParameters parameters = null;
+
+ // Output and error streams for messages
+ private final PrintStream outStream;
+
+ // The Apex services client this class is running
+ private ApexDeploymentRest apexDeploymentRest = null;
+
+ /**
+ * Main method, main entry point for command
+ *
+ * @param args The command line arguments for the client
+ */
+ public static void main(final String[] args) {
+ try {
+ final ApexDeploymentRestMain restMain = new ApexDeploymentRestMain(args, System.out);
+ restMain.init();
+ } catch (final Exception e) {
+ System.err.println(e.getMessage());
+ }
+ }
+
+ /**
+ * Constructor, kicks off the rest service
+ *
+ * @param args The command line arguments for the RESTful service
+ * @param outStream The stream for output messages
+ */
+ public ApexDeploymentRestMain(final String[] args, final PrintStream outStream) {
+ // Save the streams for output and error
+ this.outStream = outStream;
+
+ // Client parameter parsing
+ final ApexDeploymentRestParameterParser parser = new ApexDeploymentRestParameterParser();
+
+ try {
+ // Get and check the parameters
+ parameters = parser.parse(args);
+ } catch (final ApexDeploymentRestParameterException e) {
+ throw new ApexDeploymentRestParameterException(
+ "Apex Services REST endpoint (" + this.toString() + ") parameter error, " + e.getMessage() + '\n'
+ + parser.getHelp(ApexDeploymentRestMain.class.getCanonicalName()));
+ }
+
+ if (parameters.isHelpSet()) {
+ throw new ApexDeploymentRestParameterException(
+ parser.getHelp(ApexDeploymentRestMain.class.getCanonicalName()));
+ }
+
+ // Validate the parameters
+ final String validationMessage = parameters.validate();
+ if (validationMessage.length() > 0) {
+ throw new ApexDeploymentRestParameterException(
+ "Apex Services REST endpoint (" + this.toString() + ") parameters invalid, " + validationMessage
+ + '\n' + parser.getHelp(ApexDeploymentRestMain.class.getCanonicalName()));
+ }
+
+ state = ServicesState.READY;
+ }
+
+ /**
+ * Initialize the rest service
+ */
+ public void init() {
+ outStream.println("Apex Services REST endpoint (" + this.toString() + ") starting at "
+ + parameters.getBaseURI().toString() + " . . .");
+
+ try {
+ state = ServicesState.INITIALIZING;
+
+ // Start the REST service
+ apexDeploymentRest = new ApexDeploymentRest(parameters);
+
+ // Add a shutdown hook to shut down the rest services when the process is exiting
+ Runtime.getRuntime().addShutdownHook(new Thread(new ApexServicesShutdownHook()));
+
+ state = ServicesState.RUNNING;
+
+ if (parameters.getTimeToLive() == ApexDeploymentRestParameters.INFINITY_TIME_TO_LIVE) {
+ outStream.println("Apex Services REST endpoint (" + this.toString() + ") started at "
+ + parameters.getBaseURI().toString());
+ } else {
+ outStream.println("Apex Services REST endpoint (" + this.toString() + ") started");
+ }
+
+ // Find out how long is left to wait
+ long timeRemaining = parameters.getTimeToLive();
+ while (timeRemaining == ApexDeploymentRestParameters.INFINITY_TIME_TO_LIVE || timeRemaining > 0) {
+ // decrement the time to live in the non-infinity case
+ if (timeRemaining > 0) {
+ timeRemaining--;
+ }
+
+ // Wait for a second
+ Thread.sleep(1000);
+ }
+ } catch (final Exception e) {
+ outStream.println(
+ "Apex Services REST endpoint (" + this.toString() + ") failed at with error: " + e.getMessage());
+ } finally {
+ if (apexDeploymentRest != null) {
+ apexDeploymentRest.shutdown();
+ apexDeploymentRest = null;
+ }
+ state = ServicesState.STOPPED;
+ }
+
+ }
+
+ /**
+ * Get services state.
+ *
+ * @return the service state
+ */
+ public ServicesState getState() {
+ return state;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder ret = new StringBuilder();
+ ret.append(this.getClass().getSimpleName()).append(": Config=[").append(this.parameters).append("], State=")
+ .append(this.getState());
+ return ret.toString();
+ }
+
+ /**
+ * Explicitly shut down the services
+ */
+ public void shutdown() {
+ if (apexDeploymentRest != null) {
+ outStream.println("Apex Services REST endpoint (" + this.toString() + ") shutting down");
+ apexDeploymentRest.shutdown();
+ }
+ state = ServicesState.STOPPED;
+ outStream.println("Apex Services REST endpoint (" + this.toString() + ") shut down");
+ }
+
+ /**
+ * This class is a shutdown hook for the Apex services command
+ */
+ private class ApexServicesShutdownHook implements Runnable {
+ /*
+ * (non-Javadoc)
+ *
+ * @see java.lang.Runnable#run()
+ */
+ @Override
+ public void run() {
+ if (apexDeploymentRest != null) {
+ apexDeploymentRest.shutdown();
+ }
+ }
+ }
+
+}
diff --git a/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestParameterException.java b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestParameterException.java
new file mode 100644
index 000000000..87785b7f3
--- /dev/null
+++ b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestParameterException.java
@@ -0,0 +1,49 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.client.deployment.rest;
+
+/**
+ * A run time exception used to report parsing and parameter input errors.
+ *
+ * User: ewatkmi Date: 31 Jul 2017
+ */
+public class ApexDeploymentRestParameterException extends IllegalArgumentException {
+ private static final long serialVersionUID = 6520231162404452427L;
+
+ /**
+ * Create an ApexServicesRestParameterException with a message
+ *
+ * @param message the message
+ */
+ public ApexDeploymentRestParameterException(final String message) {
+ super(message);
+ }
+
+ /**
+ * Create an ApexServicesRestParameterException with a message and an exception.
+ *
+ * @param message the message
+ * @param throwable The exception that caused the exception
+ */
+ public ApexDeploymentRestParameterException(final String message, final Throwable throwable) {
+ super(message, throwable);
+ }
+}
diff --git a/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestParameterParser.java b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestParameterParser.java
new file mode 100644
index 000000000..35ad9cdde
--- /dev/null
+++ b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestParameterParser.java
@@ -0,0 +1,116 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.client.deployment.rest;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Arrays;
+
+import org.apache.commons.cli.CommandLine;
+import org.apache.commons.cli.DefaultParser;
+import org.apache.commons.cli.HelpFormatter;
+import org.apache.commons.cli.Option;
+import org.apache.commons.cli.Options;
+import org.apache.commons.cli.ParseException;
+
+/**
+ * This class reads and handles command line parameters to the Apex RESTful services
+ *
+ * User: ewatkmi Date: 31 Jul 2017
+ */
+public class ApexDeploymentRestParameterParser {
+ // Apache Commons CLI options
+ Options options;
+
+ /**
+ * Construct the options for the CLI RESTful services
+ */
+ public ApexDeploymentRestParameterParser() {
+ options = new Options();
+ options.addOption("h", "help", false, "outputs the usage of this command");
+ options.addOption(Option.builder("p").longOpt("port").desc("port to use for the Apex Services REST calls")
+ .hasArg().argName("PORT").required(false).type(Number.class).build());
+ options.addOption(Option.builder("t").longOpt("time-to-live")
+ .desc("the amount of time in seconds that the server will run for before terminating").hasArg()
+ .argName("TIME_TO_LIVE").required(false).type(Number.class).build());
+ }
+
+ /**
+ * Parse the command line options
+ *
+ * @param args the arguments
+ * @return the parsed arguments
+ */
+ public ApexDeploymentRestParameters parse(final String[] args) {
+ CommandLine commandLine = null;
+ try {
+ commandLine = new DefaultParser().parse(options, args);
+ } catch (final ParseException e) {
+ throw new ApexDeploymentRestParameterException(
+ "invalid command line arguments specified : " + e.getMessage());
+ }
+
+ final ApexDeploymentRestParameters parameters = new ApexDeploymentRestParameters();
+ final String[] remainingArgs = commandLine.getArgs();
+
+ if (commandLine.getArgs().length > 0) {
+ throw new ApexDeploymentRestParameterException(
+ "too many command line arguments specified : " + Arrays.toString(remainingArgs));
+ }
+
+ if (commandLine.hasOption('h')) {
+ parameters.setHelp(true);
+ }
+ try {
+ if (commandLine.hasOption('p')) {
+ parameters.setRESTPort(((Number) commandLine.getParsedOptionValue("port")).intValue());
+ }
+ } catch (final ParseException e) {
+ throw new ApexDeploymentRestParameterException("error parsing argument \"port\" :" + e.getMessage(), e);
+ }
+ try {
+ if (commandLine.hasOption('t')) {
+ parameters.setTimeToLive(((Number) commandLine.getParsedOptionValue("time-to-live")).longValue());
+ }
+ } catch (final ParseException e) {
+ throw new ApexDeploymentRestParameterException("error parsing argument \"time-to-live\" :" + e.getMessage(),
+ e);
+ }
+
+ return parameters;
+ }
+
+ /**
+ * Get help information
+ *
+ * @param mainClassName the main class name for the help output
+ * @return help string
+ */
+ public String getHelp(final String mainClassName) {
+ final StringWriter stringWriter = new StringWriter();
+ final PrintWriter stringPrintWriter = new PrintWriter(stringWriter);
+
+ final HelpFormatter helpFormatter = new HelpFormatter();
+ helpFormatter.printHelp(stringPrintWriter, 120, mainClassName + " [options...] ", "", options, 0, 0, "");
+
+ return stringWriter.toString();
+ }
+}
diff --git a/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestParameters.java b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestParameters.java
new file mode 100644
index 000000000..6151506b8
--- /dev/null
+++ b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestParameters.java
@@ -0,0 +1,115 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.client.deployment.rest;
+
+import java.net.URI;
+
+/**
+ * This class reads and handles command line parameters to the Apex RESTful services
+ *
+ * User: ewatkmi Date: 31 Jul 2017
+ */
+public class ApexDeploymentRestParameters {
+ public static final int DEFAULT_REST_PORT = 18989;
+ public static final int INFINITY_TIME_TO_LIVE = -1;
+
+ // Base URI the HTTP server will listen on
+ private static final String DEFAULT_SERVER_URI_ROOT = "http://localhost:";
+ private static final String DEFAULT_REST_PATH = "/apexservices/";
+ private static final String DEFAULT_STATIC_PATH = "/";
+
+ // Package that will field REST requests
+ public static final String[] DEFAULT_PACKAGES =
+ new String[] { "com.ericsson.apex.services.client.deployment.rest" };
+
+ // The services parameters
+ private boolean helpSet = false;
+ private int restPort = DEFAULT_REST_PORT;
+ private long timeToLive = INFINITY_TIME_TO_LIVE;
+
+ public String validate() {
+ String validationMessage = "";
+ validationMessage += validatePort();
+ validationMessage += validateTimeToLive();
+
+ return validationMessage;
+ }
+
+ public URI getBaseURI() {
+ return URI.create(DEFAULT_SERVER_URI_ROOT + restPort + DEFAULT_REST_PATH);
+ }
+
+ public String[] getRESTPackages() {
+ return DEFAULT_PACKAGES;
+ }
+
+ public String getStaticPath() {
+ return DEFAULT_STATIC_PATH;
+ }
+
+ private String validatePort() {
+ if (restPort < 1024 || restPort > 65535) {
+ return "port must be greater than 1023 and less than 65536\n";
+ } else {
+ return "";
+ }
+ }
+
+ private String validateTimeToLive() {
+ if (timeToLive < -1) {
+ return "time to live must be greater than -1 (set to -1 to wait forever)\n";
+ } else {
+ return "";
+ }
+ }
+
+ public boolean isHelpSet() {
+ return helpSet;
+ }
+
+ public void setHelp(final boolean helpSet) {
+ this.helpSet = helpSet;
+ }
+
+ public int getRESTPort() {
+ return restPort;
+ }
+
+ public void setRESTPort(final int restPort) {
+ this.restPort = restPort;
+ }
+
+ public long getTimeToLive() {
+ return timeToLive;
+ }
+
+ public void setTimeToLive(final long timeToLive) {
+ this.timeToLive = timeToLive;
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder ret = new StringBuilder();
+ ret.append(this.getClass().getSimpleName()).append(": URI=").append(this.getBaseURI()).append(", TTL=")
+ .append(this.getTimeToLive()).append("sec");
+ return ret.toString();
+ }
+}
diff --git a/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestResource.java b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestResource.java
new file mode 100644
index 000000000..810b59cc1
--- /dev/null
+++ b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ApexDeploymentRestResource.java
@@ -0,0 +1,146 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.client.deployment.rest;
+
+import com.google.gson.JsonObject;
+
+import java.io.InputStream;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.QueryParam;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+
+import org.glassfish.jersey.media.multipart.FormDataContentDisposition;
+import org.glassfish.jersey.media.multipart.FormDataParam;
+import org.onap.policy.apex.core.deployment.ApexDeploymentException;
+import org.onap.policy.apex.core.deployment.EngineServiceFacade;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * The class represents the root resource exposed at the base URL<br>
+ * The url to access this resource would be in the form {@code <baseURL>/rest/....} <br>
+ * For example: a GET request to the following URL
+ * {@code http://localhost:18989/apexservices/rest/?hostName=localhost&port=12345}
+ *
+ * <b>Note:</b> An allocated {@code hostName} and {@code port} query parameter must be included in all requests.
+ * Datasets for different {@code hostName} are completely isolated from one another.
+ *
+ */
+@Path("deployment/")
+@Produces({ MediaType.APPLICATION_JSON })
+@Consumes({ MediaType.APPLICATION_JSON })
+
+public class ApexDeploymentRestResource {
+ // Get a reference to the logger
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexDeploymentRestResource.class);
+
+ /**
+ * Constructor, a new resource director is created for each request.
+ */
+ public ApexDeploymentRestResource() {}
+
+ /**
+ * Query the engine service for data
+ *
+ * @param hostName the host name of the engine service to connect to.
+ * @param port the port number of the engine service to connect to.
+ * @return a Response object containing the engines service, status and context data in JSON
+ */
+ @GET
+ public Response createSession(@QueryParam("hostName") final String hostName, @QueryParam("port") final int port) {
+ final String host = hostName + ":" + port;
+ final EngineServiceFacade engineServiceFacade = new EngineServiceFacade(hostName, port);
+
+ try {
+ engineServiceFacade.init();
+ } catch (final ApexDeploymentException e) {
+ final String errorMessage = "Error connecting to Apex Engine Service at " + host;
+ LOGGER.warn(errorMessage + "<br>", e);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage + "\n" + e.getMessage())
+ .build();
+ }
+
+ final JsonObject responseObject = new JsonObject();
+
+ // Engine Service data
+ responseObject.addProperty("engine_id", engineServiceFacade.getKey().getID());
+ responseObject.addProperty("model_id",
+ engineServiceFacade.getApexModelKey() != null ? engineServiceFacade.getApexModelKey().getID()
+ : "Not Set");
+ responseObject.addProperty("server", hostName);
+ responseObject.addProperty("port", Integer.toString(port));
+
+ return Response.ok(responseObject.toString(), MediaType.APPLICATION_JSON).build();
+ }
+
+ /**
+ * Upload a model.
+ *
+ * @param hostName the host name of the engine service to connect to.
+ * @param port the port number of the engine service to connect to.
+ * @param uploadedInputStream input stream
+ * @param fileDetail details on the file
+ * @param ignoreConflicts conflict policy
+ * @param forceUpdate update policy
+ * @return a response object in plain text confirming the upload was successful
+ */
+ @POST
+ @Path("modelupload/")
+ @Consumes(MediaType.MULTIPART_FORM_DATA)
+ public Response modelUpload(@FormDataParam("hostName") final String hostName, @FormDataParam("port") final int port,
+ @FormDataParam("file") final InputStream uploadedInputStream,
+ @FormDataParam("file") final FormDataContentDisposition fileDetail,
+ @FormDataParam("ignoreConflicts") final boolean ignoreConflicts,
+ @FormDataParam("forceUpdate") final boolean forceUpdate) {
+ final EngineServiceFacade engineServiceFacade = new EngineServiceFacade(hostName, port);
+
+ try {
+ engineServiceFacade.init();
+ } catch (final ApexDeploymentException e) {
+ final String errorMessage = "Error connecting to Apex Engine Service at " + hostName + ":" + port;
+ LOGGER.warn(errorMessage + "<br>", e);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage + "\n" + e.getMessage())
+ .build();
+ }
+
+ try {
+ engineServiceFacade.deployModel(fileDetail.getFileName(), uploadedInputStream, ignoreConflicts,
+ forceUpdate);
+ } catch (final Exception e) {
+ LOGGER.warn("Error updating model on engine service " + engineServiceFacade.getKey().getID(), e);
+ final String errorMessage =
+ "Error updating model on engine service " + engineServiceFacade.getKey().getID();
+ LOGGER.warn(errorMessage + "<br>", e);
+ return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage + "\n" + e.getMessage())
+ .build();
+ }
+
+ return Response.ok("Model " + fileDetail.getFileName() + " deployed on engine service "
+ + engineServiceFacade.getKey().getID()).build();
+ }
+
+}
diff --git a/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ParameterCheck.java b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ParameterCheck.java
new file mode 100644
index 000000000..87e76cdf7
--- /dev/null
+++ b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/ParameterCheck.java
@@ -0,0 +1,211 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.apex.client.deployment.rest;
+
+import java.util.Map;
+
+import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey;
+import org.slf4j.ext.XLogger;
+import org.slf4j.ext.XLoggerFactory;
+
+/**
+ * The Class ParameterCheck is used to check parameters passed to the servlet.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+public final class ParameterCheck {
+ private static final int MAX_PORT = 65535;
+
+ /**
+ * private constructor to prevent subclassing of this utility class.
+ */
+ private ParameterCheck() {}
+
+ /**
+ * The Enum StartStop is used to hold .
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+ public enum StartStop {
+ /** Start of an Apex engine has been ordered. */
+ START,
+ /** Stop of an Apex engine has been ordered. */
+ STOP
+ };
+
+ private static final XLogger LOGGER = XLoggerFactory.getXLogger(ParameterCheck.class);
+
+ private static final String HOSTNAME_PAR = "hostname";
+ private static final String PORT_PAR = "port";
+ private static final String AXARTIFACTKEY_PAR = "AxArtifactKey";
+
+ /**
+ * Gets the host name.
+ *
+ * @param parameterMap the parameter map
+ * @return the host name
+ */
+ public static String getHostName(final Map<String, String[]> parameterMap) {
+ if (!parameterMap.containsKey(HOSTNAME_PAR)) {
+ LOGGER.warn("parameter \"" + HOSTNAME_PAR + "\" not found");
+ return null;
+ }
+
+ final String[] hostNameValue = parameterMap.get(HOSTNAME_PAR);
+
+ if (hostNameValue.length == 0 || hostNameValue[0].trim().length() == 0) {
+ LOGGER.warn("value of parameter \"" + HOSTNAME_PAR + "\" not found");
+ return null;
+ }
+
+ return hostNameValue[0];
+ }
+
+ /**
+ * Gets the port.
+ *
+ * @param parameterMap the parameter map
+ * @return the port
+ */
+ public static int getPort(final Map<String, String[]> parameterMap) {
+ if (!parameterMap.containsKey(PORT_PAR)) {
+ LOGGER.warn("parameter \"" + PORT_PAR + "\" not found");
+ return -1;
+ }
+
+ final String[] portValue = parameterMap.get(PORT_PAR);
+
+ if (portValue.length == 0 || portValue[0].trim().length() == 0) {
+ LOGGER.warn("value of parameter \"" + PORT_PAR + "\" not found");
+ return -1;
+ }
+
+ int port = -1;
+ try {
+ port = Integer.parseInt(portValue[0]);
+ } catch (final Exception e) {
+ LOGGER.warn("value \"" + portValue[0] + "\"of parameter \"" + PORT_PAR + "\" not a valid integer", e);
+ return -1;
+ }
+
+ if (port <= 0 || port > MAX_PORT) {
+ LOGGER.warn("value \"" + portValue[0] + "\"of parameter \"" + PORT_PAR
+ + "\" not a valid port between 0 and 65535");
+ return -1;
+ }
+
+ return port;
+ }
+
+ /**
+ * Gets the engine key.
+ *
+ * @param parameterMap the parameter map
+ * @return the engine key
+ */
+ public static AxArtifactKey getEngineKey(final Map<String, String[]> parameterMap) {
+ String artifactKeyParameter = null;
+ for (final String parameter : parameterMap.keySet()) {
+ // Check for an AxArtifactKey parameter
+ if (parameter.startsWith(AXARTIFACTKEY_PAR)) {
+ artifactKeyParameter = parameter;
+ break;
+ }
+ }
+ if (artifactKeyParameter == null) {
+ LOGGER.warn("parameter \"" + AXARTIFACTKEY_PAR + "\" not found");
+ return null;
+ }
+
+ final String[] axArtifactKeyArray = artifactKeyParameter.split("#");
+
+ if (axArtifactKeyArray.length != 2) {
+ LOGGER.warn("value \"" + artifactKeyParameter + "\" of parameter \"" + AXARTIFACTKEY_PAR + "\" not valid");
+ return null;
+ }
+
+ return new AxArtifactKey(axArtifactKeyArray[1]);
+ }
+
+ /**
+ * Gets the start stop.
+ *
+ * @param parameterMap the parameter map
+ * @param engineKey the engine key
+ * @return the start stop
+ */
+ public static ParameterCheck.StartStop getStartStop(final Map<String, String[]> parameterMap,
+ final AxArtifactKey engineKey) {
+ final String startStopPar = AXARTIFACTKEY_PAR + '#' + engineKey.getID();
+ if (!parameterMap.containsKey(startStopPar)) {
+ LOGGER.warn("parameter \"" + startStopPar + "\" not found");
+ return null;
+ }
+
+ final String[] startStopValue = parameterMap.get(startStopPar);
+
+ if (startStopValue.length == 0 || startStopValue[0].trim().length() == 0) {
+ LOGGER.warn("value of parameter \"" + startStopPar + "\" not found");
+ return null;
+ }
+
+ ParameterCheck.StartStop startStop;
+ if (startStopValue[0].equalsIgnoreCase("start")) {
+ startStop = ParameterCheck.StartStop.START;
+ } else if (startStopValue[0].equalsIgnoreCase("stop")) {
+ startStop = ParameterCheck.StartStop.STOP;
+ } else {
+ LOGGER.warn("value \"" + startStopValue[0] + "\"of parameter \"" + startStopPar
+ + "\" not \"start\" or \"stop\"");
+ return null;
+ }
+
+ return startStop;
+ }
+
+ /**
+ * Find and return a long value with the given name.
+ *
+ * @param parameterMap The parameter map containing the value
+ * @param longName The name of the long parameter
+ * @return The long value
+ */
+ public static long getLong(final Map<String, String[]> parameterMap, final String longName) {
+ if (!parameterMap.containsKey(longName)) {
+ LOGGER.warn("parameter \"" + longName + "\" not found");
+ return -1;
+ }
+
+ final String[] longValue = parameterMap.get(longName);
+
+ if (longValue.length == 0 || longValue[0].trim().length() == 0) {
+ LOGGER.warn("value of parameter \"" + longName + "\" not found");
+ return -1;
+ }
+
+ try {
+ return Long.parseLong(longValue[0]);
+ } catch (final Exception e) {
+ LOGGER.warn("value \"" + longValue[0] + "\"of parameter \"" + longName + "\" not a valid long", e);
+ return -1;
+ }
+ }
+}
diff --git a/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/package-info.java b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/package-info.java
new file mode 100644
index 000000000..997e411a6
--- /dev/null
+++ b/client/client-deployment/src/main/java/org/onap/policy/apex/client/deployment/rest/package-info.java
@@ -0,0 +1,27 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/**
+ * Implements the RESTful deployment for Apex.
+ *
+ * @author Liam Fallon (liam.fallon@ericsson.com)
+ */
+
+package org.onap.policy.apex.client.deployment.rest;
diff --git a/client/client-deployment/src/main/resources/webapp/WEB-INF/web.xml b/client/client-deployment/src/main/resources/webapp/WEB-INF/web.xml
new file mode 100644
index 000000000..b79cf362a
--- /dev/null
+++ b/client/client-deployment/src/main/resources/webapp/WEB-INF/web.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ============LICENSE_START=======================================================
+ Copyright (C) 2016-2018 Ericsson. 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.
+
+ SPDX-License-Identifier: Apache-2.0
+ ============LICENSE_END=========================================================
+-->
+
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee"
+ xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
+ http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
+ id="WebApp_ID" version="3.0">
+
+ <servlet>
+ <servlet-name>apex-services.rest</servlet-name>
+ <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
+ <init-param>
+ <param-name>jersey.config.server.provider.packages</param-name>
+ <param-value>org.onap.policy.apex.client.deployment.rest</param-value>
+ </init-param>
+ <init-param>
+ <param-name>jersey.config.server.provider.classnames</param-name>
+ <param-value>org.glassfish.jersey.media.multipart.MultiPartFeature</param-value>
+ </init-param>
+ <load-on-startup>1</load-on-startup>
+ </servlet>
+ <servlet-mapping>
+ <servlet-name>apex-services.rest</servlet-name>
+ <url-pattern>/apexservices/*</url-pattern>
+ </servlet-mapping>
+
+</web-app> \ No newline at end of file
diff --git a/client/client-deployment/src/main/resources/webapp/index.html b/client/client-deployment/src/main/resources/webapp/index.html
new file mode 100644
index 000000000..2ae25f901
--- /dev/null
+++ b/client/client-deployment/src/main/resources/webapp/index.html
@@ -0,0 +1,87 @@
+<!--
+ ============LICENSE_START=======================================================
+ Copyright (C) 2016-2018 Ericsson. 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.
+
+ SPDX-License-Identifier: Apache-2.0
+ ============LICENSE_END=========================================================
+-->
+
+<html>
+<head>
+<meta charset="UTF-8">
+
+<title>Apex Deployment</title>
+
+<!-- interface style -->
+<link rel="stylesheet" type="text/css" href="css/interfaceAssets.css">
+<!-- ApexChartLib style -->
+<link rel="stylesheet" type="text/css" href="css/apexChartLib.css">
+<!-- Apex services client style -->
+<link rel="stylesheet" type="text/css" href="css/styles.css">
+
+<script type="text/javascript" src="js/ApexUtils.js"></script>
+
+</head>
+<body>
+
+ <!-- interface styled System Bar -->
+ <div class="ebSystemBar">
+ <div class="ebSystemBar-topMenuName">Apex</div>
+ <div class="ebSystemBar-config"></div>
+ </div>
+
+ <div class="layoutWrapper">
+
+ <div class="ebBreadcrumbs">
+ <div class="ebBreadcrumbs-item">
+ <a href="javascript:getHomepageURL();" class="ebBreadcrumbs-link">Apex</a>
+ </div>
+ <div class="ebBreadcrumbs-item">
+ <a href="" class="ebBreadcrumbs-link">Deployment</a>
+ </div>
+ </div>
+
+ <div class="appHeading">
+ <h1 class="title">Apex Deployment</h1>
+ </div>
+
+ <div class="search ebQuickActionBar"></div>
+
+ <!-- Main content div -->
+ <div id="content" class="content">
+
+ <!-- Engine Service -->
+ <h2>Engine Service</h2>
+ <div class="engineService"></div>
+
+ <!-- Apex Model Loading -->
+ <h2>Apex Model Loading</h2>
+ <div class="modelLoading"></div>
+
+ </div>
+ </div>
+
+ <!-- jQuery -->
+ <script src="jquery/jquery-1.12.4.js"></script>
+
+ <!-- Apex services client JS files -->
+ <script type="text/javascript" src="js/ApexAjax.js"></script>
+ <script type="text/javascript" src="js/ApexTable.js"></script>
+ <script type="text/javascript" src="js/ApexEngineService.js"></script>
+ <script type="text/javascript" src="js/ApexModelLoading.js"></script>
+ <script type="text/javascript" src="js/ApexServicesMain.js"></script>
+
+</body>
+</html>
diff --git a/client/client-deployment/src/main/resources/webapp/js/ApexAjax.js b/client/client-deployment/src/main/resources/webapp/js/ApexAjax.js
new file mode 100644
index 000000000..beb2cb11d
--- /dev/null
+++ b/client/client-deployment/src/main/resources/webapp/js/ApexAjax.js
@@ -0,0 +1,84 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Send a GET request
+ */
+function ajax_get(requestURL, callback, hostName, port, params, errorCallback) {
+ var data = {
+ hostName : hostName,
+ port : port
+ };
+ for ( var p in params) {
+ data[p] = params[p];
+ }
+ return $.ajax({
+ type : 'GET',
+ url : requestURL,
+ dataType : "json",
+ data : data,
+ success : function(data, textStatus, jqXHR) {
+ if (callback) {
+ callback(data);
+ }
+ },
+ error : function(jqXHR, textStatus, errorThrown) {
+ if (jqXHR.status == 500 || jqXHR.status == 404) {
+ if (jqXHR.responseText.indexOf("cound not handshake with server") !== -1 || jqXHR.status == 404) {
+ clearEngineURL();
+ getEngineURL(jqXHR.responseText);
+ } else {
+ apexErrorDialog_activate(document.body, jqXHR.responseText);
+ }
+ }
+ if (errorCallback) {
+ errorCallback(jqXHR, textStatus, errorThrown);
+ }
+ }
+ });
+}
+
+/*
+ * Send a POST request and add a file to its payload
+ */
+function ajax_upload(requestURL, callback, hostName, port, fileUrl, ignoreConflicts, forceUpdate) {
+ var formData = new FormData();
+ formData.append("hostName", hostName);
+ formData.append("port", port);
+ formData.append("file", fileUrl);
+ formData.append("ignoreConflicts", ignoreConflicts);
+ formData.append("forceUpdate", forceUpdate);
+ return $.ajax({
+ url : requestURL,
+ type : "POST",
+ contentType : false,
+ dataType : "text",
+ processData : false,
+ data : formData,
+ success : function(data, textStatus, jqXHR) {
+ callback(data);
+ },
+ error : function(jqXHR, textStatus, errorThrown) {
+ if (jqXHR.status == 500) {
+ apexErrorDialog_activate(document.body, jqXHR.responseText);
+ }
+ }
+ });
+}
diff --git a/client/client-deployment/src/main/resources/webapp/js/ApexEngineService.js b/client/client-deployment/src/main/resources/webapp/js/ApexEngineService.js
new file mode 100644
index 000000000..f47c98f07
--- /dev/null
+++ b/client/client-deployment/src/main/resources/webapp/js/ApexEngineService.js
@@ -0,0 +1,101 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Create the Engine Service Table
+ */
+function createEngineServiceTable() {
+ var tableId = config.engineService.tableId;
+ var headers = config.engineService.headers;
+ var table = createEngineTable($("." + config.engineService.parent), tableId, headers.map(function(a) {
+ return a.title;
+ }));
+ var tableRow = document.createElement("tr");
+ var tableData = "";
+ for ( var h in headers) {
+ tableData += "<td id=" + tableId + "_" + headers[h].id + "></td>";
+ }
+ tableRow.innerHTML = tableData;
+ var actionTD = $(tableRow).find("#" + tableId + "_periodic_events");
+ actionTD
+ .html('<input type="text" name="period" id="period" style="display:inline-block"><label class="ebSwitcher"><input type="checkbox" class="ebSwitcher-checkbox" /><div class="ebSwitcher-body"><div class="ebSwitcher-onLabel">Stopped</div><div class="ebSwitcher-switch"></div><div class="ebSwitcher-offLabel">Started</div></div></label>');
+ var period = actionTD.find("#period");
+ var switcher = actionTD.find(".ebSwitcher");
+ switcher.css('display', 'inline-block');
+ switcher.css('margin-left', '5px');
+ switcher.css('vertical-align', 'middle');
+ var checkbox = $(actionTD).find('input:checkbox:first');
+ checkbox.change(function(event) {
+ var startstop;
+ if (checkbox.prop('checked')) {
+ startstop = "Stop";
+ } else {
+ startstop = "Start";
+ }
+ this.servicesCall.abort();
+ ajax_get(restRootURL + "periodiceventstartstop", startStopCallback, this.engineURL.hostname,
+ this.engineURL.port, {
+ engineId : this.engineId,
+ startstop : startstop,
+ period : period.val()
+ }, resetPeriodicEvents);
+ }.bind(this));
+ $(table).children("#engineTableBody").append(tableRow);
+}
+
+/*
+ * Check for any changes in the Engine Service Table data and update only where
+ * necessary
+ */
+function setEngineServiceData(engineId, modelId, server, port, periodicEvents) {
+ this.engineId = engineId;
+ var tableId = config.engineService.tableId;
+ var headers = config.engineService.headers.map(function(a) {
+ return a.id;
+ });
+ var data = [ engineId, server + ":" + port, modelId ];
+
+ var engineServiceTable = $("#engineServicesTable");
+
+ for ( var h in headers) {
+ var td = engineServiceTable.find("#" + tableId + "_" + headers[h]);
+ if (td.html() !== data[h]) {
+ engineServiceTable.find("#" + tableId + "_" + headers[h]).html(data[h]);
+ }
+ }
+
+ var actionTD = engineServiceTable.find("#" + tableId + "_periodic_events");
+ var checkbox = $(actionTD).find('input:checkbox:first');
+ if (checkbox.is(":checked") === periodicEvents) {
+ checkbox.prop("checked", !checkbox.prop("checked"));
+ }
+}
+
+/*
+ * Resets the switcher for Periodic Events in the Engine Service Table
+ */
+function resetPeriodicEvents() {
+ var engineServiceTable = $("#engineServicesTable");
+ var periodicEventsTD = $(engineServiceTable).find("#engineServicesTable_periodic_events");
+ var checkbox = $(periodicEventsTD).find('input:checkbox:first');
+ if (checkbox.is(":checked")) {
+ checkbox.prop("checked", false);
+ }
+}
diff --git a/client/client-deployment/src/main/resources/webapp/js/ApexModelLoading.js b/client/client-deployment/src/main/resources/webapp/js/ApexModelLoading.js
new file mode 100644
index 000000000..8bd051f0f
--- /dev/null
+++ b/client/client-deployment/src/main/resources/webapp/js/ApexModelLoading.js
@@ -0,0 +1,63 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Create the div for uploading Apex models
+ */
+function createModelLoadingDiv() {
+ var fileLoader = document.createElement("input");
+ fileLoader.setAttribute("type", "file");
+ fileLoader.setAttribute("name", "apexModelFile");
+ fileLoader.setAttribute("label", "Load Apex Model XML file");
+ $('.modelLoading').append(fileLoader);
+
+ var ignoreConflictsCheckbox = document.createElement("input");
+ ignoreConflictsCheckbox.setAttribute("type", "checkbox");
+ ignoreConflictsCheckbox.setAttribute("name", "ignoreContextConflicts");
+ $('.modelLoading').append(ignoreConflictsCheckbox);
+
+ ignoreConflictsLabel = document.createElement("label");
+ ignoreConflictsLabel.setAttribute("class", "ignoreConflictsLabel");
+ ignoreConflictsLabel.innerHTML = "Ignore Context Conflicts";
+ $('.modelLoading').append(ignoreConflictsLabel);
+
+ var forceUpdateCheckbox = document.createElement("input");
+ forceUpdateCheckbox.setAttribute("type", "checkbox");
+ forceUpdateCheckbox.setAttribute("name", "forceUpdate");
+ $('.modelLoading').append(forceUpdateCheckbox);
+
+ forceUpdateLabel = document.createElement("label");
+ forceUpdateLabel.setAttribute("class", "ignoreConflictsLabel");
+ forceUpdateLabel.innerHTML = "Force Update";
+ $('.modelLoading').append(forceUpdateLabel);
+
+ var submitButton = document.createElement("button");
+ submitButton.setAttribute("class", "ebBtn");
+ submitButton.innerHTML = "Load Apex Model XML file";
+ $(submitButton).click(
+ function() {
+ var file = fileLoader.files[0];
+ var ignoreConflicts = $(ignoreConflictsCheckbox).is(":checked");
+ var forceUpdate = $(forceUpdateCheckbox).is(":checked");
+ ajax_upload(restRootURL + "modelupload/", uploadCallback, this.engineURL.hostname, this.engineURL.port,
+ file, ignoreConflicts, forceUpdate);
+ }.bind(this));
+ $('.modelLoading').append(submitButton);
+} \ No newline at end of file
diff --git a/client/client-deployment/src/main/resources/webapp/js/ApexServicesMain.js b/client/client-deployment/src/main/resources/webapp/js/ApexServicesMain.js
new file mode 100644
index 000000000..a54815ab3
--- /dev/null
+++ b/client/client-deployment/src/main/resources/webapp/js/ApexServicesMain.js
@@ -0,0 +1,147 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+var restRootURL;
+
+var config = {
+ refresh : 5000,
+ engineService : {
+ parent : "engineService",
+ tableId : "engineServicesTable",
+ headers : [ {
+ title : "Engine Service ID",
+ id : "engine_id"
+ }, {
+ title : "server:port",
+ id : "server_port"
+ }, {
+ title : "Model ID",
+ id : "model_id"
+ } ]
+ }
+}
+
+/*
+ * Callback for showing model info
+ */
+function servicesCallback(data) {
+ // If engine url in cookie has not been cleared
+ if (localStorage.getItem("apex-monitor-services")) {
+ setEngineServiceData(data.engine_id, data.model_id, data.server, data.port, data.periodic_events);
+
+ // Make content visible after data has been returned for the first time
+ if (!$(".content").is(':visible')) {
+ $(".content").fadeIn();
+ }
+
+ // Repeat the same request
+ setTimeout(function() {
+ this.servicesCall = ajax_get(restRootURL, servicesCallback, this.engineURL.hostname, this.engineURL.port);
+ }, config.refresh);
+ }
+}
+
+/*
+ * Callback for uploading a model
+ */
+function uploadCallback(response) {
+ // Open a dialog showing the response
+ apexSuccessDialog_activate(document.body, response);
+}
+
+/*
+ * Clears and resets all content on the page
+ */
+function setUpPage() {
+ // Clear each div
+ $('#content > div').each(function() {
+ $(this).empty();
+ });
+
+ // Set up content div's
+ createEngineServiceTable();
+ createModelLoadingDiv();
+}
+
+/*
+ * Retrieves the engine URL from the cookie. If it has not been set yet, then a
+ * dialog is shown asking for it
+ */
+function getEngineURL(message) {
+ // The engine URL is stored in a cookie using the key
+ // "apex-monitor-services"
+ var engineURL = localStorage.getItem("apex-monitor-services");
+
+ // This url is used to store the last known engine URL so that the user
+ // doesn't have to retype it every time
+ var oldEngineURL = localStorage.getItem("apex-monitor-services_old");
+
+ // If an engine URL is stored in the cookie
+ if (engineURL) {
+ // Parse the engine URL
+ this.engineURL = JSON.parse(engineURL);
+
+ // Send a request with that engine URL
+ this.servicesCall = ajax_get(restRootURL, servicesCallback, this.engineURL.hostname, this.engineURL.port);
+ } else {
+ // Prompt for engine URL
+ apexDialogForm_activate(document.body, message);
+ }
+}
+
+/*
+ * Clears the cookie and reset the page
+ */
+function clearEngineURL() {
+ // Remove engine URL from cookie
+ localStorage.removeItem("apex-monitor-services");
+
+ // Reset the page
+ setUpPage();
+}
+
+/*
+ * Called after the DOM is ready
+ */
+$(document).ready(
+ function() {
+ restRootURL = location.protocol
+ + "//"
+ + window.location.hostname
+ + (location.port ? ':' + location.port : '')
+ + (location.pathname.endsWith("/deployment/") ? location.pathname.substring(0, location.pathname
+ .indexOf("deployment/")) : location.pathname) + "apexservices/deployment/";
+
+ // Set up the structure of the page
+ setUpPage();
+
+ // Check cookies for engine URL
+ getEngineURL();
+
+ // Add click event to config icon for clearing engine URL
+ $(".ebSystemBar-config").click(function() {
+ // Clear the engine URL
+ clearEngineURL();
+
+ // Request the engine URL
+ getEngineURL();
+ });
+
+ }); \ No newline at end of file
diff --git a/client/client-deployment/src/main/resources/webapp/js/ApexTable.js b/client/client-deployment/src/main/resources/webapp/js/ApexTable.js
new file mode 100644
index 000000000..20e3d08bd
--- /dev/null
+++ b/client/client-deployment/src/main/resources/webapp/js/ApexTable.js
@@ -0,0 +1,59 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Create a table with given headers
+ */
+function createEngineTable(parent, id, tableHeaders) {
+ var table = createTable(id);
+
+ var tableHead = document.createElement("thead");
+ table.appendChild(tableHead);
+ tableHead.setAttribute("id", "engineTableHeader");
+
+ var tableHeaderRow = document.createElement("tr");
+ tableHead.appendChild(tableHeaderRow);
+ tableHeaderRow.setAttribute("id", "engineTableHeaderRow");
+
+ for ( var t in tableHeaders) {
+ var tableHeader = document.createElement("th");
+ tableHeaderRow.appendChild(tableHeader);
+ tableHeader.setAttribute("id", "engineTableHeader");
+ tableHeader.appendChild(document.createTextNode(tableHeaders[t]));
+ }
+
+ var tableBody = document.createElement("tbody");
+ tableBody.setAttribute("id", "engineTableBody");
+ table.appendChild(tableBody);
+
+ parent.append(table);
+
+ return table;
+}
+
+/*
+ * Create a table and apply UISDK styles to it
+ */
+function createTable(id) {
+ var table = document.createElement("table");
+ table.setAttribute("id", id);
+ table.setAttribute("class", "apexTable ebTable elTablelib-Table-table ebTable_striped");
+ return table;
+} \ No newline at end of file
diff --git a/client/client-deployment/src/main/resources/webapp/js/ApexUtils.js b/client/client-deployment/src/main/resources/webapp/js/ApexUtils.js
new file mode 100644
index 000000000..0f5e689fd
--- /dev/null
+++ b/client/client-deployment/src/main/resources/webapp/js/ApexUtils.js
@@ -0,0 +1,212 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2016-2018 Ericsson. 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.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+/*
+ * Crate a dialog with input, attach it to a given parent and show an optional message
+ */
+function apexDialogForm_activate(formParent, message) {
+ apexUtils_removeElement("apexDialogDiv");
+
+ var contentelement = document.createElement("apexDialogDiv");
+ var formDiv = document.createElement("div");
+ var backgroundDiv = document.createElement("div");
+ backgroundDiv.setAttribute("id", "apexDialogDivBackground");
+ backgroundDiv.setAttribute("class", "apexDialogDivBackground");
+
+ backgroundDiv.appendChild(formDiv);
+ contentelement.appendChild(backgroundDiv);
+ formParent.appendChild(contentelement);
+
+ formDiv.setAttribute("id", "apexDialogDiv");
+ formDiv.setAttribute("class", "apexDialogDiv");
+
+ var headingSpan = document.createElement("span");
+ formDiv.appendChild(headingSpan);
+
+ headingSpan.setAttribute("class", "headingSpan");
+ headingSpan.innerHTML = "Apex Engine Configuration";
+
+ var form = document.createElement("apexDialog");
+ formDiv.appendChild(form);
+
+ form.setAttribute("id", "apexDialog");
+ form.setAttribute("class", "form-style-1");
+ form.setAttribute("method", "post");
+
+ if (message) {
+ var messageLI = document.createElement("li");
+ messageLI.setAttribute("class", "dialogMessage");
+ messageLI.innerHTML = message;
+ form.appendChild(messageLI);
+ }
+
+ var urlLI = document.createElement("li");
+ form.appendChild(urlLI);
+
+ var urlLabel = document.createElement("label");
+ urlLI.appendChild(urlLabel);
+
+ urlLabel.setAttribute("for", "apexDialogUrlInput");
+ urlLabel.innerHTML = "Apex Engine rest URL:";
+
+ var urlLabelSpan = document.createElement("span");
+ urlLabel.appendChild(urlLabelSpan);
+
+ urlLabelSpan.setAttribute("class", "required");
+ urlLabelSpan.innerHTML = "*";
+
+ var engineUrl = localStorage.getItem("apex-monitor-services_old");
+
+ var urlInput = document.createElement("input");
+ urlInput.setAttribute("id", "services_url_input");
+ urlInput.setAttribute("placeholder", "localhost:12345");
+ urlInput.value = (engineUrl && engineUrl !== "null") ? JSON.parse(engineUrl).hostname + ":"
+ + JSON.parse(engineUrl).port : "";
+ urlLI.appendChild(urlInput);
+
+ var inputLI = document.createElement("li");
+ form.appendChild(inputLI);
+
+ var submitInput = document.createElement("input");
+ submitInput.setAttribute("id", "submit");
+ submitInput.setAttribute("class", "button ebBtn");
+ submitInput.setAttribute("type", "submit");
+ submitInput.setAttribute("value", "Submit");
+ submitInput.onclick = apexDialogForm_submitPressed;
+ inputLI.appendChild(submitInput);
+
+ // Enter key press triggers submit
+ $(urlInput).keyup(function(event) {
+ if (event.keyCode == 13) {
+ $(submitInput).click();
+ }
+ });
+
+ urlInput.focus();
+}
+
+/*
+ * Create a dialog for displaying text
+ */
+function apexTextDialog_activate(formParent, message, title) {
+ apexUtils_removeElement("apexDialogDiv");
+
+ var contentelement = document.createElement("div");
+ contentelement.setAttribute("id", "apexDialogDiv")
+ var formDiv = document.createElement("div");
+ var backgroundDiv = document.createElement("div");
+ backgroundDiv.setAttribute("id", "apexDialogDivBackground");
+ backgroundDiv.setAttribute("class", "apexDialogDivBackground");
+
+ backgroundDiv.appendChild(formDiv);
+ contentelement.appendChild(backgroundDiv);
+ formParent.appendChild(contentelement);
+
+ formDiv.setAttribute("id", "apexErrorDialogDiv");
+ formDiv.setAttribute("class", "apexDialogDiv apexErrorDialogDiv");
+
+ var headingSpan = document.createElement("span");
+ formDiv.appendChild(headingSpan);
+
+ headingSpan.setAttribute("class", "headingSpan");
+ headingSpan.innerHTML = title;
+
+ var form = document.createElement("div");
+ formDiv.appendChild(form);
+
+ form.setAttribute("id", "apexDialog");
+ form.setAttribute("class", "form-style-1");
+ form.setAttribute("method", "post");
+
+ if (message) {
+ var messageLI = document.createElement("li");
+ messageLI.setAttribute("class", "dialogMessage");
+ messageLI.innerHTML = message;
+ form.appendChild(messageLI);
+ }
+
+ var inputLI = document.createElement("li");
+ form.appendChild(inputLI);
+
+ var cancelInput = document.createElement("input");
+ cancelInput.setAttribute("class", "button ebBtn");
+ cancelInput.setAttribute("type", "submit");
+ cancelInput.setAttribute("value", "Close");
+ cancelInput.onclick = newModelForm_cancelPressed;
+ form.appendChild(cancelInput);
+}
+
+/*
+ * Create a Success dialog
+ */
+function apexSuccessDialog_activate(formParent, message) {
+ apexTextDialog_activate(formParent, message, "Success");
+}
+
+/*
+ * Create an Error dialog
+ */
+function apexErrorDialog_activate(formParent, message) {
+ apexTextDialog_activate(formParent, message, "Error");
+}
+
+/*
+ * Dialog cancel callback
+ */
+function newModelForm_cancelPressed() {
+ apexUtils_removeElement("apexDialogDivBackground");
+}
+
+/*
+ * Dialog submit callback
+ */
+function apexDialogForm_submitPressed() {
+ var url = $('#services_url_input').val();
+ if (url && url.length > 0) {
+ var engineConfig = {
+ hostname : url.split(":")[0],
+ port : url.split(":")[1]
+ };
+ localStorage.setItem("apex-monitor-services_old", JSON.stringify(engineConfig));
+ localStorage.setItem("apex-monitor-services", JSON.stringify(engineConfig));
+ apexUtils_removeElement("apexDialogDivBackground");
+ getEngineURL();
+ }
+}
+
+/*
+ * Remove an element from the page
+ */
+function apexUtils_removeElement(elementname) {
+ var element = document.getElementById(elementname);
+ if (element != null) {
+ element.parentNode.removeChild(element);
+ }
+}
+
+function getHomepageURL() {
+ var homepageURL = location.protocol
+ + "//"
+ + window.location.hostname
+ + (location.port ? ':' + location.port : '')
+ + (location.pathname.endsWith("/deployment/") ? location.pathname.substring(0, location.pathname
+ .indexOf("deployment/")) : location.pathname);
+ location.href = homepageURL;
+} \ No newline at end of file
diff --git a/client/client-deployment/src/main/resources/webapp/resources/16px/rowCollapsed_black_16px.svg b/client/client-deployment/src/main/resources/webapp/resources/16px/rowCollapsed_black_16px.svg
new file mode 100644
index 000000000..6878c863c
--- /dev/null
+++ b/client/client-deployment/src/main/resources/webapp/resources/16px/rowCollapsed_black_16px.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
+ <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
+]>
+<svg version="1.1"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
+ x="0px" y="0px" width="16px" height="16px" viewBox="13 2437.971 16 16" enable-background="new 13 2437.971 16 16"
+ xml:space="preserve">
+<defs>
+</defs>
+<rect display="none" fill="#66A19F" width="87" height="3280.97"/>
+<rect x="17" y="2441.97" fill="#FFFFFF" width="7" height="7"/>
+<path d="M24.5,2440.97c-0.275,0-7.725,0-8,0s-0.5,0.225-0.5,0.5s0,7.725,0,8s0.225,0.499,0.5,0.499c0.22,0,7.78,0,8,0
+ c0.275,0,0.5-0.223,0.5-0.499s0-7.725,0-8S24.775,2440.97,24.5,2440.97z M24,2448.97h-7v-7.001h7V2448.97z"/>
+<line fill="none" stroke="#000000" stroke-miterlimit="10" x1="18" y1="2445.47" x2="23" y2="2445.47"/>
+<line fill="none" stroke="#000000" stroke-miterlimit="10" x1="20.5" y1="2447.97" x2="20.5" y2="2442.971"/>
+<rect x="13" y="2437.97" display="none" opacity="0.2" fill="#E94E47" width="16" height="16"/>
+</svg>
diff --git a/client/client-deployment/src/main/resources/webapp/resources/16px/rowExpanded_black_16px.svg b/client/client-deployment/src/main/resources/webapp/resources/16px/rowExpanded_black_16px.svg
new file mode 100644
index 000000000..5e3e46a66
--- /dev/null
+++ b/client/client-deployment/src/main/resources/webapp/resources/16px/rowExpanded_black_16px.svg
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
+ <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
+]>
+<svg version="1.1"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
+ x="0px" y="0px" width="16px" height="16px" viewBox="13 2405.971 16 16" enable-background="new 13 2405.971 16 16"
+ xml:space="preserve">
+<defs>
+</defs>
+<rect display="none" fill="#66A19F" width="87" height="3280.97"/>
+<rect x="17" y="2409.97" fill="#FFFFFF" width="7" height="7"/>
+<path d="M24.5,2408.971c-0.275,0-7.725,0-8,0s-0.5,0.225-0.5,0.5s0,7.725,0,8s0.225,0.499,0.5,0.499c0.22,0,7.78,0,8,0
+ c0.275,0,0.5-0.223,0.5-0.499s0-7.725,0-8S24.775,2408.971,24.5,2408.971z M24,2416.971h-7v-7.001h7V2416.971z"/>
+<line fill="none" stroke="#000000" stroke-miterlimit="10" x1="18" y1="2413.471" x2="23" y2="2413.471"/>
+<rect x="13" y="2405.97" display="none" opacity="0.2" fill="#E94E47" width="16" height="16"/>
+</svg>
diff --git a/client/client-deployment/src/main/resources/webapp/resources/16px/settings_black_16px.svg b/client/client-deployment/src/main/resources/webapp/resources/16px/settings_black_16px.svg
new file mode 100644
index 000000000..c347888e9
--- /dev/null
+++ b/client/client-deployment/src/main/resources/webapp/resources/16px/settings_black_16px.svg
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" [
+ <!ENTITY ns_flows "http://ns.adobe.com/Flows/1.0/">
+]>
+<svg version="1.1"
+ xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:a="http://ns.adobe.com/AdobeSVGViewerExtensions/3.0/"
+ x="0px" y="0px" width="16px" height="16px" viewBox="13 101.971 16 16" enable-background="new 13 101.971 16 16"
+ xml:space="preserve">
+<defs>
+</defs>
+<rect display="none" fill="#66A19F" width="87" height="3280.97"/>
+<path d="M28,110.97v-2h-2.101c-0.13-0.638-0.383-1.229-0.73-1.754l1.488-1.488l-1.414-1.414l-1.488,1.488
+ c-0.524-0.347-1.117-0.601-1.755-0.731v-2.101h-2v2.101c-0.638,0.129-1.23,0.383-1.754,0.731l-1.488-1.488l-1.414,1.414l1.488,1.488
+ c-0.347,0.524-0.601,1.116-0.731,1.754H14v2h2.101c0.13,0.638,0.384,1.23,0.731,1.755l-1.488,1.488l1.414,1.414l1.488-1.488
+ c0.524,0.347,1.116,0.601,1.754,0.73v2.101h2v-2.101c0.638-0.129,1.23-0.383,1.754-0.731l1.489,1.489l1.414-1.414l-1.489-1.489
+ c0.347-0.524,0.601-1.116,0.731-1.754H28z M21,112.47c-1.381,0-2.5-1.119-2.5-2.5s1.119-2.5,2.5-2.5s2.5,1.119,2.5,2.5
+ S22.381,112.47,21,112.47z"/>
+<rect x="13" y="101.97" display="none" opacity="0.2" fill="#E94E47" width="16" height="16"/>
+</svg>
diff --git a/client/client-deployment/src/main/resources/webapp/resources/systemBar/help_black.svg b/client/client-deployment/src/main/resources/webapp/resources/systemBar/help_black.svg
new file mode 100644
index 000000000..14fdf5d35
--- /dev/null
+++ b/client/client-deployment/src/main/resources/webapp/resources/systemBar/help_black.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
+<path fill="#1D1D1B" d="M8,0C3.582,0,0,3.582,0,8s3.582,8,8,8s8-3.582,8-8S12.418,0,8,0z M8.608,12.149
+ c-0.205,0.183-0.442,0.273-0.711,0.273c-0.277,0-0.521-0.09-0.728-0.27c-0.207-0.181-0.311-0.433-0.311-0.756
+ c0-0.287,0.101-0.528,0.3-0.724c0.201-0.196,0.447-0.295,0.738-0.295c0.287,0,0.529,0.099,0.725,0.295
+ c0.196,0.195,0.295,0.437,0.295,0.724C8.917,11.717,8.813,11.967,8.608,12.149z M10.46,6.227c-0.123,0.229-0.27,0.427-0.439,0.594
+ C9.85,6.986,9.545,7.267,9.104,7.661c-0.122,0.111-0.22,0.208-0.293,0.292C8.738,8.038,8.684,8.114,8.647,8.185
+ c-0.036,0.069-0.063,0.14-0.083,0.209c-0.02,0.07-0.049,0.193-0.089,0.368C8.408,9.135,8.194,9.32,7.837,9.32
+ c-0.187,0-0.343-0.061-0.47-0.183C7.239,9.016,7.176,8.835,7.176,8.595c0-0.301,0.047-0.561,0.14-0.782
+ c0.093-0.22,0.217-0.413,0.371-0.58C7.84,7.067,8.048,6.869,8.31,6.64c0.229-0.201,0.395-0.352,0.497-0.454
+ c0.102-0.103,0.188-0.216,0.257-0.341c0.07-0.125,0.105-0.261,0.105-0.408c0-0.287-0.107-0.528-0.32-0.725S8.361,4.417,8.024,4.417
+ c-0.394,0-0.684,0.099-0.87,0.298C6.968,4.913,6.811,5.206,6.682,5.593C6.56,5.998,6.329,6.2,5.989,6.2
+ c-0.201,0-0.37-0.071-0.508-0.212C5.344,5.846,5.274,5.693,5.274,5.528c0-0.34,0.109-0.685,0.328-1.034
+ C5.82,4.146,6.14,3.856,6.559,3.627s0.907-0.344,1.466-0.344c0.52,0,0.978,0.096,1.375,0.287c0.397,0.192,0.705,0.452,0.922,0.782
+ c0.216,0.33,0.324,0.688,0.324,1.074C10.646,5.73,10.584,5.998,10.46,6.227z"/>
+</svg>
diff --git a/client/client-deployment/src/main/resources/webapp/resources/systemBar/logout_black.svg b/client/client-deployment/src/main/resources/webapp/resources/systemBar/logout_black.svg
new file mode 100644
index 000000000..af297acde
--- /dev/null
+++ b/client/client-deployment/src/main/resources/webapp/resources/systemBar/logout_black.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generator: Adobe Illustrator 15.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
+ width="16px" height="16px" viewBox="0 0 16 16" enable-background="new 0 0 16 16" xml:space="preserve">
+<g>
+ <g>
+ <path fill="#1D1D1B" d="M10.77,12.455c0,0-0.684,0.192-0.684-0.684c0-0.199,0-0.861,0-1.711H5.98
+ c-0.377,0-0.684-0.308-0.684-0.684V6.639c0-0.377,0.307-0.684,0.684-0.684h4.106c0-0.818,0-1.475,0-1.732
+ c0-0.919,0.684-0.662,0.684-0.662l5.133,4.447L10.77,12.455z"/>
+ </g>
+ <path fill="#1D1D1B" d="M9.85,14H3.099c-0.551,0-1-0.447-1-1V3c0-0.552,0.449-1,1-1H9.85V0H3.099c-1.656,0-3,1.344-3,3v10
+ c0,1.656,1.344,3,3,3H9.85V14z"/>
+</g>
+</svg>