diff options
author | 2018-07-06 16:29:16 +0100 | |
---|---|---|
committer | 2018-07-09 15:14:03 +0100 | |
commit | 0ba667816e703344eec33bda147546b30b6bbd5b (patch) | |
tree | da7f8e53a8ae1266717957eea7e95324cf3fe1d7 /client/client-monitoring/src/main/java | |
parent | dcf8f703fdd07161c86231ecc4af0f25872a45f4 (diff) |
Adding client monitoring module to apex-pdp
Change-Id: I6b4d00a5e49326f62f3585526ede8e89df99d7e5
Issue-ID: POLICY-864
Signed-off-by: ramverma <ram.krishna.verma@ericsson.com>
Diffstat (limited to 'client/client-monitoring/src/main/java')
8 files changed, 1136 insertions, 0 deletions
diff --git a/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRest.java b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRest.java new file mode 100644 index 000000000..d6f7e64ad --- /dev/null +++ b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRest.java @@ -0,0 +1,80 @@ +/*- + * ============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.monitoring.rest; + +import org.glassfish.grizzly.http.server.HttpServer; +import org.glassfish.jersey.grizzly2.httpserver.GrizzlyHttpServerFactory; +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 ApexMonitoringRest { + // Logger for this class + private static final XLogger logger = XLoggerFactory.getXLogger(ApexMonitoringRest.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 ApexMonitoringRest() { + this(new ApexMonitoringRestParameters()); + } + + /** + * Starts the HTTP server for the Apex services client + * + * @param parameters: The Apex parameters to use to start the server + */ + public ApexMonitoringRest(final ApexMonitoringRestParameters 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.services.client.monitoring.rest package + final ResourceConfig rc = new ResourceConfig().packages(parameters.getRESTPackages()); + + // 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( + ApexMonitoringRestMain.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-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestMain.java b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestMain.java new file mode 100644 index 000000000..fcc29ed29 --- /dev/null +++ b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestMain.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.monitoring.rest; + +import java.io.PrintStream; + +/** + * User: ewatkmi Date: 31 Jul 2017 + */ +public class ApexMonitoringRestMain { + // Services state + public enum ServicesState { + STOPPED, READY, INITIALIZING, RUNNING + }; + + private ServicesState state = ServicesState.STOPPED; + + // The parameters for the client + private ApexMonitoringRestParameters parameters = null; + + // Output and error streams for messages + private final PrintStream outStream; + + // The Apex services client this class is running + private ApexMonitoringRest apexMonitoringRest = 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 ApexMonitoringRestMain restMain = new ApexMonitoringRestMain(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 ApexMonitoringRestMain(final String[] args, final PrintStream outStream) { + // Save the streams for output and error + this.outStream = outStream; + + // Client parameter parsing + final ApexMonitoringRestParameterParser parser = new ApexMonitoringRestParameterParser(); + + try { + // Get and check the parameters + parameters = parser.parse(args); + } catch (final ApexMonitoringRestParameterException e) { + throw new ApexMonitoringRestParameterException( + "Apex Services REST endpoint (" + this.toString() + ") parameter error, " + e.getMessage() + '\n' + + parser.getHelp(ApexMonitoringRestMain.class.getCanonicalName())); + } + + if (parameters.isHelpSet()) { + throw new ApexMonitoringRestParameterException( + parser.getHelp(ApexMonitoringRestMain.class.getCanonicalName())); + } + + // Validate the parameters + final String validationMessage = parameters.validate(); + if (validationMessage.length() > 0) { + throw new ApexMonitoringRestParameterException( + "Apex Services REST endpoint (" + this.toString() + ") parameters invalid, " + validationMessage + + '\n' + parser.getHelp(ApexMonitoringRestMain.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 + apexMonitoringRest = new ApexMonitoringRest(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() == ApexMonitoringRestParameters.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 == ApexMonitoringRestParameters.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 (apexMonitoringRest != null) { + apexMonitoringRest.shutdown(); + apexMonitoringRest = 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 (apexMonitoringRest != null) { + outStream.println("Apex Services REST endpoint (" + this.toString() + ") shutting down"); + apexMonitoringRest.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 (apexMonitoringRest != null) { + apexMonitoringRest.shutdown(); + } + } + } + +} diff --git a/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestParameterException.java b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestParameterException.java new file mode 100644 index 000000000..cbbc2940a --- /dev/null +++ b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestParameterException.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.monitoring.rest; + +/** + * A run time exception used to report parsing and parameter input errors + * + * User: ewatkmi Date: 31 Jul 2017 + */ +public class ApexMonitoringRestParameterException extends IllegalArgumentException { + private static final long serialVersionUID = 6520231162404452427L; + + /** + * Create an ApexServicesRestParameterException with a message. + * + * @param message the message + */ + public ApexMonitoringRestParameterException(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 ApexMonitoringRestParameterException(final String message, final Throwable throwable) { + super(message, throwable); + } +} diff --git a/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestParameterParser.java b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestParameterParser.java new file mode 100644 index 000000000..35ee6b4fa --- /dev/null +++ b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestParameterParser.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.monitoring.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 ApexMonitoringRestParameterParser { + // Apache Commons CLI options + Options options; + + /** + * Construct the options for the CLI RESTful services + */ + public ApexMonitoringRestParameterParser() { + 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 parsed parameters + */ + public ApexMonitoringRestParameters parse(final String[] args) { + CommandLine commandLine = null; + try { + commandLine = new DefaultParser().parse(options, args); + } catch (final ParseException e) { + throw new ApexMonitoringRestParameterException( + "invalid command line arguments specified : " + e.getMessage()); + } + + final ApexMonitoringRestParameters parameters = new ApexMonitoringRestParameters(); + final String[] remainingArgs = commandLine.getArgs(); + + if (commandLine.getArgs().length > 0) { + throw new ApexMonitoringRestParameterException( + "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 ApexMonitoringRestParameterException("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 ApexMonitoringRestParameterException("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-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestParameters.java b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestParameters.java new file mode 100644 index 000000000..a1a8efc57 --- /dev/null +++ b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestParameters.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.monitoring.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 ApexMonitoringRestParameters { + 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[] { "org.onap.policy.apex.services.client.monitoring.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-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestResource.java b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestResource.java new file mode 100644 index 000000000..84f29dfe2 --- /dev/null +++ b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ApexMonitoringRestResource.java @@ -0,0 +1,346 @@ +/*- + * ============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.monitoring.rest; + +import com.google.gson.Gson; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +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.onap.policy.apex.core.deployment.ApexDeploymentException; +import org.onap.policy.apex.core.deployment.EngineServiceFacade; +import org.onap.policy.apex.model.basicmodel.concepts.ApexException; +import org.onap.policy.apex.model.basicmodel.concepts.AxArtifactKey; +import org.onap.policy.apex.model.enginemodel.concepts.AxEngineModel; +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("monitoring/") +@Produces({ MediaType.APPLICATION_JSON }) +@Consumes({ MediaType.APPLICATION_JSON }) + +public class ApexMonitoringRestResource { + // Get a reference to the logger + private static final XLogger LOGGER = XLoggerFactory.getXLogger(ApexMonitoringRestResource.class); + + // Set the maximum number of stored data entries to be stored for each engine + private static final int maxCachedEntries = 50; + + // Set up a map separated by host and engine for the data + private static final HashMap<String, HashMap<String, List<Counter>>> cache = + new HashMap<String, HashMap<String, List<Counter>>>(); + + // Set up a map separated by host for storing the state of periodic events + private static final HashMap<String, Boolean> periodicEventsStateCache = new HashMap<String, Boolean>(); + + /** + * Constructor, a new resource director is created for each request. + */ + public ApexMonitoringRestResource() {} + + /** + * 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 Gson gson = new Gson(); + 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)); + responseObject.addProperty("periodic_events", getPeriodicEventsState(host)); + + // Engine Status data + final JsonArray engineStatusList = new JsonArray(); + + for (final AxArtifactKey engineKey : engineServiceFacade.getEngineKeyArray()) { + try { + final JsonObject engineStatusObject = new JsonObject(); + final AxEngineModel axEngineModel = engineServiceFacade.getEngineStatus(engineKey); + engineStatusObject.addProperty("timestamp", axEngineModel.getTimeStampString()); + engineStatusObject.addProperty("id", engineKey.getID()); + engineStatusObject.addProperty("status", axEngineModel.getState().toString()); + engineStatusObject.addProperty("last_message", axEngineModel.getStats().getTimeStampString()); + engineStatusObject.addProperty("up_time", axEngineModel.getStats().getUpTime() / 1000L); + engineStatusObject.addProperty("policy_executions", axEngineModel.getStats().getEventCount()); + engineStatusObject.addProperty("last_policy_duration", + gson.toJson( + getValuesFromCache(host, engineKey.getID() + "_last_policy_duration", + axEngineModel.getTimestamp(), axEngineModel.getStats().getLastExecutionTime()), + List.class)); + engineStatusObject.addProperty("average_policy_duration", + gson.toJson(getValuesFromCache(host, engineKey.getID() + "_average_policy_duration", + axEngineModel.getTimestamp(), + (long) axEngineModel.getStats().getAverageExecutionTime()), List.class)); + engineStatusList.add(engineStatusObject); + } catch (final ApexException e) { + LOGGER.warn("Error getting status of engine with ID " + engineKey.getID() + "<br>", e); + } + } + responseObject.add("status", engineStatusList); + + // Engine context data + final JsonArray engineContextList = new JsonArray(); + for (final AxArtifactKey engineKey : engineServiceFacade.getEngineKeyArray()) { + try { + final String engineInfo = engineServiceFacade.getEngineInfo(engineKey); + if (engineInfo != null && !engineInfo.trim().isEmpty()) { + final JsonObject engineContextObject = new JsonObject(); + engineContextObject.addProperty("id", engineKey.getID()); + engineContextObject.addProperty("engine_info", engineInfo); + engineContextList.add(engineContextObject); + } + } catch (final ApexException e) { + LOGGER.warn("Error getting runtime information of engine with ID " + engineKey.getID() + "<br>", e); + } + } + responseObject.add("context", engineContextList); + + return Response.ok(responseObject.toString(), MediaType.APPLICATION_JSON).build(); + } + + /** + * Start/Stop and Apex engine + * + * @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 engineId the id of the engine to be started/stopped. + * @param startStop the parameter to start/stop the engine. Expects either "Start" or "Stop" + * @return a Response object of type 200 + */ + @GET + @Path("startstop/") + public Response startStop(@QueryParam("hostName") final String hostName, @QueryParam("port") final int port, + @QueryParam("engineId") final String engineId, @QueryParam("startstop") final String startStop) { + 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 { + final Map<String, String[]> parameterMap = new HashMap<String, String[]>(); + parameterMap.put("hostname", new String[] { hostName }); + parameterMap.put("port", new String[] { Integer.toString(port) }); + parameterMap.put("AxArtifactKey#" + engineId, new String[] { startStop }); + final AxArtifactKey engineKey = ParameterCheck.getEngineKey(parameterMap); + if (startStop.equals("Start")) { + engineServiceFacade.startEngine(engineKey); + } else if (startStop.equals("Stop")) { + engineServiceFacade.stopEngine(engineKey); + } + } catch (final Exception e) { + final String errorMessage = "Error calling " + startStop + " on Apex Engine: " + engineId; + LOGGER.warn(errorMessage + "<br>", e); + final StringWriter sw = new StringWriter(); + e.printStackTrace(new PrintWriter(sw)); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(errorMessage + "\n" + sw.toString()) + .build(); + } + + return Response.ok("{}").build(); + } + + /** + * Start/Stop and Apex engine + * + * @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 engineId the id of the engine to be started/stopped. + * @param startStop the parameter to start/stop the engine. Expects either "Start" or "Stop" + * @param period the time between each event in milliseconds + * @return a Response object of type 200 + */ + @GET + @Path("periodiceventstartstop/") + public Response periodiceventStartStop(@QueryParam("hostName") final String hostName, + @QueryParam("port") final int port, @QueryParam("engineId") final String engineId, + @QueryParam("startstop") final String startStop, @QueryParam("period") final long period) { + final EngineServiceFacade engineServiceFacade = new EngineServiceFacade(hostName, port); + final String host = hostName + ":" + port; + try { + engineServiceFacade.init(); + final Map<String, String[]> parameterMap = new HashMap<String, String[]>(); + parameterMap.put("hostname", new String[] { hostName }); + parameterMap.put("port", new String[] { Integer.toString(port) }); + parameterMap.put("AxArtifactKey#" + engineId, new String[] { startStop }); + parameterMap.put("period", new String[] { Long.toString(period) }); + final AxArtifactKey engineKey = ParameterCheck.getEngineKey(parameterMap); + if (startStop.equals("Start")) { + engineServiceFacade.startPerioidicEvents(engineKey, period); + setPeriodicEventsState(host, true); + } else if (startStop.equals("Stop")) { + engineServiceFacade.stopPerioidicEvents(engineKey); + setPeriodicEventsState(host, false); + } + } 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(); + } + + return Response.ok("{}").build(); + } + + /** + * Check if periodic events are running + * + * @param host the engine's host url + * @return a boolean stating if periodic events are running for a given host + */ + private Boolean getPeriodicEventsState(final String host) { + return periodicEventsStateCache.containsKey(host) ? periodicEventsStateCache.get(host) : false; + } + + /** + * Sets the state of periodic events for a host + * + * @param host the engine's host url + * @param boolean that states if periodic events have been started or stopped + */ + private void setPeriodicEventsState(final String host, final Boolean isRunning) { + periodicEventsStateCache.put(host, isRunning); + } + + /** + * This method takes in the latest data entry for an engine, adds it to an existing data set and returns the full + * map for that host and engine + * + * @param host the engine's host url + * @param id the engines id + * @param timestamp the timestamp of the latest data entry + * @param latestValue the value of the latest data entry + * @return a list of {@code Counter} objects for that engine + */ + private List<Counter> getValuesFromCache(final String host, final String id, final long timestamp, + final long latestValue) { + SlidingWindowList<Counter> valueList; + + if (!cache.containsKey(host)) { + cache.put(host, new HashMap<String, List<Counter>>()); + } + + if (cache.get(host).containsKey(id)) { + valueList = (SlidingWindowList<Counter>) cache.get(host).get(id); + } else { + valueList = new SlidingWindowList<Counter>(maxCachedEntries); + } + valueList.add(new Counter(timestamp, latestValue)); + + cache.get(host).put(id, valueList); + + return valueList; + } + + /** + * A list of values that uses a FIFO sliding window of a fixed size. + */ + public class SlidingWindowList<V> extends LinkedList<V> { + private static final long serialVersionUID = -7187277916025957447L; + + private final int maxEntries; + + public SlidingWindowList(final int maxEntries) { + this.maxEntries = maxEntries; + } + + @Override + public boolean add(final V e) { + if (this.size() > (maxEntries - 1)) { + this.removeFirst(); + } + return super.add(e); + }; + + } + + /** + * A class used to storing a single data entry for an engine. + */ + public class Counter { + private long timestamp; + private long value; + + public Counter(final long timestamp, final long value) { + this.timestamp = timestamp; + this.value = value; + } + + public long getTimestamp() { + return timestamp; + } + + public long getValue() { + return value; + } + } +} diff --git a/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ParameterCheck.java b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/ParameterCheck.java new file mode 100644 index 000000000..8edeb54f1 --- /dev/null +++ b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/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.monitoring.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-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/package-info.java b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/rest/package-info.java new file mode 100644 index 000000000..d6c8d3c5e --- /dev/null +++ b/client/client-monitoring/src/main/java/org/onap/policy/apex/client/monitoring/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 monitoring client. + * + * @author Liam Fallon (liam.fallon@ericsson.com) + */ + +package org.onap.policy.apex.client.monitoring.rest; |