diff options
author | Jorge Hernandez <jh1730@att.com> | 2017-09-07 00:07:32 -0500 |
---|---|---|
committer | Jorge Hernandez <jh1730@att.com> | 2017-09-07 00:22:38 -0500 |
commit | f6679d84b20e79e8f9753fbdea08ecd20b913e75 (patch) | |
tree | d8b001488ade0002828a8bb829c06f31500f289e /policy-management/src/main/java/org | |
parent | 40d0d77001e5a36e6fe799b9e1fbc26752c5c6f5 (diff) |
Support environment configurations
This enables PDP-D to have knowledge of any installation
property or else configured via OS environment variable
or as an environment file.
This allows the user to query or set via REST API of programmatically
through PolicyEngine any environment variable.
It also provides a means to make data globally available to all
drools applications.
For example:
http://localhost:9696/policy/pdp/engine/environment> get
HTTP/1.1 200 OK
Content-Length: 749
Content-Type: application/json
Date: Wed, 06 Sep 2017 23:53:57 GMT
Server: Jetty(9.3.14.v20161028)
{
"DCAE_SERVERS": "",
"DCAE_TOPIC": "",
"DMAAP_SERVERS": "",
"ENGINE_MANAGEMENT_HOST": "0.0.0.0",
"ENGINE_MANAGEMENT_PASSWORD": "",
"ENGINE_MANAGEMENT_PORT": "9696",
"ENGINE_MANAGEMENT_USER": "",
"HEALTHCHECK_PASSWORD": "",
"HEALTHCHECK_USER": "",
"JAVA_HOME": "/usr/lib/jvm/java-8-oracle",
"M2_HOME": "/usr/share/maven",
"PAP_HOST": "",
"PAP_PASSWORD": "",
"PAP_USERNAME": "",
"PDPD_CONFIGURATION_API_KEY": "",
"PDPD_CONFIGURATION_API_SECRET": "",
"PDPD_CONFIGURATION_CONSUMER_GROUP": "",
"PDPD_CONFIGURATION_CONSUMER_INSTANCE": "",
"PDPD_CONFIGURATION_PARTITION_KEY": "",
"PDPD_CONFIGURATION_SERVERS": "",
"PDPD_CONFIGURATION_TOPIC": "PDPD-CONFIGURATION",
"PDP_HOST": "",
"PDP_PASSWORD": "",
"PDP_USERNAME": "",
"POLICY_HOME": "/home/policy/snapshot",
"SQL_HOST": "",
"SQL_PASSWORD": "",
"SQL_USER": ""
}
policy@newton:~/snapshot/config$ echo -n "http://one.com/aai" | http --verbose PUT :9696/policy/pdp/engine/environment/AAI_URL Content-Type:text/plain Accept:text/plain
PUT /policy/pdp/engine/environment/AAI_URL HTTP/1.1
Accept: text/plain
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 18
Content-Type: text/plain
Host: localhost:9696
User-Agent: HTTPie/0.9.2
http://one.com/aai
HTTP/1.1 200 OK
Content-Length: 0
Content-Type: text/plain
Date: Thu, 07 Sep 2017 00:05:05 GMT
Server: Jetty(9.3.14.v20161028)
policy@newton:~/snapshot/config$ echo -n "http://one.com/aai2" | http --verbose PUT :9696/policy/pdp/engine/environment/AAI_URL Content-Type:text/plain Accept:text/plain
PUT /policy/pdp/engine/environment/AAI_URL HTTP/1.1
Accept: text/plain
Accept-Encoding: gzip, deflate
Connection: keep-alive
Content-Length: 19
Content-Type: text/plain
Host: localhost:9696
User-Agent: HTTPie/0.9.2
http://one.com/aai2
HTTP/1.1 200 OK
Content-Length: 18
Content-Type: text/plain
Date: Thu, 07 Sep 2017 00:05:45 GMT
Server: Jetty(9.3.14.v20161028)
http://one.com/aai
policy@newton:~/snapshot/config$ http :9696/policy/pdp/engine/environment/AAI_URL
HTTP/1.1 200 OK
Content-Length: 19
Content-Type: application/json
Date: Thu, 07 Sep 2017 05:14:57 GMT
Server: Jetty(9.3.14.v20161028)
http://one.com/aai2
Change-Id: I1fcd610938af751977bb2db925b57b4e5b3f7ba4
Issue-ID: POLICY-162
Signed-off-by: Jorge Hernandez <jh1730@att.com>
Diffstat (limited to 'policy-management/src/main/java/org')
5 files changed, 3866 insertions, 4007 deletions
diff --git a/policy-management/src/main/java/org/onap/policy/drools/persistence/FileSystemPersistence.java b/policy-management/src/main/java/org/onap/policy/drools/persistence/FileSystemPersistence.java new file mode 100644 index 00000000..5ac17253 --- /dev/null +++ b/policy-management/src/main/java/org/onap/policy/drools/persistence/FileSystemPersistence.java @@ -0,0 +1,300 @@ +/*- + * ============LICENSE_START======================================================= + * policy-management + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.policy.drools.persistence; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.onap.policy.drools.properties.PolicyProperties; +import org.onap.policy.drools.utils.PropertyUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Properties based Persistence + */ +public class FileSystemPersistence implements SystemPersistence { + /** + * policy controllers suffix + */ + public final static String CONTROLLER_SUFFIX_IDENTIFIER = "-controller"; + + /** + * policy controller properties file suffix + */ + public final static String PROPERTIES_FILE_CONTROLLER_SUFFIX = + CONTROLLER_SUFFIX_IDENTIFIER + ".properties"; + + /** + * policy controller properties file suffix + */ + public final static String PROPERTIES_FILE_CONTROLLER_BACKUP_SUFFIX = + CONTROLLER_SUFFIX_IDENTIFIER + ".properties.bak"; + + /** + * policy engine properties file name + */ + public final static String PROPERTIES_FILE_ENGINE = "policy-engine.properties"; + + /** + * Installation environment suffix for files + */ + public final static String ENV_SUFFIX = ".environment"; + + /** + * configuration directory + */ + protected Path configurationDirectory = Paths.get(DEFAULT_CONFIGURATION_DIR); + + /** + * logger + */ + private static final Logger logger = LoggerFactory.getLogger(FileSystemPersistence.class); + + + @Override + public void setConfigurationDir(String configDir) { + if (configDir == null) { + configDir = DEFAULT_CONFIGURATION_DIR; + this.configurationDirectory = Paths.get(DEFAULT_CONFIGURATION_DIR); + } + + if (!configDir.equals(DEFAULT_CONFIGURATION_DIR)) + this.configurationDirectory = Paths.get(configDir); + + if (Files.notExists(this.configurationDirectory)) { + try { + Files.createDirectories(this.configurationDirectory); + } catch (final IOException e) { + throw new IllegalStateException("cannot create " + this.configurationDirectory, e); + } + } + + if (!Files.isDirectory(this.configurationDirectory)) + throw new IllegalStateException( + "config directory: " + this.configurationDirectory + " is not a directory"); + } + + @Override + public Path getConfigurationPath() { + return this.configurationDirectory; + } + + @Override + public Properties getEngineProperties() { + final Path policyEnginePath = + Paths.get(this.configurationDirectory.toString(), PROPERTIES_FILE_ENGINE); + try { + if (Files.exists(policyEnginePath)) + return PropertyUtil.getProperties(policyEnginePath.toFile()); + } catch (final Exception e) { + logger.warn("{}: could not find {}", this, policyEnginePath, e); + } + + return null; + } + + @Override + public boolean backupController(String controllerName) { + final Path controllerPropertiesPath = Paths.get(this.configurationDirectory.toString(), + controllerName + PROPERTIES_FILE_CONTROLLER_SUFFIX); + + if (Files.exists(controllerPropertiesPath)) { + try { + logger.info("{}: there is an existing configuration file @ {} ", this, + controllerPropertiesPath); + final Path controllerPropertiesBakPath = Paths.get(this.configurationDirectory.toString(), + controllerName + PROPERTIES_FILE_CONTROLLER_BACKUP_SUFFIX); + Files.copy(controllerPropertiesPath, controllerPropertiesBakPath, + StandardCopyOption.REPLACE_EXISTING); + } catch (final Exception e) { + logger.warn("{}: {} cannot be backed up", this, controllerName, e); + return false; + } + } + + return true; + } + + @Override + public boolean storeController(String controllerName, Object configuration) { + if (!(configuration instanceof Properties)) + throw new IllegalArgumentException( + "configuration must be of type properties to be handled by this manager"); + + final Properties properties = (Properties) configuration; + + final Path controllerPropertiesPath = Paths.get(this.configurationDirectory.toString(), + controllerName + PROPERTIES_FILE_CONTROLLER_SUFFIX); + if (Files.exists(controllerPropertiesPath)) { + try { + final Properties oldProperties = + PropertyUtil.getProperties(controllerPropertiesPath.toFile()); + if (oldProperties.equals(properties)) { + logger.info( + "{}: noop: a properties file with the same contents exists for controller {}.", this, + controllerName); + return true; + } else { + this.backupController(controllerName); + } + } catch (final Exception e) { + logger.info("{}: no existing {} properties", this, controllerName); + // continue + } + } + + final File controllerPropertiesFile = controllerPropertiesPath.toFile(); + try (FileWriter writer = new FileWriter(controllerPropertiesFile)) { + properties.store(writer, "Machine created Policy Controller Configuration"); + } catch (final Exception e) { + logger.warn("{}: {} cannot be saved", this, controllerName, e); + return false; + } + + return true; + } + + @Override + public boolean deleteController(String controllerName) { + final Path controllerPropertiesPath = Paths.get(this.configurationDirectory.toString(), + controllerName + PROPERTIES_FILE_CONTROLLER_SUFFIX); + + if (Files.exists(controllerPropertiesPath)) { + try { + final Path controllerPropertiesBakPath = Paths.get(this.configurationDirectory.toString(), + controllerName + PROPERTIES_FILE_CONTROLLER_BACKUP_SUFFIX); + Files.move(controllerPropertiesPath, controllerPropertiesBakPath, + StandardCopyOption.REPLACE_EXISTING); + } catch (final Exception e) { + logger.warn("{}: {} cannot be deleted", this, controllerName, e); + return false; + } + } + + return true; + } + + @Override + public Properties getControllerProperties(String controllerName) { + return this.getProperties(controllerName + CONTROLLER_SUFFIX_IDENTIFIER); + } + + @Override + public List<Properties> getControllerProperties() { + final List<Properties> controllers = new ArrayList<>(); + final File[] controllerFiles = this.configurationDirectory.toFile().listFiles(); + for (final File controllerFile : controllerFiles) { + if (controllerFile.getName().endsWith(PROPERTIES_FILE_CONTROLLER_SUFFIX)) { + final int idxSuffix = controllerFile.getName().indexOf(PROPERTIES_FILE_CONTROLLER_SUFFIX); + final int lastIdxSuffix = + controllerFile.getName().lastIndexOf(PROPERTIES_FILE_CONTROLLER_SUFFIX); + if (idxSuffix != lastIdxSuffix) + throw new IllegalArgumentException( + "Improper naming of controller properties file: " + "Expected <controller-name>" + + FileSystemPersistence.PROPERTIES_FILE_CONTROLLER_SUFFIX); + + final String name = controllerFile.getName().substring(0, lastIdxSuffix); + try { + final Properties controllerProperties = this.getControllerProperties(name); + final String controllerName = + controllerProperties.getProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME); + if (controllerName == null) { + controllerProperties.setProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME, name); + } else if (!controllerName.equals(name)) { + logger.error("{}: mismatch controller named {} with file name {}", this, controllerName, + controllerFile.getName()); + continue; + } + controllers.add(this.getControllerProperties(name)); + } catch (final Exception e) { + logger.error("{}: cannot obtain properties for controller {} because of {}", name, + e.getMessage(), e); + } + } + } + return controllers; + } + + @Override + public Properties getProperties(String name) { + final Path propertiesPath = + Paths.get(this.configurationDirectory.toString(), name + ".properties"); + + if (!Files.exists(propertiesPath)) { + throw new IllegalArgumentException("properties for " + name + " are not persisted."); + } + + try { + return PropertyUtil.getProperties(propertiesPath.toFile()); + } catch (final Exception e) { + logger.warn("{}: can't read properties @ {}", name, propertiesPath); + throw new IllegalArgumentException( + "can't read properties for " + name + " @ " + propertiesPath, e); + } + } + + @Override + public List<Properties> getEnvironmentProperties() { + final List<Properties> envs = new ArrayList<>(); + final File[] envFiles = this.configurationDirectory.toFile().listFiles(); + for (final File envFile : envFiles) { + if (envFile.getName().endsWith(ENV_SUFFIX)) { + final String name = envFile.getName().substring(0, envFile.getName().indexOf(ENV_SUFFIX)); + try { + envs.add(this.getEnvironmentProperties(name)); + } catch (final Exception e) { + logger.error("{}: cannot get environment {} because of {}", name, e.getMessage(), e); + } + } + } + return envs; + } + + @Override + public Properties getEnvironmentProperties(String name) { + final Path envPath = Paths.get(this.configurationDirectory.toString(), name + ENV_SUFFIX); + if (!Files.exists(envPath)) { + throw new IllegalArgumentException("{} environment" + name + " cannot be retrieved"); + } + + try { + return PropertyUtil.getProperties(envPath.toFile()); + } catch (final Exception e) { + throw new IllegalArgumentException("cannot read environment " + name, e); + } + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("FileSystemPersistence [configurationDirectory=") + .append(this.configurationDirectory).append("]"); + return builder.toString(); + } +} diff --git a/policy-management/src/main/java/org/onap/policy/drools/persistence/SystemPersistence.java b/policy-management/src/main/java/org/onap/policy/drools/persistence/SystemPersistence.java index 2390fc89..eb1521ba 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/persistence/SystemPersistence.java +++ b/policy-management/src/main/java/org/onap/policy/drools/persistence/SystemPersistence.java @@ -7,9 +7,9 @@ * 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. @@ -20,230 +20,113 @@ package org.onap.policy.drools.persistence; -import java.io.File; -import java.io.FileWriter; -import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; +import java.util.List; import java.util.Properties; -import org.onap.policy.drools.utils.PropertyUtil; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - +/** + * System Configuration + */ public interface SystemPersistence { - - /** - * configuration directory - */ - public static String CONFIG_DIR_NAME = "config"; - - /** - * policy controllers suffix - */ - public final static String CONTROLLER_SUFFIX_IDENTIFIER = "-controller"; - - /** - * policy controller properties file suffix - */ - public final static String PROPERTIES_FILE_CONTROLLER_SUFFIX = - CONTROLLER_SUFFIX_IDENTIFIER + ".properties"; - - /** - * policy engine properties file name - */ - public final static String PROPERTIES_FILE_ENGINE = "policy-engine.properties"; - - - /** - * backs up a controller configuration. - * - * @param controllerName the controller name - * @return true if the configuration is backed up - */ - public boolean backupController(String controllerName); - - /** - * persists controller configuration - * - * @param controllerName the controller name - * @param configuration object containing the configuration - * - * @return true if storage is succesful, false otherwise - * @throws IllegalArgumentException if the configuration cannot be handled by the persistence manager - */ - public boolean storeController(String controllerName, Object configuration); - - /** - * delete controller configuration - * - * @param controllerName the controller name - * @return true if storage is succesful, false otherwise - */ - public boolean deleteController(String controllerName); - - /** - * get controller properties - * - * @param controllerName controller name - * @return properties for this controller - * - * @throws IllegalArgumentException if the controller name does not lead to a properties configuration - */ - public Properties getControllerProperties(String controllerName); - - /** - * get properties by name - * - * @param name - * @return properties - * - * @throws IllegalArgumentException if the name does not lead to a properties configuration - */ - public Properties getProperties(String name); - - /** - * Persistence Manager. For now it is a file-based properties management, - * In the future, it will probably be DB based, so manager implementation - * will change. - */ - public static final SystemPersistence manager = new SystemPropertiesPersistence(); -} + /** + * configuration directory + */ + public static final String DEFAULT_CONFIGURATION_DIR = "config"; -/** - * Properties based Persistence - */ -class SystemPropertiesPersistence implements SystemPersistence { - - /** - * logger - */ - private static Logger logger = LoggerFactory.getLogger(SystemPropertiesPersistence.class); - - /** - * backs up the properties-based controller configuration - * @param controllerName the controller name - * @return true if the configuration is backed up in disk or back up does not apply, false otherwise. - */ - @Override - public boolean backupController(String controllerName) { - Path controllerPropertiesPath = - Paths.get(CONFIG_DIR_NAME, controllerName + PROPERTIES_FILE_CONTROLLER_SUFFIX); - - if (Files.exists(controllerPropertiesPath)) { - try { - logger.warn("There is an existing configuration file at " + - controllerPropertiesPath.toString() + - " with contents: " + Files.readAllBytes(controllerPropertiesPath)); - Path controllerPropertiesBakPath = - Paths.get(CONFIG_DIR_NAME, controllerName + - PROPERTIES_FILE_CONTROLLER_SUFFIX + ".bak"); - Files.copy(controllerPropertiesPath, - controllerPropertiesBakPath, StandardCopyOption.REPLACE_EXISTING); - } catch (Exception e) { - logger.warn("{}: cannot be backed up", controllerName, e); - return false; - } - } - - return true; - } - - /** - * persists properties-based controller configuration and makes a backup if necessary - * @param controllerName the controller name - * @return true if the properties has been stored in disk, false otherwise - */ - @Override - public boolean storeController(String controllerName, Object configuration) { - if (!(configuration instanceof Properties)) { - throw new IllegalArgumentException("configuration must be of type properties to be handled by this manager"); - } - - Properties properties = (Properties) configuration; - - Path controllerPropertiesPath = - Paths.get(CONFIG_DIR_NAME, controllerName + PROPERTIES_FILE_CONTROLLER_SUFFIX); - if (Files.exists(controllerPropertiesPath)) { - try { - Properties oldProperties = PropertyUtil.getProperties(controllerPropertiesPath.toFile()); - if (oldProperties.equals(properties)) { - logger.info("A properties file with the same contents already exists for controller " + - controllerName + - ". No action is taken"); - return true; - } else { - this.backupController(controllerName); - } - } catch (Exception e) { - logger.info("{}: no existing Properties", controllerName); - // continue - } - } - - File controllerPropertiesFile = controllerPropertiesPath.toFile(); - try (FileWriter writer = new FileWriter(controllerPropertiesFile)) { - properties.store(writer, "Machine created Policy Controller Configuration"); - } catch (Exception e) { - logger.warn("{}: cannot be STORED", controllerName, e); - return false; - } - - return true; - } - - /** - * deletes properties-based controller configuration - * @param controllerName the controller name - * - * @return true if the properties has been deleted from disk, false otherwise - */ - @Override - public boolean deleteController(String controllerName) { - - Path controllerPropertiesPath = - Paths.get(CONFIG_DIR_NAME, - controllerName + PROPERTIES_FILE_CONTROLLER_SUFFIX); + /** + * sets a configuration directory and ensures it exists + * + * @param configDir configuration directory or null to use the default one + */ + public void setConfigurationDir(String configDir); + + /** + * get configuration directory path + * + * @return configuration directory path + */ + public Path getConfigurationPath(); + + /** + * backs up a controller configuration. + * + * @param controllerName the controller name + * @return true if the configuration is backed up + */ + public boolean backupController(String controllerName); + + /** + * persists controller configuration + * + * @param controllerName the controller name + * @param configuration object containing the configuration + * + * @return true if storage is succesful, false otherwise + * @throws IllegalArgumentException if the configuration cannot be handled by the persistence + * manager + */ + public boolean storeController(String controllerName, Object configuration); + + /** + * delete controller configuration + * + * @param controllerName the controller name + * @return true if storage is succesful, false otherwise + */ + public boolean deleteController(String controllerName); + + /** + * get controller properties + * + * @param controllerName controller name + * @return properties for this controller + * + * @throws IllegalArgumentException if the controller name does not lead to a properties + * configuration + */ + public Properties getControllerProperties(String controllerName); + + /** + * get controllers configuration + * + * @return list of controllers properties + */ + public List<Properties> getControllerProperties(); + + /** + * get environments + * + * @param environment name + */ + public List<Properties> getEnvironmentProperties(); + + /** + * get environment properties + * + * @param environment name + */ + public Properties getEnvironmentProperties(String environmentName); - if (Files.exists(controllerPropertiesPath)) { - try { - Path controllerPropertiesBakPath = - Paths.get(CONFIG_DIR_NAME, controllerName + - PROPERTIES_FILE_CONTROLLER_SUFFIX + ".bak"); - Files.move(controllerPropertiesPath, - controllerPropertiesBakPath, - StandardCopyOption.REPLACE_EXISTING); - } catch (Exception e) { - logger.warn("{}: cannot be DELETED", controllerName, e); - return false; - } - } - - return true; - } + /** + * get the engine properties + * + * @return the engine properties + */ + public Properties getEngineProperties(); - @Override - public Properties getControllerProperties(String controllerName) { - return this.getProperties(controllerName + CONTROLLER_SUFFIX_IDENTIFIER); - } - - @Override - public Properties getProperties(String name) { - Path propertiesPath = - Paths.get(CONFIG_DIR_NAME, name + ".properties"); - - if (!Files.exists(propertiesPath)) { - throw new IllegalArgumentException("properties for " + name + " are not persisted."); - } + /** + * get properties by name + * + * @param name + * @return properties + * + * @throws IllegalArgumentException if the name does not lead to a properties configuration + */ + public Properties getProperties(String name); - try { - return PropertyUtil.getProperties(propertiesPath.toFile()); - } catch (Exception e) { - logger.warn("{}: can't read properties @ {}", name, propertiesPath); - throw new IllegalArgumentException("can't read properties for " + - name + " @ " + - propertiesPath, e); - } - } + /** + * Persistence Manager. For now it is a file-based properties management, In the future, it will + * probably be DB based, so manager implementation will change. + */ + public static final SystemPersistence manager = new FileSystemPersistence(); } diff --git a/policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java b/policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java index 379ca6a2..ffcb35cd 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java +++ b/policy-management/src/main/java/org/onap/policy/drools/server/restful/RestManager.java @@ -7,9 +7,9 @@ * 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. @@ -63,6 +63,7 @@ import org.onap.policy.drools.protocol.configuration.ControllerConfiguration; import org.onap.policy.drools.protocol.configuration.PdpdConfiguration; import org.onap.policy.drools.system.PolicyController; import org.onap.policy.drools.system.PolicyEngine; +import org.onap.policy.drools.utils.LoggerUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -86,2351 +87,2004 @@ import io.swagger.annotations.Tag; @Consumes(MediaType.APPLICATION_JSON) @Api @SwaggerDefinition( - info = @Info( - description = "PDP-D Telemetry Services", - version = "v1.0", - title = "PDP-D Telemetry" - ), + info = @Info(description = "PDP-D Telemetry Services", version = "v1.0", + title = "PDP-D Telemetry"), consumes = {MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN}, - produces = {MediaType.APPLICATION_JSON}, - schemes = {SwaggerDefinition.Scheme.HTTP}, - tags = { - @Tag(name = "pdp-d-telemetry", description = "Drools PDP Telemetry Operations") - } -) + produces = {MediaType.APPLICATION_JSON}, schemes = {SwaggerDefinition.Scheme.HTTP}, + tags = {@Tag(name = "pdp-d-telemetry", description = "Drools PDP Telemetry Operations")}) public class RestManager { - /** - * Logger - */ - private static Logger logger = LoggerFactory.getLogger(RestManager.class); - - @GET - @Path("engine") - @ApiOperation( - value="Retrieves the Engine Operational Status", - notes="Top-level abstraction. Provides a global view of resources", - response=PolicyEngine.class - ) - public Response engine() { - return Response.status(Response.Status.OK).entity(PolicyEngine.manager).build(); - } - - @DELETE - @Path("engine") - @ApiOperation( - value="Shuts down the Engine", - notes="Deleting the engine, the top-level abstraction, equivalenty shuts it down", - response=PolicyEngine.class - ) - public Response engineShutdown() { - try { - PolicyEngine.manager.shutdown(); - } catch (IllegalStateException e) { - logger.error("{}: cannot shutdown {} because of {}", this, PolicyEngine.manager, e.getMessage(), e); - return Response.status(Response.Status.BAD_REQUEST). - entity(PolicyEngine.manager). - build(); - } - - return Response.status(Response.Status.OK). - entity(PolicyEngine.manager). - build(); - } - - @GET - @Path("engine/features") - @ApiOperation( - value="Engine Features", - notes="Provides the list of loaded features using the PolicyEngineFeatureAPI", - responseContainer="List" - ) - public Response engineFeatures() { - return Response.status(Response.Status.OK).entity(PolicyEngine.manager.getFeatures()).build(); - } - - @GET - @Path("engine/features/inventory") - @ApiOperation( - value="Engine Detailed Feature Inventory", - notes="Provides detailed list of loaded features using the PolicyEngineFeatureAPI", - responseContainer="List", - response=PolicyEngineFeatureAPI.class - ) - public Response engineFeaturesInventory() { - return Response.status(Response.Status.OK).entity(PolicyEngine.manager.getFeatureProviders()).build(); - } - - @GET - @Path("engine/features/{featureName}") - @ApiOperation( - value="Engine Feature", - notes="Provides Details for a given feature Engine Provider", - response=PolicyEngineFeatureAPI.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message = "The feature cannot be found") - }) - public Response engineFeature(@ApiParam(value="Feature Name", required=true) - @PathParam("featureName") String featureName) { - try { - return Response.status(Response.Status.OK). - entity(PolicyEngine.manager.getFeatureProvider(featureName)).build(); - } catch(IllegalArgumentException iae) { - logger.debug("feature unavailable: {}", featureName, iae); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(iae.getMessage())).build(); - } - } - - @GET - @Path("engine/inputs") - @ApiOperation( - value="Engine Input Ports", - notes="List of input ports", - responseContainer="List" - ) - public Response engineInputs() { - return Response.status(Response.Status.OK). - entity(Arrays.asList(Inputs.values())). - build(); - } - - @POST - @Path("engine/inputs/configuration") - @ApiOperation( - value="Engine Input Configuration Requests", - notes="Feeds a configuration request input into the Engine" - ) - @ApiResponses(value={ - @ApiResponse(code=406, message = "The configuration request cannot be honored") - }) - public Response engineUpdate( - @ApiParam(value="Configuration to apply", required=true) PdpdConfiguration configuration) { - PolicyController controller = null; - boolean success = true; - try { - success = PolicyEngine.manager.configure(configuration); - } catch (Exception e) { - success = false; - logger.info("{}: cannot configure {} because of {}", this, PolicyEngine.manager, e.getMessage(), e); - } - - if (!success) - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error("cannot perform operation")).build(); - else - return Response.status(Response.Status.OK).entity(controller).build(); - } - - @GET - @Path("engine/properties") - @ApiOperation( - value="Engine Configuration Properties", - notes="Used for booststrapping the engine", - response=Properties.class - ) - public Response engineProperties() { - return Response.status(Response.Status.OK).entity(PolicyEngine.manager.getProperties()).build(); - } - - @GET - @Path("engine/switches") - @ApiOperation( - value="Engine Control Switches", - notes="List of the Engine Control Switches", - responseContainer="List" - ) - public Response engineSwitches() { - return Response.status(Response.Status.OK). - entity(Arrays.asList(Switches.values())). - build(); - } - - @PUT - @Path("engine/switches/activation") - @ApiOperation( - value="Switches on the Engine Activation Switch", - notes="Turns on Activation Switch on the Engine. This order entails that the engine " + - "and controllers are unlocked and started", - response=PolicyEngine.class - ) - public Response engineActivation() { - boolean success = true; - try { - PolicyEngine.manager.activate(); - } catch (Exception e) { - success = false; - logger.info("{}: cannot activate {} because of {}", this, PolicyEngine.manager, e.getMessage(), e); - } - - if (!success) - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error("cannot perform operation")).build(); - else - return Response.status(Response.Status.OK).entity(PolicyEngine.manager).build(); - } - - @DELETE - @Path("engine/switches/activation") - @ApiOperation( - value="Switches off Engine Activation Switch", - notes="Turns off the Activation Switch on the Engine. This order entails that the engine " + - "and controllers are locked (with the exception of those resources defined as unmanaged)", - response=PolicyEngine.class - ) - public Response engineDeactivation() { - boolean success = true; - try { - PolicyEngine.manager.deactivate(); - } catch (Exception e) { - success = false; - logger.info("{}: cannot deactivate {} because of {}", this, PolicyEngine.manager, e.getMessage(), e); - } - - if (!success) - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error("cannot perform operation")).build(); - else - return Response.status(Response.Status.OK).entity(PolicyEngine.manager).build(); - } - - @PUT - @Path("engine/switches/lock") - @ApiOperation( - value="Switches on the Engine Lock Control", - notes="This switch locks all the engine resources as a whole, except those that are defined unmanaged", - response=PolicyEngine.class - ) - @ApiResponses(value = { - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response engineLock() { - boolean success = PolicyEngine.manager.lock(); - if (success) - return Response.status(Status.OK). - entity(PolicyEngine.manager). - build(); - else - return Response.status(Status.NOT_ACCEPTABLE). - entity(new Error("cannot perform operation")). - build(); - } - - @DELETE - @Path("engine/switches/lock") - @ApiOperation( - value="Switches off the Lock control", - notes="This switch locks all the engine resources as a whole, except those that are defined unmanaged", - response=PolicyEngine.class - ) - @ApiResponses(value = { - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response engineUnlock() { - boolean success = PolicyEngine.manager.unlock(); - if (success) - return Response.status(Status.OK). - entity(PolicyEngine.manager). - build(); - else - return Response.status(Status.NOT_ACCEPTABLE). - entity(new Error("cannot perform operation")). - build(); - } - - @GET - @Path("engine/controllers") - @ApiOperation( - value="Lists the Policy Controllers Names", - notes="Unique Policy Controller Identifiers", - responseContainer="List" - ) - public Response controllers() { - return Response.status(Response.Status.OK).entity(PolicyEngine.manager.getPolicyControllerIds()).build(); - } - - @GET - @Path("engine/controllers/inventory") - @ApiOperation( - value="Lists the Policy Controllers", - notes="Detailed list of Policy Controllers", - responseContainer="List", - response=PolicyController.class - ) - public Response controllerInventory() { - return Response.status(Response.Status.OK).entity(PolicyEngine.manager.getPolicyControllers()).build(); - } - - @POST - @Path("engine/controllers") - @ApiOperation( - value="Creates and starts a new Policy Controller", - notes="Controller creation based on properties", - response=PolicyController.class - ) - @ApiResponses(value = { - @ApiResponse(code=400, message = "Invalid configuration information has been provided"), - @ApiResponse(code=304, message = "The controller already exists"), - @ApiResponse(code=406, message = "The administrative state of the system prevents it " + - "from processing this request"), - @ApiResponse(code=206, message = "The controller has been created " + - "but cannot be started"), - @ApiResponse(code=201, message = "The controller has been succesfully created and started") - }) - public Response controllerAdd(@ApiParam(value="Configuration Properties to apply", required = true) - Properties config) { - if (config == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error("A configuration must be provided")). - build(); - - String controllerName = config.getProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME); - if (controllerName == null || controllerName.isEmpty()) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error - ("Configuration must have an entry for " + - PolicyProperties.PROPERTY_CONTROLLER_NAME)). - build(); - - PolicyController controller; - try { - controller = PolicyController.factory.get(controllerName); - if (controller != null) - return Response.status(Response.Status.NOT_MODIFIED). - entity(controller). - build(); - } catch (IllegalArgumentException e) { - // This is OK - } catch (IllegalStateException e) { - logger.info("{}: cannot get policy-controller because of {}", this, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + " not found")).build(); - } - - try { - controller = PolicyEngine.manager.createPolicyController - (config.getProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME), config); - } catch (IllegalArgumentException | IllegalStateException e) { - logger.warn("{}: cannot create policy-controller because of {}", this, e.getMessage(), e); - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(e.getMessage())). - build(); - } - - try { - boolean success = controller.start(); - if (!success) { - logger.info("{}: cannot start {}", this, controller); - return Response.status(Response.Status.PARTIAL_CONTENT). - entity(new Error(controllerName + " can't be started")).build(); - } - } catch (IllegalStateException e) { - logger.info("{}: cannot start {} because of {}", this, controller, e.getMessage(), e);; - return Response.status(Response.Status.PARTIAL_CONTENT). - entity(controller).build(); - } - - return Response.status(Response.Status.CREATED). - entity(controller). - build(); - } - - @GET - @Path("engine/controllers/features") - @ApiOperation( - value="Lists of Feature Providers Identifiers", - notes="Unique Policy Controller Identifiers", - responseContainer="List" - ) - public Response controllerFeatures() { - return Response.status(Response.Status.OK).entity(PolicyEngine.manager.getFeatures()).build(); - } - - @GET - @Path("engine/controllers/features/inventory") - @ApiOperation( - value="Detailed Controllers Feature Inventory", - notes="Provides detailed list of loaded features using the PolicyControllerFeatureAPI", - responseContainer="List", - response=PolicyControllerFeatureAPI.class - ) - public Response controllerFeaturesInventory() { - return Response.status(Response.Status.OK). - entity(PolicyController.factory.getFeatureProviders()). - build(); - } - - @GET - @Path("engine/controllers/features/{featureName}") - @ApiOperation( - value="Controller Feature", - notes="Provides Details for a given Policy Controller feature provider", - response=PolicyControllerFeatureAPI.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message = "The feature cannot be found") - }) - public Response controllerFeature(@ApiParam(value="Feature Name", required=true) - @PathParam("featureName") String featureName) { - try { - return Response.status(Response.Status.OK). - entity(PolicyController.factory.getFeatureProvider(featureName)). - build(); - } catch(IllegalArgumentException iae) { - logger.debug("{}: cannot feature {} because of {}", this, featureName, iae.getMessage(), iae); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(iae.getMessage())).build(); - } - } + /** + * Logger + */ + private static Logger logger = LoggerFactory.getLogger(RestManager.class); - @GET - @Path("engine/controllers/{controller}") - @ApiOperation( - value="Retrieves a Policy Controller", - notes="A Policy Controller is a concrete drools application abstraction. " + - "It aggregates networking, drools, and other resources," + - "as provides operational controls over drools applications", - response=PolicyController.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response controller(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName) { - try { - return Response.status(Response.Status.OK). - entity(PolicyController.factory.get(controllerName)). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + " not acceptable")). - build(); - } - } - - @DELETE - @Path("engine/controllers/{controller}") - @ApiOperation( - value="Deletes a Policy Controller", - notes="A Policy Controller is a concrete drools application abstraction. " + - "It aggregates networking, drools, and other resources," + - "as provides operational controls over drools applications", - response=PolicyController.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled"), - @ApiResponse(code=500, message="A problem has occurred while deleting the Policy Controller") - }) - public Response controllerDelete(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName) { - - PolicyController controller; - try { - controller = - PolicyController.factory.get(controllerName); - if (controller == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + " does not exist")). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + " not found: " + e.getMessage())). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + " not acceptable")).build(); - } - - try { - PolicyEngine.manager.removePolicyController(controllerName); - } catch (IllegalArgumentException | IllegalStateException e) { - logger.debug("{}: cannot remove policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR). - entity(new Error(e.getMessage())). - build(); - } - - return Response.status(Response.Status.OK). - entity(controller). - build(); - } - - @GET - @Path("engine/controllers/{controller}/properties") - @ApiOperation( - value="Retrieves the configuration properties of a Policy Controller", - notes="Configuration resources used by the controller if Properties format", - response=PolicyController.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response controllerProperties(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName) { - try { - PolicyController controller = PolicyController.factory.get(controllerName); - return Response.status(Response.Status.OK). - entity(controller.getProperties()). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + " not acceptable")). - build(); - } - } - - @GET - @Path("engine/controllers/{controller}/inputs") - @ApiOperation( - value="Policy Controller Input Ports", - notes="List of input ports", - responseContainer="List" - ) - public Response controllerInputs() { - return Response.status(Response.Status.OK). - entity(Arrays.asList(Inputs.values())). - build(); - } - - @POST - @Path("engine/controllers/{controller}/inputs/configuration") - @ApiOperation( - value="Policy Controller Input Configuration Requests", - notes="Feeds a configuration request input into the given Policy Controller" - ) - @ApiResponses(value={ - @ApiResponse(code=400, message = "The configuration request is invalid"), - @ApiResponse(code=406, message = "The configuration request cannot be honored") - }) - public Response controllerUpdate(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Configuration to apply", required=true) - ControllerConfiguration controllerConfiguration) { - - if (controllerName == null || controllerName.isEmpty() || - controllerConfiguration == null || - controllerConfiguration.getName().intern() != controllerName) - return Response.status(Response.Status.BAD_REQUEST). - entity("A valid or matching controller names must be provided"). - build(); - - PolicyController controller; - try { - controller = PolicyEngine.manager.updatePolicyController(controllerConfiguration); - if (controller == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + " does not exist")). - build(); - } catch (IllegalArgumentException e) { - logger.info("{}: cannot update policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + " not found: " + e.getMessage())). - build(); - } catch (Exception e) { - logger.info("{}: cannot update policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + " not acceptable")).build(); - } - - return Response.status(Response.Status.OK). - entity(controller). - build(); - } - - @GET - @Path("engine/controllers/{controller}/switches") - @ApiOperation( - value="Policy Controller Switches", - notes="List of the Policy Controller Switches", - responseContainer="List" - ) - public Response controllerSwitches() { - return Response.status(Response.Status.OK). - entity(Arrays.asList(Switches.values())). - build(); - } - - @PUT - @Path("engine/controllers/{controller}/switches/lock") - @ApiOperation( - value="Switches on the Policy Controller Lock Control", - notes="This action on the switch locks the Policy Controller", - response=PolicyController.class - ) - @ApiResponses(value = { - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response controllerLock(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName) { - PolicyController policyController = PolicyController.factory.get(controllerName); - boolean success = policyController.lock(); - if (success) - return Response.status(Status.OK). - entity(policyController). - build(); - else - return Response.status(Status.NOT_ACCEPTABLE). - entity(new Error("Controller " + controllerName + " cannot be locked")). - build(); - } - - @DELETE - @Path("engine/controllers/{controller}/switches/lock") - @ApiOperation( - value="Switches off the Policy Controller Lock Control", - notes="This action on the switch unlocks the Policy Controller", - response=PolicyController.class - ) - @ApiResponses(value = { - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response controllerUnlock(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName) { - PolicyController policyController = PolicyController.factory.get(controllerName); - boolean success = policyController.unlock(); - if (success) - return Response.status(Status.OK). - entity(policyController). - build(); - else - return Response.status(Status.NOT_ACCEPTABLE). - entity(new Error("Controller " + controllerName + " cannot be unlocked")). - build(); - } - - @GET - @Path("engine/controllers/{controller}/drools") - @ApiOperation( - value="Retrieves the Drools Controller subcomponent of the Policy Controller", - notes="The Drools Controller provides an abstraction over the Drools subsystem", - response=DroolsController.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response drools(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName) { - try { - DroolsController drools = getDroolsController(controllerName); - return Response.status(Response.Status.OK). - entity(drools). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + " not acceptable")). - build(); - } - } - - @GET - @Path("engine/controllers/{controller}/drools/facts") - @ApiOperation( - value="Retrieves Facts Summary information for a given controller", - notes="Provides the session names, and a count of fact object in the drools working memory", - responseContainer="Map" - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response droolsFacts(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName) { - try { - Map<String,Long> sessionCounts = new HashMap<>(); - DroolsController drools = getDroolsController(controllerName); - for (String session : drools.getSessionNames()) { - sessionCounts.put(session, drools.factCount(session)); - } - return Response.status(Response.Status.OK). - entity(sessionCounts). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + " not acceptable")). - build(); - } - } - - @GET - @Path("engine/controllers/{controller}/drools/facts/{session}") - @ApiOperation( - value="Retrieves Fact Types (classnames) for a given controller and its count", - notes="The fact types are the classnames of the objects inserted in the drools working memory", - responseContainer="Map" - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller or session cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response droolsFacts(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Drools Session Name", required=true) - @PathParam("session") String sessionName) { - try { - DroolsController drools = getDroolsController(controllerName); - return Response.status(Response.Status.OK). - entity(drools.factClassNames(sessionName)). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error("entity not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + sessionName + " not acceptable")). - build(); - } - } - - @GET - @Path("engine/controllers/{controller}/drools/facts/{session}/{factType}") - @ApiOperation( - value="Retrieves fact objects of a given type in the drools working memory" + - "for a given controller and session", - notes="The fact types are the classnames of the objects inserted in the drools working memory", - responseContainer="List" - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller, session, or fact type cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response droolsFacts(@ApiParam(value="Fact count", required=false) - @DefaultValue("false") @QueryParam("count") boolean count, - @ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Drools Session Name", required=true) - @PathParam("session") String sessionName, - @ApiParam(value="Drools Fact Type", required=true) - @PathParam("factType") String factType) { - try { - DroolsController drools = getDroolsController(controllerName); - List<Object> facts = drools.facts(sessionName, factType, false); - if (!count) - return Response.status(Response.Status.OK).entity(facts).build(); - else - return Response.status(Response.Status.OK).entity(facts.size()).build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + sessionName + ":" + factType + - " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + sessionName + ":" + factType + - " not acceptable")). - build(); - } - } - - @DELETE - @Path("engine/controllers/{controller}/drools/facts/{session}/{factType}") - @ApiOperation( - value="Deletes all the fact objects of a given type from the drools working memory" + - "for a given controller and session. The objects retracted from the working " + - "memory are provided in the response.", - notes="The fact types are the classnames of the objects inserted in the drools working memory", - responseContainer="List" - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller, session, or fact type, cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled"), - @ApiResponse(code=500, message="A server error has occurred processing this request") - }) - public Response droolsFactsDelete(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Drools Session Name", required=true) - @PathParam("session") String sessionName, - @ApiParam(value="Drools Fact Type", required=true) - @PathParam("factType") String factType) { - try { - DroolsController drools = getDroolsController(controllerName); - List<Object> facts = drools.facts(sessionName, factType, true); - return Response.status(Response.Status.OK).entity(facts).build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, factType {}, because of {}", - this, controllerName, sessionName, factType, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + sessionName + ":" + factType + - " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, factType {}, because of {}", - this, controllerName, sessionName, factType, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + sessionName + ":" + factType + - " not acceptable")). - build(); - } catch (Exception e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, factType {}, because of {}", - this, controllerName, sessionName, factType, e.getMessage(), e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR). - entity(new Error(e.getMessage())). - build(); - } - } - - @GET - @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}") - @ApiOperation( - value="Gets all the fact objects returned by a DRL query with no parameters from the drools working memory" + - "for a given controller and session", - notes="The DRL query must be defined in the DRL file", - responseContainer="List" - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller, session, or query information, cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled"), - @ApiResponse(code=500, message="A server error has occurred processing this request") - }) - public Response droolsFacts(@ApiParam(value="Fact count", required=false) - @DefaultValue("false") @QueryParam("count") boolean count, - @ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Drools Session Name", required=true) - @PathParam("session") String sessionName, - @ApiParam(value="Query Name Present in DRL", required=true) - @PathParam("query") String queryName, - @ApiParam(value="Query Identifier Present in the DRL Query", required=true) - @PathParam("queriedEntity") String queriedEntity) { - try { - DroolsController drools = getDroolsController(controllerName); - List<Object> facts = drools.factQuery(sessionName, queryName, queriedEntity, false); - if (!count) - return Response.status(Response.Status.OK).entity(facts).build(); - else - return Response.status(Response.Status.OK).entity(facts.size()).build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, query {}, entity {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + sessionName + ":" + queryName + - queriedEntity + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, query {}, entity {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + sessionName + ":" + queryName + - queriedEntity + " not acceptable")). - build(); - } catch (Exception e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, query {}, entity {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR). - entity(new Error(e.getMessage())). - build(); - } - } - - @POST - @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}") - @ApiOperation( - value="Gets all the fact objects returned by a DRL query with parameters from the drools working memory" + - "for a given controller and session", - notes="The DRL query with parameters must be defined in the DRL file", - responseContainer="List" - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller, session, or query information, cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled"), - @ApiResponse(code=500, message="A server error has occurred processing this request") - }) - public Response droolsFacts(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Drools Session Name", required=true) - @PathParam("session") String sessionName, - @ApiParam(value="Query Name Present in DRL", required=true) - @PathParam("query") String queryName, - @ApiParam(value="Query Identifier Present in the DRL Query", required=true) - @PathParam("queriedEntity") String queriedEntity, - @ApiParam(value="Query Parameter Values to pass in the DRL Query", required=false) - List<Object> queryParameters) { - try { - DroolsController drools = getDroolsController(controllerName); - List<Object> facts; - if (queryParameters == null || queryParameters.isEmpty()) - facts = drools.factQuery(sessionName, queryName, queriedEntity, false); - else - facts = drools.factQuery(sessionName, queryName, queriedEntity, false, queryParameters.toArray()); - return Response.status(Response.Status.OK).entity(facts).build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, queryParameters, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + sessionName + ":" + queryName + - queriedEntity + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, queryParameters, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + sessionName + ":" + queryName + - queriedEntity + " not acceptable")). - build(); - } catch (Exception e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, queryParameters, e.getMessage(), e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR). - entity(new Error(e.getMessage())). - build(); - } - } - - @DELETE - @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}") - @ApiOperation( - value="Deletes all the fact objects returned by a DRL query with parameters from the drools working memory" + - "for a given controller and session", - notes="The DRL query with parameters must be defined in the DRL file", - responseContainer="List" - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller, session, or query information, cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled"), - @ApiResponse(code=500, message="A server error has occurred processing this request") - }) - public Response droolsFactsDelete(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Drools Session Name", required=true) - @PathParam("session") String sessionName, - @ApiParam(value="Query Name Present in DRL", required=true) - @PathParam("query") String queryName, - @ApiParam(value="Query Identifier Present in the DRL Query", required=true) - @PathParam("queriedEntity") String queriedEntity, - @ApiParam(value="Query Parameter Values to pass in the DRL Query", required=false) - List<Object> queryParameters) { - try { - DroolsController drools = getDroolsController(controllerName); - List<Object> facts; - if (queryParameters == null || queryParameters.isEmpty()) - facts = drools.factQuery(sessionName, queryName, queriedEntity, true); - else - facts = drools.factQuery(sessionName, queryName, queriedEntity, true, queryParameters.toArray()); - return Response.status(Response.Status.OK).entity(facts).build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, queryParameters, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + sessionName + ":" + queryName + - queriedEntity + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, queryParameters, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + sessionName + ":" + queryName + - queriedEntity + " not acceptable")). - build(); - } catch (Exception e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, queryParameters, e.getMessage(), e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR). - entity(new Error(e.getMessage())). - build(); - } - } - - @POST - @Path("engine/controllers/tools/coders/decoders/filters/rules/{ruleName}") - @ApiOperation( - value="Produces a Decoder Rule Filter in a format that the Policy Controller can understand", - notes="The result can be used with other APIs to attach a filter to a decoder" - ) - public Response rules(@ApiParam(value="Negate regex?", required=true) - @DefaultValue("false") @QueryParam("negate") boolean negate, - @ApiParam(value="Rule Name", required=true) - @PathParam("ruleName") String name, - @ApiParam(value="Regex expression", required=true) - String regex) { - String literalRegex = Pattern.quote(regex); - if (negate) - literalRegex = "^(?!" + literalRegex + "$).*"; - - return Response.status(Status.OK). - entity(new JsonProtocolFilter.FilterRule(name,literalRegex)). - build(); - } - - @GET - @Path("engine/controllers/{controller}/decoders") - @ApiOperation( - value="Gets all the decoders used by a controller", - notes="A Policy Controller uses decoders to deserialize incoming network messages from " + - "subscribed network topics into specific (fact) objects. " + - "The deserialized (fact) object will typically be inserted in the drools working " + - " memory of the controlled drools application.", - responseContainer="List", - response=ProtocolCoderToolset.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response decoders(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName) { - try { - DroolsController drools = getDroolsController(controllerName); - List<ProtocolCoderToolset> decoders = EventProtocolCoder.manager.getDecoders - (drools.getGroupId(), drools.getArtifactId()); - return Response.status(Response.Status.OK). - entity(decoders). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + " not acceptable")). - build(); - } - } - - @GET - @Path("engine/controllers/{controller}/decoders/filters") - @ApiOperation( - value="Gets all the filters used by a controller", - notes="A Policy Controller uses decoders to deserialize incoming network messages from " + - "subscribed network topics into specific (fact) objects. " + - "The deserialized (fact) object will typically be inserted in the drools working " + - " memory of the controlled drools application." + - "Acceptance filters are used to filter out undesired network messages for the given controller", - responseContainer="List", - response=CoderFilters.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response decoderFilters(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName) { - try { - DroolsController drools = getDroolsController(controllerName); - List<CoderFilters> filters = EventProtocolCoder.manager.getDecoderFilters - (drools.getGroupId(), drools.getArtifactId()); - return Response.status(Response.Status.OK). - entity(filters). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + " not acceptable")). - build(); - } - } - - @GET - @Path("engine/controllers/{controller}/decoders/{topic}") - @ApiOperation( - value="Gets all the decoders in use by a controller for a networked topic", - notes="A Policy Controller uses decoders to deserialize incoming network messages from " + - "subscribed network topics into specific (fact) objects. " + - "The deserialized (fact) object will typically be inserted in the drools working " + - " memory of the controlled drools application.", - responseContainer="List", - response=ProtocolCoderToolset.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller or topic cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response decoder(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Networked Topic Name", required=true) - @PathParam("topic") String topic) { - try { - DroolsController drools = getDroolsController(controllerName); - ProtocolCoderToolset decoder = EventProtocolCoder.manager.getDecoders - (drools.getGroupId(), drools.getArtifactId(), topic); - return Response.status(Response.Status.OK). - entity(decoder). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", - this, controllerName, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + topic + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", - this, controllerName, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + topic + " not acceptable")). - build(); - } - } - - @GET - @Path("engine/controllers/{controller}/decoders/{topic}/filters") - @ApiOperation( - value="Gets all filters attached to decoders for a given networked topic in use by a controller", - notes="A Policy Controller uses decoders to deserialize incoming network messages from " + - "subscribed network topics into specific (fact) objects. " + - "The deserialized (fact) object will typically be inserted in the drools working " + - " memory of the controlled drools application." + - "Acceptance filters are used to filter out undesired network messages for the given controller", - responseContainer="List", - response=CoderFilters.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller or topic cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response decoderFilter(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Networked Topic Name", required=true) - @PathParam("topic") String topic) { - try { - DroolsController drools = getDroolsController(controllerName); - ProtocolCoderToolset decoder = EventProtocolCoder.manager.getDecoders - (drools.getGroupId(), drools.getArtifactId(), topic); - if (decoder == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(topic + " does not exist")). - build(); - else - return Response.status(Response.Status.OK). - entity(decoder.getCoders()). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", - this, controllerName, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + topic + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", - this, controllerName, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + topic + " not acceptable")). - build(); - } - } - - @GET - @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}") - @ApiOperation( - value="Gets all filters attached to decoders for a given subscribed networked topic " + - "and fact type", - notes="Decoders are associated with networked topics. A Policy Controller manages " + - "multiple topics and therefore its attached decoders. " + - "A Policy Controller uses filters to further specify the fact mapping. " + - "Filters are applied on a per fact type (classname).", - responseContainer="List", - response=CoderFilters.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller, topic, or fact type cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response decoderFilter(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Networked Topic Name", required=true) - @PathParam("topic") String topic, - @ApiParam(value="Fact Type", required=true) - @PathParam("factType") String factClass) { - try { - DroolsController drools = getDroolsController(controllerName); - ProtocolCoderToolset decoder = EventProtocolCoder.manager.getDecoders - (drools.getGroupId(), drools.getArtifactId(), topic); - CoderFilters filters = decoder.getCoder(factClass); - if (filters == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(topic + ":" + factClass + " does not exist")). - build(); - else - return Response.status(Response.Status.OK). - entity(filters). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}", - this, controllerName, topic, factClass, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + topic + ":" + - factClass + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}", - this, controllerName, topic, factClass, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + topic + ":" + - factClass + " not acceptable")). - build(); - } - } - - @PUT - @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}") - @ApiOperation( - value="Attaches filters to the decoder for a given networked topic " + - "and fact type", - notes="Decoders are associated with networked topics. A Policy Controller manages " + - "multiple topics and therefore its attached decoders. " + - "A Policy Controller uses filters to further specify the fact mapping. " + - "Filters are applied on a per fact type (classname).", - responseContainer="List", - response=CoderFilters.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller, topic, fact type, cannot be found, " + - "or a filter has not been provided"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response decoderFilter(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic, - @ApiParam(value="Fact Type", required=true) - @PathParam("factType") String factClass, - @ApiParam(value="Configuration Filter", required=true) - JsonProtocolFilter configFilters) { - - if (configFilters == null) { - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error("Configuration Filters not provided")). - build(); - } - - try { - DroolsController drools = getDroolsController(controllerName); - ProtocolCoderToolset decoder = EventProtocolCoder.manager.getDecoders - (drools.getGroupId(), drools.getArtifactId(), topic); - CoderFilters filters = decoder.getCoder(factClass); - if (filters == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(topic + ":" + factClass + " does not exist")). - build(); - filters.setFilter(configFilters); - return Response.status(Response.Status.OK). - entity(filters). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get decoder filters for policy-controller {} topic {} type {} filters {} because of {}", - this, controllerName, topic, factClass, configFilters, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + topic + ":" + - factClass + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get decoder filters for policy-controller {} topic {} type {} filters {} because of {}", - this, controllerName, topic, factClass, configFilters, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + topic + ":" + - factClass + " not acceptable")). - build(); - } - } - - @GET - @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rules") - @ApiOperation( - value="Gets the filter rules attached to a topic decoder of a controller", - notes="Decoders are associated with networked topics. A Policy Controller manages " + - "multiple topics and therefore its attached decoders. " + - "A Policy Controller uses filters to further specify the fact mapping. " + - "Filters are applied on a per fact type and are composed of field matching rules. ", - responseContainer="List", - response=FilterRule.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller, topic, or fact type cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response decoderFilterRules(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic, - @ApiParam(value="Fact Type", required=true) - @PathParam("factType") String factClass) { - try { - DroolsController drools = getDroolsController(controllerName); - ProtocolCoderToolset decoder = EventProtocolCoder.manager.getDecoders - (drools.getGroupId(), drools.getArtifactId(), topic); - - CoderFilters filters = decoder.getCoder(factClass); - if (filters == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + ":" + topic + ":" + factClass + " does not exist")). - build(); - - JsonProtocolFilter filter = filters.getFilter(); - if (filter == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + ":" + topic + ":" + factClass + " no filters")). - build(); - - return Response.status(Response.Status.OK). - entity(filter.getRules()). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}", - this, controllerName, topic, factClass, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + topic + ":" + - factClass + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}", - this, controllerName, topic, factClass, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + topic + ":" + - factClass + " not acceptable")). - build(); - } - } - - @GET - @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rules/{ruleName}") - @ApiOperation( - value="Gets a filter rule by name attached to a topic decoder of a controller", - notes="Decoders are associated with networked topics. A Policy Controller manages " + - "multiple topics and therefore its attached decoders. " + - "A Policy Controller uses filters to further specify the fact mapping. " + - "Filters are applied on a per fact type and are composed of field matching rules. ", - responseContainer="List", - response=FilterRule.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller, topic, fact type, or rule name cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response decoderFilterRules(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic, - @ApiParam(value="Fact Type", required=true) - @PathParam("factType") String factClass, - @ApiParam(value="Rule Name", required=true) - @PathParam("ruleName") String ruleName) { - try { - DroolsController drools = getDroolsController(controllerName); - ProtocolCoderToolset decoder = EventProtocolCoder.manager.getDecoders - (drools.getGroupId(), drools.getArtifactId(), topic); - - CoderFilters filters = decoder.getCoder(factClass); - if (filters == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + ":" + topic + ":" + factClass + " does not exist")). - build(); - - JsonProtocolFilter filter = filters.getFilter(); - if (filter == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + ":" + topic + ":" + factClass + " no filters")). - build(); - - return Response.status(Response.Status.OK). - entity(filter.getRules(ruleName)). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get decoder filters for policy-controller {} topic {} type {} rule {} because of {}", - this, controllerName, topic, factClass, ruleName, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + topic + ":" + - factClass + ": " + ruleName + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get decoder filters for policy-controller {} topic {} type {} rule {} because of {}", - this, controllerName, topic, factClass, ruleName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + topic + ":" + - factClass + ":" + ruleName + " not acceptable")). - build(); - } - } - - @DELETE - @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rules/{ruleName}") - @ApiOperation( - value="Deletes a filter rule by name attached to a topic decoder of a controller", - notes="Decoders are associated with networked topics. A Policy Controller manages " + - "multiple topics and therefore its attached decoders. " + - "A Policy Controller uses filters to further specify the fact mapping. " + - "Filters are applied on a per fact type and are composed of field matching rules. ", - responseContainer="List", - response=FilterRule.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller, topic, fact type, or rule name cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response decoderFilterRuleDelete(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic, - @ApiParam(value="Fact Type", required=true) - @PathParam("factType") String factClass, - @ApiParam(value="Rule Name", required=true) - @PathParam("ruleName") String ruleName, - @ApiParam(value="Filter Rule", required=true) - FilterRule rule) { - - try { - DroolsController drools = getDroolsController(controllerName); - ProtocolCoderToolset decoder = EventProtocolCoder.manager.getDecoders - (drools.getGroupId(), drools.getArtifactId(), topic); - - CoderFilters filters = decoder.getCoder(factClass); - if (filters == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + ":" + topic + ":" + factClass + " does not exist")). - build(); - - JsonProtocolFilter filter = filters.getFilter(); - if (filter == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + ":" + topic + ":" + factClass + " no filters")). - build(); - - if (rule == null) { - filter.deleteRules(ruleName); - return Response.status(Response.Status.OK). - entity(filter.getRules()). - build(); - } - - if (rule.getName() == null || !rule.getName().equals(ruleName)) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + ":" + topic + ":" + factClass + ":" + ruleName + - " rule name request inconsistencies (" + rule.getName() + ")")). - build(); - - filter.deleteRule(ruleName, rule.getRegex()); - return Response.status(Response.Status.OK). - entity(filter.getRules()). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get decoder filters for policy-controller {} topic {} type {} rule {} because of {}", - this, controllerName, topic, factClass, ruleName, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + topic + ":" + - factClass + ": " + ruleName + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get decoder filters for policy-controller {} topic {} type {} rule {} because of {}", - this, controllerName, topic, factClass, ruleName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + topic + ":" + - factClass + ":" + ruleName + " not acceptable")). - build(); - } - } - - @PUT - @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rules") - @ApiOperation( - value="Places a new filter rule in a topic decoder", - notes="Decoders are associated with networked topics. A Policy Controller manages " + - "multiple topics and therefore its attached decoders. " + - "A Policy Controller uses filters to further specify the fact mapping. " + - "Filters are applied on a per fact type and are composed of field matching rules. ", - responseContainer="List", - response=FilterRule.class - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The controller, topic, or fact type cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response decoderFilterRule(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic, - @ApiParam(value="Fact Type", required=true) - @PathParam("factType") String factClass, - @ApiParam(value="Rule Name", required=true) - @PathParam("ruleName") String ruleName, - @ApiParam(value="Filter Rule", required=true) - FilterRule rule) { - - try { - DroolsController drools = getDroolsController(controllerName); - ProtocolCoderToolset decoder = EventProtocolCoder.manager.getDecoders - (drools.getGroupId(), drools.getArtifactId(), topic); - - CoderFilters filters = decoder.getCoder(factClass); - if (filters == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + ":" + topic + ":" + factClass + " does not exist")). - build(); - - JsonProtocolFilter filter = filters.getFilter(); - if (filter == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + ":" + topic + ":" + factClass + " no filters")). - build(); - - if (rule.getName() == null) - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + ":" + topic + ":" + factClass + - " rule name request inconsistencies (" + rule.getName() + ")")). - build(); - - filter.addRule(rule.getName(), rule.getRegex()); - return Response.status(Response.Status.OK). - entity(filter.getRules()). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot access decoder filter rules for policy-controller {} topic {} type {} rule {} because of {}", - this, controllerName, topic, factClass, ruleName, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + topic + ":" + - factClass + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot access decoder filter rules for policy-controller {} topic {} type {} rule {} because of {}", - this, controllerName, topic, factClass, ruleName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + topic + ":" + - factClass + " not acceptable")). - build(); - } - } - - @POST - @Path("engine/controllers/{controller}/decoders/{topic}") - @Consumes(MediaType.TEXT_PLAIN) - @ApiOperation( - value="Decodes a string into a fact object, and encodes it back into a string", - notes="Tests the decode/encode functions of a controller", - response=CodingResult.class - ) - @ApiResponses(value = { - @ApiResponse(code=400, message="Bad input has been provided"), - @ApiResponse(code=404, message="The controller cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response decode(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName, - @ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic, - @ApiParam(value="JSON String to decode", required=true) - String json) { - - PolicyController policyController; - try { - policyController = PolicyController.factory.get(controllerName); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", - this, controllerName, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(controllerName + ":" + topic + ":" + - " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", - this, controllerName, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + ":" + topic + ":" + - " not acceptable")). - build(); - } - - CodingResult result = new CodingResult(); - result.decoding = false; - result.encoding = false; - result.jsonEncoding = null; - - Object event; - try { - event = EventProtocolCoder.manager.decode - (policyController.getDrools().getGroupId(), - policyController.getDrools().getArtifactId(), - topic, - json); - result.decoding = true; - } catch (Exception e) { - logger.debug("{}: cannot get policy-controller {} topic {} because of {}", - this, controllerName, topic, e.getMessage(), e); - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(e.getMessage())). - build(); - } - - try { - result.jsonEncoding = EventProtocolCoder.manager.encode(topic, event); - result.encoding = true; - } catch (Exception e) { - // continue so to propagate decoding results .. - logger.debug("{}: cannot encode for policy-controller {} topic {} because of {}", - this, controllerName, topic, e.getMessage(), e); - } - - return Response.status(Response.Status.OK). - entity(result). - build(); - } - - @GET - @Path("engine/controllers/{controller}/encoders") - @ApiOperation( - value="Retrieves the encoder filters of a controller", - notes="The encoders serializes a fact object, typically for network transmission", - responseContainer="List", - response=CoderFilters.class - ) - @ApiResponses(value = { - @ApiResponse(code=400, message="Bad input has been provided"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response encoderFilters(@ApiParam(value="Policy Controller Name", required=true) - @PathParam("controller") String controllerName) { - List<CoderFilters> encoders; - try { - PolicyController controller = PolicyController.factory.get(controllerName); - DroolsController drools = controller.getDrools(); - encoders = EventProtocolCoder.manager.getEncoderFilters - (drools.getGroupId(), drools.getArtifactId()); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot get encoder filters for policy-controller {} because of {}", - this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.BAD_REQUEST). - entity(new Error(controllerName + " not found: " + e.getMessage())). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot get encoder filters for policy-controller {} because of {}", - this, controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(controllerName + " is not accepting the request")).build(); - } - - return Response.status(Response.Status.OK). - entity(encoders). - build(); - } - - @GET - @Path("engine/topics") - @ApiOperation( - value="Retrieves the managed topics", - notes="Network Topics Aggregation", - response=TopicEndpoint.class - ) - public Response topics() { - return Response.status(Response.Status.OK). - entity(TopicEndpoint.manager). - build(); - } - - @GET - @Path("engine/topics/switches") - @ApiOperation( - value="Topics Control Switches", - notes="List of the Topic Control Switches", - responseContainer="List" - ) - public Response topicSwitches() { - return Response.status(Response.Status.OK). - entity(Arrays.asList(Switches.values())). - build(); - } - - @PUT - @Path("engine/topics/switches/lock") - @ApiOperation( - value="Locks all the managed topics", - notes="The operation affects all managed sources and sinks", - response=TopicEndpoint.class - ) - @ApiResponses(value = { - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response topicsLock() { - boolean success = TopicEndpoint.manager.lock(); - if (success) - return Response.status(Status.OK). - entity(TopicEndpoint.manager). - build(); - else - return Response.status(Status.NOT_ACCEPTABLE). - entity(new Error("cannot perform operation")). - build(); - } - - @DELETE - @Path("engine/topics/switches/lock") - @ApiOperation( - value="Unlocks all the managed topics", - notes="The operation affects all managed sources and sinks", - response=TopicEndpoint.class - ) - @ApiResponses(value = { - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response topicsUnlock() { - boolean success = TopicEndpoint.manager.unlock(); - if (success) - return Response.status(Status.OK). - entity(TopicEndpoint.manager). - build(); - else - return Response.status(Status.NOT_ACCEPTABLE). - entity(new Error("cannot perform operation")). - build(); - } - - @GET - @Path("engine/topics/sources") - @ApiOperation( - value="Retrieves the managed topic sources", - notes="Network Topic Sources Agregation", - responseContainer="List", - response=TopicSource.class - ) - public Response sources() { - return Response.status(Response.Status.OK). - entity(TopicEndpoint.manager.getTopicSources()). - build(); - } - - @GET - @Path("engine/topics/sinks") - @ApiOperation( - value="Retrieves the managed topic sinks", - notes="Network Topic Sinks Agregation", - responseContainer="List", - response=TopicSink.class - ) - public Response sinks() { - return Response.status(Response.Status.OK). - entity(TopicEndpoint.manager.getTopicSinks()). - build(); - } - - @GET - @Path("engine/topics/sources/ueb") - @ApiOperation( - value="Retrieves the UEB managed topic sources", - notes="UEB Topic Sources Agregation", - responseContainer="List", - response=UebTopicSource.class - ) - public Response uebSources() { - return Response.status(Response.Status.OK). - entity(TopicEndpoint.manager.getUebTopicSources()). - build(); - } - - @GET - @Path("engine/topics/sinks/ueb") - @ApiOperation( - value="Retrieves the UEB managed topic sinks", - notes="UEB Topic Sinks Agregation", - responseContainer="List", - response=UebTopicSource.class - ) - public Response uebSinks() { - return Response.status(Response.Status.OK). - entity(TopicEndpoint.manager.getUebTopicSinks()). - build(); - } - - @GET - @Path("engine/topics/sources/dmaap") - @ApiOperation( - value="Retrieves the DMaaP managed topic sources", - notes="DMaaP Topic Sources Agregation", - responseContainer="List", - response=DmaapTopicSource.class - ) - public Response dmaapSources() { - return Response.status(Response.Status.OK). - entity(TopicEndpoint.manager.getDmaapTopicSources()). - build(); - } - - @GET - @Path("engine/topics/sinks/dmaap") - @ApiOperation( - value="Retrieves the DMaaP managed topic sinks", - notes="DMaaP Topic Sinks Agregation", - responseContainer="List", - response=DmaapTopicSink.class - ) - public Response dmaapSinks() { - return Response.status(Response.Status.OK). - entity(TopicEndpoint.manager.getDmaapTopicSinks()). - build(); - } - - @GET - @Path("engine/topics/sources/ueb/{topic}") - @ApiOperation( - value="Retrieves an UEB managed topic source", - notes="This is an UEB Network Communicaton Endpoint source of messages for the Engine", - response=UebTopicSource.class - ) - public Response uebSourceTopic(@ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic) { - return Response.status(Response.Status.OK). - entity(TopicEndpoint.manager.getUebTopicSource(topic)). - build(); + @GET + @Path("engine") + @ApiOperation(value = "Retrieves the Engine Operational Status", + notes = "Top-level abstraction. Provides a global view of resources", + response = PolicyEngine.class) + public Response engine() { + return Response.status(Response.Status.OK).entity(PolicyEngine.manager).build(); + } + + @DELETE + @Path("engine") + @ApiOperation(value = "Shuts down the Engine", + notes = "Deleting the engine, the top-level abstraction, equivalenty shuts it down", + response = PolicyEngine.class) + public Response engineShutdown() { + try { + PolicyEngine.manager.shutdown(); + } catch (final IllegalStateException e) { + logger.error("{}: cannot shutdown {} because of {}", this, PolicyEngine.manager, + e.getMessage(), e); + return Response.status(Response.Status.BAD_REQUEST).entity(PolicyEngine.manager).build(); } - - @GET - @Path("engine/topics/sinks/ueb/{topic}") - @ApiOperation( - value="Retrieves an UEB managed topic sink", - notes="This is an UEB Network Communicaton Endpoint destination of messages from the Engine", - response=UebTopicSink.class - ) - public Response uebSinkTopic(@ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic) { - return Response.status(Response.Status.OK). - entity(TopicEndpoint.manager.getUebTopicSink(topic)). - build(); + + return Response.status(Response.Status.OK).entity(PolicyEngine.manager).build(); + } + + @GET + @Path("engine/features") + @ApiOperation(value = "Engine Features", + notes = "Provides the list of loaded features using the PolicyEngineFeatureAPI", + responseContainer = "List") + public Response engineFeatures() { + return Response.status(Response.Status.OK).entity(PolicyEngine.manager.getFeatures()).build(); + } + + @GET + @Path("engine/features/inventory") + @ApiOperation(value = "Engine Detailed Feature Inventory", + notes = "Provides detailed list of loaded features using the PolicyEngineFeatureAPI", + responseContainer = "List", response = PolicyEngineFeatureAPI.class) + public Response engineFeaturesInventory() { + return Response.status(Response.Status.OK).entity(PolicyEngine.manager.getFeatureProviders()) + .build(); + } + + @GET + @Path("engine/features/{featureName}") + @ApiOperation(value = "Engine Feature", + notes = "Provides Details for a given feature Engine Provider", + response = PolicyEngineFeatureAPI.class) + @ApiResponses(value = {@ApiResponse(code = 404, message = "The feature cannot be found")}) + public Response engineFeature(@ApiParam(value = "Feature Name", + required = true) @PathParam("featureName") String featureName) { + try { + return Response.status(Response.Status.OK) + .entity(PolicyEngine.manager.getFeatureProvider(featureName)).build(); + } catch (final IllegalArgumentException iae) { + logger.debug("feature unavailable: {}", featureName, iae); + return Response.status(Response.Status.NOT_FOUND).entity(new Error(iae.getMessage())).build(); + } + } + + @GET + @Path("engine/inputs") + @ApiOperation(value = "Engine Input Ports", notes = "List of input ports", + responseContainer = "List") + public Response engineInputs() { + return Response.status(Response.Status.OK).entity(Arrays.asList(Inputs.values())).build(); + } + + @POST + @Path("engine/inputs/configuration") + @ApiOperation(value = "Engine Input Configuration Requests", + notes = "Feeds a configuration request input into the Engine") + @ApiResponses( + value = {@ApiResponse(code = 406, message = "The configuration request cannot be honored")}) + public Response engineUpdate(@ApiParam(value = "Configuration to apply", + required = true) PdpdConfiguration configuration) { + final PolicyController controller = null; + boolean success = true; + try { + success = PolicyEngine.manager.configure(configuration); + } catch (final Exception e) { + success = false; + logger.info("{}: cannot configure {} because of {}", this, PolicyEngine.manager, + e.getMessage(), e); } - - @GET - @Path("engine/topics/sources/dmaap/{topic}") - @ApiOperation( - value="Retrieves a DMaaP managed topic source", - notes="This is a DMaaP Network Communicaton Endpoint source of messages for the Engine", - response=DmaapTopicSource.class - ) - public Response dmaapSourceTopic(@ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic) { - return Response.status(Response.Status.OK). - entity(TopicEndpoint.manager.getDmaapTopicSource(topic)). - build(); + + if (!success) + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error("cannot perform operation")).build(); + else + return Response.status(Response.Status.OK).entity(controller).build(); + } + + @GET + @Path("engine/properties") + @ApiOperation(value = "Engine Configuration Properties", + notes = "Used for booststrapping the engine", response = Properties.class) + public Response engineProperties() { + return Response.status(Response.Status.OK).entity(PolicyEngine.manager.getProperties()).build(); + } + + @GET + @Path("engine/environment") + @ApiOperation(value = "Engine Environment Properties", + notes = "Installation and OS environment properties used by the engine", + response = Properties.class) + public Response engineEnvironment() { + return Response.status(Response.Status.OK).entity(PolicyEngine.manager.getEnvironment()) + .build(); + } + + @GET + @Path("engine/environment/{envProperty}") + @Consumes(MediaType.TEXT_PLAIN) + @ApiOperation(value = "Gets an environment variable", response = String.class) + public Response engineEnvironment(@ApiParam(value = "Environment Property", + required = true) @PathParam("envProperty") String envProperty) { + return Response.status(Response.Status.OK) + .entity(PolicyEngine.manager.getEnvironmentProperty(envProperty)).build(); + } + + @PUT + @Path("engine/environment/{envProperty}") + @Consumes(MediaType.TEXT_PLAIN) + @Produces(MediaType.TEXT_PLAIN) + @ApiOperation(value = "Adds a new environment value to the engine", response = String.class) + public Response engineEnvironmentAdd( + @ApiParam(value = "Environment Property", + required = true) @PathParam("envProperty") String envProperty, + @ApiParam(value = "Environment Value", required = true) String envValue) { + final String previousValue = PolicyEngine.manager.setEnvironmentProperty(envProperty, envValue); + return Response.status(Response.Status.OK).entity(previousValue).build(); + } + + @GET + @Path("engine/switches") + @ApiOperation(value = "Engine Control Switches", notes = "List of the Engine Control Switches", + responseContainer = "List") + public Response engineSwitches() { + return Response.status(Response.Status.OK).entity(Arrays.asList(Switches.values())).build(); + } + + @PUT + @Path("engine/switches/activation") + @ApiOperation(value = "Switches on the Engine Activation Switch", + notes = "Turns on Activation Switch on the Engine. This order entails that the engine " + + "and controllers are unlocked and started", + response = PolicyEngine.class) + public Response engineActivation() { + boolean success = true; + try { + PolicyEngine.manager.activate(); + } catch (final Exception e) { + success = false; + logger.info("{}: cannot activate {} because of {}", this, PolicyEngine.manager, + e.getMessage(), e); } - - @GET - @Path("engine/topics/sinks/dmaap/{topic}") - @ApiOperation( - value="Retrieves a DMaaP managed topic sink", - notes="This is a DMaaP Network Communicaton Endpoint destination of messages from the Engine", - response=DmaapTopicSink.class - ) - public Response dmaapSinkTopic(@ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic) { - return Response.status(Response.Status.OK). - entity(TopicEndpoint.manager.getDmaapTopicSink(topic)). - build(); + + if (!success) + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error("cannot perform operation")).build(); + else + return Response.status(Response.Status.OK).entity(PolicyEngine.manager).build(); + } + + @DELETE + @Path("engine/switches/activation") + @ApiOperation(value = "Switches off Engine Activation Switch", + notes = "Turns off the Activation Switch on the Engine. This order entails that the engine " + + "and controllers are locked (with the exception of those resources defined as unmanaged)", + response = PolicyEngine.class) + public Response engineDeactivation() { + boolean success = true; + try { + PolicyEngine.manager.deactivate(); + } catch (final Exception e) { + success = false; + logger.info("{}: cannot deactivate {} because of {}", this, PolicyEngine.manager, + e.getMessage(), e); } - - @GET - @Path("engine/topics/sources/ueb/{topic}/events") - @ApiOperation( - value="Retrieves the latest events received by an UEB topic", - notes="This is a UEB Network Communicaton Endpoint source of messages for the Engine", - responseContainer="List" - ) - public Response uebSourceEvents(@ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic) { - return Response.status(Status.OK). - entity(Arrays.asList(TopicEndpoint.manager.getUebTopicSource(topic).getRecentEvents())). - build(); + + if (!success) + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error("cannot perform operation")).build(); + else + return Response.status(Response.Status.OK).entity(PolicyEngine.manager).build(); + } + + @PUT + @Path("engine/switches/lock") + @ApiOperation(value = "Switches on the Engine Lock Control", + notes = "This switch locks all the engine resources as a whole, except those that are defined unmanaged", + response = PolicyEngine.class) + @ApiResponses(value = { + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response engineLock() { + final boolean success = PolicyEngine.manager.lock(); + if (success) + return Response.status(Status.OK).entity(PolicyEngine.manager).build(); + else + return Response.status(Status.NOT_ACCEPTABLE).entity(new Error("cannot perform operation")) + .build(); + } + + @DELETE + @Path("engine/switches/lock") + @ApiOperation(value = "Switches off the Lock control", + notes = "This switch locks all the engine resources as a whole, except those that are defined unmanaged", + response = PolicyEngine.class) + @ApiResponses(value = { + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response engineUnlock() { + final boolean success = PolicyEngine.manager.unlock(); + if (success) + return Response.status(Status.OK).entity(PolicyEngine.manager).build(); + else + return Response.status(Status.NOT_ACCEPTABLE).entity(new Error("cannot perform operation")) + .build(); + } + + @GET + @Path("engine/controllers") + @ApiOperation(value = "Lists the Policy Controllers Names", + notes = "Unique Policy Controller Identifiers", responseContainer = "List") + public Response controllers() { + return Response.status(Response.Status.OK).entity(PolicyEngine.manager.getPolicyControllerIds()) + .build(); + } + + @GET + @Path("engine/controllers/inventory") + @ApiOperation(value = "Lists the Policy Controllers", + notes = "Detailed list of Policy Controllers", responseContainer = "List", + response = PolicyController.class) + public Response controllerInventory() { + return Response.status(Response.Status.OK).entity(PolicyEngine.manager.getPolicyControllers()) + .build(); + } + + @POST + @Path("engine/controllers") + @ApiOperation(value = "Creates and starts a new Policy Controller", + notes = "Controller creation based on properties", response = PolicyController.class) + @ApiResponses(value = { + @ApiResponse(code = 400, message = "Invalid configuration information has been provided"), + @ApiResponse(code = 304, message = "The controller already exists"), + @ApiResponse(code = 406, + message = "The administrative state of the system prevents it " + + "from processing this request"), + @ApiResponse(code = 206, + message = "The controller has been created " + "but cannot be started"), + @ApiResponse(code = 201, + message = "The controller has been succesfully created and started")}) + public Response controllerAdd( + @ApiParam(value = "Configuration Properties to apply", required = true) Properties config) { + if (config == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error("A configuration must be provided")).build(); + + final String controllerName = config.getProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME); + if (controllerName == null || controllerName.isEmpty()) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error( + "Configuration must have an entry for " + PolicyProperties.PROPERTY_CONTROLLER_NAME)) + .build(); + + PolicyController controller; + try { + controller = PolicyController.factory.get(controllerName); + if (controller != null) + return Response.status(Response.Status.NOT_MODIFIED).entity(controller).build(); + } catch (final IllegalArgumentException e) { + // This is OK + } catch (final IllegalStateException e) { + logger.info("{}: cannot get policy-controller because of {}", this, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + " not found")).build(); } - - @GET - @Path("engine/topics/sinks/ueb/{topic}/events") - @ApiOperation( - value="Retrieves the latest events sent from a topic", - notes="This is a UEB Network Communicaton Endpoint sink of messages from the Engine", - responseContainer="List" - ) - public Response uebSinkEvents(@ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic) { - return Response.status(Status.OK). - entity(Arrays.asList(TopicEndpoint.manager.getUebTopicSink(topic).getRecentEvents())). - build(); + + try { + controller = PolicyEngine.manager.createPolicyController( + config.getProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME), config); + } catch (IllegalArgumentException | IllegalStateException e) { + logger.warn("{}: cannot create policy-controller because of {}", this, e.getMessage(), e); + return Response.status(Response.Status.BAD_REQUEST).entity(new Error(e.getMessage())).build(); } - - @GET - @Path("engine/topics/sources/dmaap/{topic}/events") - @ApiOperation( - value="Retrieves the latest events received by a DMaaP topic", - notes="This is a DMaaP Network Communicaton Endpoint source of messages for the Engine", - responseContainer="List" - ) - public Response dmaapSourceEvents(@ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic) { - return Response.status(Status.OK). - entity(Arrays.asList(TopicEndpoint.manager.getDmaapTopicSource(topic).getRecentEvents())). - build(); + + try { + final boolean success = controller.start(); + if (!success) { + logger.info("{}: cannot start {}", this, controller); + return Response.status(Response.Status.PARTIAL_CONTENT) + .entity(new Error(controllerName + " can't be started")).build(); + } + } catch (final IllegalStateException e) { + logger.info("{}: cannot start {} because of {}", this, controller, e.getMessage(), e);; + return Response.status(Response.Status.PARTIAL_CONTENT).entity(controller).build(); } - - @GET - @Path("engine/topics/sinks/dmaap/{topic}/events") - @ApiOperation( - value="Retrieves the latest events send through a DMaaP topic", - notes="This is a DMaaP Network Communicaton Endpoint destination of messages from the Engine", - responseContainer="List" - ) - public Response dmaapSinkEvents( - @PathParam("topic") String topic) { - return Response.status(Status.OK). - entity(Arrays.asList(TopicEndpoint.manager.getDmaapTopicSink(topic).getRecentEvents())). - build(); + + return Response.status(Response.Status.CREATED).entity(controller).build(); + } + + @GET + @Path("engine/controllers/features") + @ApiOperation(value = "Lists of Feature Providers Identifiers", + notes = "Unique Policy Controller Identifiers", responseContainer = "List") + public Response controllerFeatures() { + return Response.status(Response.Status.OK).entity(PolicyEngine.manager.getFeatures()).build(); + } + + @GET + @Path("engine/controllers/features/inventory") + @ApiOperation(value = "Detailed Controllers Feature Inventory", + notes = "Provides detailed list of loaded features using the PolicyControllerFeatureAPI", + responseContainer = "List", response = PolicyControllerFeatureAPI.class) + public Response controllerFeaturesInventory() { + return Response.status(Response.Status.OK) + .entity(PolicyController.factory.getFeatureProviders()).build(); + } + + @GET + @Path("engine/controllers/features/{featureName}") + @ApiOperation(value = "Controller Feature", + notes = "Provides Details for a given Policy Controller feature provider", + response = PolicyControllerFeatureAPI.class) + @ApiResponses(value = {@ApiResponse(code = 404, message = "The feature cannot be found")}) + public Response controllerFeature(@ApiParam(value = "Feature Name", + required = true) @PathParam("featureName") String featureName) { + try { + return Response.status(Response.Status.OK) + .entity(PolicyController.factory.getFeatureProvider(featureName)).build(); + } catch (final IllegalArgumentException iae) { + logger.debug("{}: cannot feature {} because of {}", this, featureName, iae.getMessage(), iae); + return Response.status(Response.Status.NOT_FOUND).entity(new Error(iae.getMessage())).build(); + } + } + + @GET + @Path("engine/controllers/{controller}") + @ApiOperation(value = "Retrieves a Policy Controller", + notes = "A Policy Controller is a concrete drools application abstraction. " + + "It aggregates networking, drools, and other resources," + + "as provides operational controls over drools applications", + response = PolicyController.class) + @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response controller(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + try { + return Response.status(Response.Status.OK) + .entity(PolicyController.factory.get(controllerName)).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + " not acceptable")).build(); + } + } + + @DELETE + @Path("engine/controllers/{controller}") + @ApiOperation(value = "Deletes a Policy Controller", + notes = "A Policy Controller is a concrete drools application abstraction. " + + "It aggregates networking, drools, and other resources," + + "as provides operational controls over drools applications", + response = PolicyController.class) + @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + + "this request to be fulfilled"), + @ApiResponse(code = 500, + message = "A problem has occurred while deleting the Policy Controller")}) + public Response controllerDelete(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + + PolicyController controller; + try { + controller = PolicyController.factory.get(controllerName); + if (controller == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + " does not exist")).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + " not found: " + e.getMessage())).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + " not acceptable")).build(); } - - @GET - @Path("engine/topics/sources/ueb/{topic}/switches") - @ApiOperation( - value="UEB Topic Control Switches", - notes="List of the UEB Topic Control Switches", - responseContainer="List" - ) - public Response uebTopicSwitches() { - return Response.status(Response.Status.OK). - entity(Arrays.asList(Switches.values())). - build(); + + try { + PolicyEngine.manager.removePolicyController(controllerName); + } catch (IllegalArgumentException | IllegalStateException e) { + logger.debug("{}: cannot remove policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(new Error(e.getMessage())).build(); } - - @PUT - @Path("engine/topics/sources/ueb/{topic}/switches/lock") - @ApiOperation( - value="Locks an UEB Source topic", - response=UebTopicSource.class - ) - @ApiResponses(value = { - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response uebTopicLock(@ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic) { - UebTopicSource source = TopicEndpoint.manager.getUebTopicSource(topic); - boolean success = source.lock(); - if (success) - return Response.status(Status.OK). - entity(source). - build(); - else - return Response.status(Status.NOT_ACCEPTABLE). - entity(new Error("cannot perform operation on " + topic)). - build(); + + return Response.status(Response.Status.OK).entity(controller).build(); + } + + @GET + @Path("engine/controllers/{controller}/properties") + @ApiOperation(value = "Retrieves the configuration properties of a Policy Controller", + notes = "Configuration resources used by the controller if Properties format", + response = PolicyController.class) + @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response controllerProperties(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + try { + final PolicyController controller = PolicyController.factory.get(controllerName); + return Response.status(Response.Status.OK).entity(controller.getProperties()).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + " not acceptable")).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/inputs") + @ApiOperation(value = "Policy Controller Input Ports", notes = "List of input ports", + responseContainer = "List") + public Response controllerInputs() { + return Response.status(Response.Status.OK).entity(Arrays.asList(Inputs.values())).build(); + } + + @POST + @Path("engine/controllers/{controller}/inputs/configuration") + @ApiOperation(value = "Policy Controller Input Configuration Requests", + notes = "Feeds a configuration request input into the given Policy Controller") + @ApiResponses(value = {@ApiResponse(code = 400, message = "The configuration request is invalid"), + @ApiResponse(code = 406, message = "The configuration request cannot be honored")}) + public Response controllerUpdate( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Configuration to apply", + required = true) ControllerConfiguration controllerConfiguration) { + + if (controllerName == null || controllerName.isEmpty() || controllerConfiguration == null + || controllerConfiguration.getName().intern() != controllerName) + return Response.status(Response.Status.BAD_REQUEST) + .entity("A valid or matching controller names must be provided").build(); + + PolicyController controller; + try { + controller = PolicyEngine.manager.updatePolicyController(controllerConfiguration); + if (controller == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + " does not exist")).build(); + } catch (final IllegalArgumentException e) { + logger.info("{}: cannot update policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + " not found: " + e.getMessage())).build(); + } catch (final Exception e) { + logger.info("{}: cannot update policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + " not acceptable")).build(); } - - @DELETE - @Path("engine/topics/sources/ueb/{topic}/switches/lock") - @ApiOperation( - value="Unlocks an UEB Source topic", - response=UebTopicSource.class - ) - @ApiResponses(value = { - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response uebTopicUnlock(@ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic) { - UebTopicSource source = TopicEndpoint.manager.getUebTopicSource(topic); - boolean success = source.unlock(); - if (success) - return Response.status(Status.OK). - entity(source). - build(); - else - return Response.status(Status.NOT_ACCEPTABLE). - entity(new Error("cannot perform operation on " + topic)). - build(); + + return Response.status(Response.Status.OK).entity(controller).build(); + } + + @GET + @Path("engine/controllers/{controller}/switches") + @ApiOperation(value = "Policy Controller Switches", + notes = "List of the Policy Controller Switches", responseContainer = "List") + public Response controllerSwitches() { + return Response.status(Response.Status.OK).entity(Arrays.asList(Switches.values())).build(); + } + + @PUT + @Path("engine/controllers/{controller}/switches/lock") + @ApiOperation(value = "Switches on the Policy Controller Lock Control", + notes = "This action on the switch locks the Policy Controller", + response = PolicyController.class) + @ApiResponses(value = { + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response controllerLock(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + final PolicyController policyController = PolicyController.factory.get(controllerName); + final boolean success = policyController.lock(); + if (success) + return Response.status(Status.OK).entity(policyController).build(); + else + return Response.status(Status.NOT_ACCEPTABLE) + .entity(new Error("Controller " + controllerName + " cannot be locked")).build(); + } + + @DELETE + @Path("engine/controllers/{controller}/switches/lock") + @ApiOperation(value = "Switches off the Policy Controller Lock Control", + notes = "This action on the switch unlocks the Policy Controller", + response = PolicyController.class) + @ApiResponses(value = { + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response controllerUnlock(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + final PolicyController policyController = PolicyController.factory.get(controllerName); + final boolean success = policyController.unlock(); + if (success) + return Response.status(Status.OK).entity(policyController).build(); + else + return Response.status(Status.NOT_ACCEPTABLE) + .entity(new Error("Controller " + controllerName + " cannot be unlocked")).build(); + } + + @GET + @Path("engine/controllers/{controller}/drools") + @ApiOperation(value = "Retrieves the Drools Controller subcomponent of the Policy Controller", + notes = "The Drools Controller provides an abstraction over the Drools subsystem", + response = DroolsController.class) + @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response drools(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + return Response.status(Response.Status.OK).entity(drools).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + " not acceptable")).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/drools/facts") + @ApiOperation(value = "Retrieves Facts Summary information for a given controller", + notes = "Provides the session names, and a count of fact object in the drools working memory", + responseContainer = "Map") + @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response droolsFacts(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + try { + final Map<String, Long> sessionCounts = new HashMap<>(); + final DroolsController drools = this.getDroolsController(controllerName); + for (final String session : drools.getSessionNames()) { + sessionCounts.put(session, drools.factCount(session)); + } + return Response.status(Response.Status.OK).entity(sessionCounts).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + " not acceptable")).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/drools/facts/{session}") + @ApiOperation(value = "Retrieves Fact Types (classnames) for a given controller and its count", + notes = "The fact types are the classnames of the objects inserted in the drools working memory", + responseContainer = "Map") + @ApiResponses( + value = {@ApiResponse(code = 404, message = "The controller or session cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response droolsFacts( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Drools Session Name", + required = true) @PathParam("session") String sessionName) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + return Response.status(Response.Status.OK).entity(drools.factClassNames(sessionName)).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND).entity(new Error("entity not found")) + .build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + sessionName + " not acceptable")).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/drools/facts/{session}/{factType}") + @ApiOperation( + value = "Retrieves fact objects of a given type in the drools working memory" + + "for a given controller and session", + notes = "The fact types are the classnames of the objects inserted in the drools working memory", + responseContainer = "List") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "The controller, session, or fact type cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response droolsFacts( + @ApiParam(value = "Fact count", + required = false) @DefaultValue("false") @QueryParam("count") boolean count, + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Drools Session Name", + required = true) @PathParam("session") String sessionName, + @ApiParam(value = "Drools Fact Type", + required = true) @PathParam("factType") String factType) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final List<Object> facts = drools.facts(sessionName, factType, false); + if (!count) + return Response.status(Response.Status.OK).entity(facts).build(); + else + return Response.status(Response.Status.OK).entity(facts.size()).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + sessionName + ":" + factType + " not found")) + .build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity( + new Error(controllerName + ":" + sessionName + ":" + factType + " not acceptable")) + .build(); + } + } + + @DELETE + @Path("engine/controllers/{controller}/drools/facts/{session}/{factType}") + @ApiOperation( + value = "Deletes all the fact objects of a given type from the drools working memory" + + "for a given controller and session. The objects retracted from the working " + + "memory are provided in the response.", + notes = "The fact types are the classnames of the objects inserted in the drools working memory", + responseContainer = "List") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "The controller, session, or fact type, cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + + "this request to be fulfilled"), + @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) + public Response droolsFactsDelete( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Drools Session Name", + required = true) @PathParam("session") String sessionName, + @ApiParam(value = "Drools Fact Type", + required = true) @PathParam("factType") String factType) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final List<Object> facts = drools.facts(sessionName, factType, true); + return Response.status(Response.Status.OK).entity(facts).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get: drools-controller {}, session {}, factType {}, because of {}", + this, controllerName, sessionName, factType, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + sessionName + ":" + factType + " not found")) + .build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get: drools-controller {}, session {}, factType {}, because of {}", + this, controllerName, sessionName, factType, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity( + new Error(controllerName + ":" + sessionName + ":" + factType + " not acceptable")) + .build(); + } catch (final Exception e) { + logger.debug("{}: cannot get: drools-controller {}, session {}, factType {}, because of {}", + this, controllerName, sessionName, factType, e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(new Error(e.getMessage())).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}") + @ApiOperation( + value = "Gets all the fact objects returned by a DRL query with no parameters from the drools working memory" + + "for a given controller and session", + notes = "The DRL query must be defined in the DRL file", responseContainer = "List") + @ApiResponses(value = { + @ApiResponse(code = 404, + message = "The controller, session, or query information, cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + + "this request to be fulfilled"), + @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) + public Response droolsFacts( + @ApiParam(value = "Fact count", + required = false) @DefaultValue("false") @QueryParam("count") boolean count, + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Drools Session Name", + required = true) @PathParam("session") String sessionName, + @ApiParam(value = "Query Name Present in DRL", + required = true) @PathParam("query") String queryName, + @ApiParam(value = "Query Identifier Present in the DRL Query", + required = true) @PathParam("queriedEntity") String queriedEntity) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final List<Object> facts = drools.factQuery(sessionName, queryName, queriedEntity, false); + if (!count) + return Response.status(Response.Status.OK).entity(facts).build(); + else + return Response.status(Response.Status.OK).entity(facts.size()).build(); + } catch (final IllegalArgumentException e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error( + controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not found")) + .build(); + } catch (final IllegalStateException e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error( + controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not acceptable")) + .build(); + } catch (final Exception e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(new Error(e.getMessage())).build(); + } + } + + @POST + @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}") + @ApiOperation( + value = "Gets all the fact objects returned by a DRL query with parameters from the drools working memory" + + "for a given controller and session", + notes = "The DRL query with parameters must be defined in the DRL file", + responseContainer = "List") + @ApiResponses(value = { + @ApiResponse(code = 404, + message = "The controller, session, or query information, cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + + "this request to be fulfilled"), + @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) + public Response droolsFacts( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Drools Session Name", + required = true) @PathParam("session") String sessionName, + @ApiParam(value = "Query Name Present in DRL", + required = true) @PathParam("query") String queryName, + @ApiParam(value = "Query Identifier Present in the DRL Query", + required = true) @PathParam("queriedEntity") String queriedEntity, + @ApiParam(value = "Query Parameter Values to pass in the DRL Query", + required = false) List<Object> queryParameters) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + List<Object> facts; + if (queryParameters == null || queryParameters.isEmpty()) + facts = drools.factQuery(sessionName, queryName, queriedEntity, false); + else + facts = drools.factQuery(sessionName, queryName, queriedEntity, false, + queryParameters.toArray()); + return Response.status(Response.Status.OK).entity(facts).build(); + } catch (final IllegalArgumentException e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, queryParameters, + e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error( + controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not found")) + .build(); + } catch (final IllegalStateException e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, queryParameters, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error( + controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not acceptable")) + .build(); + } catch (final Exception e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, queryParameters, + e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(new Error(e.getMessage())).build(); + } + } + + @DELETE + @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}") + @ApiOperation( + value = "Deletes all the fact objects returned by a DRL query with parameters from the drools working memory" + + "for a given controller and session", + notes = "The DRL query with parameters must be defined in the DRL file", + responseContainer = "List") + @ApiResponses(value = { + @ApiResponse(code = 404, + message = "The controller, session, or query information, cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + + "this request to be fulfilled"), + @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) + public Response droolsFactsDelete( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Drools Session Name", + required = true) @PathParam("session") String sessionName, + @ApiParam(value = "Query Name Present in DRL", + required = true) @PathParam("query") String queryName, + @ApiParam(value = "Query Identifier Present in the DRL Query", + required = true) @PathParam("queriedEntity") String queriedEntity, + @ApiParam(value = "Query Parameter Values to pass in the DRL Query", + required = false) List<Object> queryParameters) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + List<Object> facts; + if (queryParameters == null || queryParameters.isEmpty()) + facts = drools.factQuery(sessionName, queryName, queriedEntity, true); + else + facts = drools.factQuery(sessionName, queryName, queriedEntity, true, + queryParameters.toArray()); + return Response.status(Response.Status.OK).entity(facts).build(); + } catch (final IllegalArgumentException e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, queryParameters, + e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error( + controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not found")) + .build(); + } catch (final IllegalStateException e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, queryParameters, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error( + controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not acceptable")) + .build(); + } catch (final Exception e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, queryParameters, + e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(new Error(e.getMessage())).build(); + } + } + + @POST + @Path("engine/controllers/tools/coders/decoders/filters/rules/{ruleName}") + @ApiOperation( + value = "Produces a Decoder Rule Filter in a format that the Policy Controller can understand", + notes = "The result can be used with other APIs to attach a filter to a decoder") + public Response rules( + @ApiParam(value = "Negate regex?", + required = true) @DefaultValue("false") @QueryParam("negate") boolean negate, + @ApiParam(value = "Rule Name", required = true) @PathParam("ruleName") String name, + @ApiParam(value = "Regex expression", required = true) String regex) { + String literalRegex = Pattern.quote(regex); + if (negate) + literalRegex = "^(?!" + literalRegex + "$).*"; + + return Response.status(Status.OK).entity(new JsonProtocolFilter.FilterRule(name, literalRegex)) + .build(); + } + + @GET + @Path("engine/controllers/{controller}/decoders") + @ApiOperation(value = "Gets all the decoders used by a controller", + notes = "A Policy Controller uses decoders to deserialize incoming network messages from " + + "subscribed network topics into specific (fact) objects. " + + "The deserialized (fact) object will typically be inserted in the drools working " + + " memory of the controlled drools application.", + responseContainer = "List", response = ProtocolCoderToolset.class) + @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response decoders(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final List<ProtocolCoderToolset> decoders = + EventProtocolCoder.manager.getDecoders(drools.getGroupId(), drools.getArtifactId()); + return Response.status(Response.Status.OK).entity(decoders).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, + controllerName, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, + controllerName, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + " not acceptable")).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/decoders/filters") + @ApiOperation(value = "Gets all the filters used by a controller", + notes = "A Policy Controller uses decoders to deserialize incoming network messages from " + + "subscribed network topics into specific (fact) objects. " + + "The deserialized (fact) object will typically be inserted in the drools working " + + " memory of the controlled drools application." + + "Acceptance filters are used to filter out undesired network messages for the given controller", + responseContainer = "List", response = CoderFilters.class) + @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response decoderFilters(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final List<CoderFilters> filters = + EventProtocolCoder.manager.getDecoderFilters(drools.getGroupId(), drools.getArtifactId()); + return Response.status(Response.Status.OK).entity(filters).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, + controllerName, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, + controllerName, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + " not acceptable")).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/decoders/{topic}") + @ApiOperation(value = "Gets all the decoders in use by a controller for a networked topic", + notes = "A Policy Controller uses decoders to deserialize incoming network messages from " + + "subscribed network topics into specific (fact) objects. " + + "The deserialized (fact) object will typically be inserted in the drools working " + + " memory of the controlled drools application.", + responseContainer = "List", response = ProtocolCoderToolset.class) + @ApiResponses( + value = {@ApiResponse(code = 404, message = "The controller or topic cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response decoder( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Networked Topic Name", required = true) @PathParam("topic") String topic) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final ProtocolCoderToolset decoder = EventProtocolCoder.manager + .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); + return Response.status(Response.Status.OK).entity(decoder).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, + controllerName, topic, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + topic + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, + controllerName, topic, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + topic + " not acceptable")).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/decoders/{topic}/filters") + @ApiOperation( + value = "Gets all filters attached to decoders for a given networked topic in use by a controller", + notes = "A Policy Controller uses decoders to deserialize incoming network messages from " + + "subscribed network topics into specific (fact) objects. " + + "The deserialized (fact) object will typically be inserted in the drools working " + + " memory of the controlled drools application." + + "Acceptance filters are used to filter out undesired network messages for the given controller", + responseContainer = "List", response = CoderFilters.class) + @ApiResponses( + value = {@ApiResponse(code = 404, message = "The controller or topic cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response decoderFilter( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Networked Topic Name", required = true) @PathParam("topic") String topic) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final ProtocolCoderToolset decoder = EventProtocolCoder.manager + .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); + if (decoder == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(topic + " does not exist")).build(); + else + return Response.status(Response.Status.OK).entity(decoder.getCoders()).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, + controllerName, topic, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + topic + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, + controllerName, topic, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + topic + " not acceptable")).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}") + @ApiOperation( + value = "Gets all filters attached to decoders for a given subscribed networked topic " + + "and fact type", + notes = "Decoders are associated with networked topics. A Policy Controller manages " + + "multiple topics and therefore its attached decoders. " + + "A Policy Controller uses filters to further specify the fact mapping. " + + "Filters are applied on a per fact type (classname).", + responseContainer = "List", response = CoderFilters.class) + @ApiResponses(value = { + @ApiResponse(code = 404, message = "The controller, topic, or fact type cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response decoderFilter( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Networked Topic Name", required = true) @PathParam("topic") String topic, + @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final ProtocolCoderToolset decoder = EventProtocolCoder.manager + .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); + final CoderFilters filters = decoder.getCoder(factClass); + if (filters == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(topic + ":" + factClass + " does not exist")).build(); + else + return Response.status(Response.Status.OK).entity(filters).build(); + } catch (final IllegalArgumentException e) { + logger.debug( + "{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}", + this, controllerName, topic, factClass, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug( + "{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}", + this, controllerName, topic, factClass, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not acceptable")) + .build(); + } + } + + @PUT + @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}") + @ApiOperation( + value = "Attaches filters to the decoder for a given networked topic " + "and fact type", + notes = "Decoders are associated with networked topics. A Policy Controller manages " + + "multiple topics and therefore its attached decoders. " + + "A Policy Controller uses filters to further specify the fact mapping. " + + "Filters are applied on a per fact type (classname).", + responseContainer = "List", response = CoderFilters.class) + @ApiResponses(value = { + @ApiResponse(code = 404, + message = "The controller, topic, fact type, cannot be found, " + + "or a filter has not been provided"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response decoderFilter( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic, + @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass, + @ApiParam(value = "Configuration Filter", required = true) JsonProtocolFilter configFilters) { + + if (configFilters == null) { + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error("Configuration Filters not provided")).build(); } - - @GET - @Path("engine/topics/sources/dmaap/{topic}/switches") - @ApiOperation( - value="DMaaP Topic Control Switches", - notes="List of the DMaaP Topic Control Switches", - responseContainer="List" - ) - public Response dmaapTopicSwitches() { - return Response.status(Response.Status.OK). - entity(Arrays.asList(Switches.values())). - build(); + + try { + final DroolsController drools = this.getDroolsController(controllerName); + final ProtocolCoderToolset decoder = EventProtocolCoder.manager + .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); + final CoderFilters filters = decoder.getCoder(factClass); + if (filters == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(topic + ":" + factClass + " does not exist")).build(); + filters.setFilter(configFilters); + return Response.status(Response.Status.OK).entity(filters).build(); + } catch (final IllegalArgumentException e) { + logger.debug( + "{}: cannot get decoder filters for policy-controller {} topic {} type {} filters {} because of {}", + this, controllerName, topic, factClass, configFilters, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug( + "{}: cannot get decoder filters for policy-controller {} topic {} type {} filters {} because of {}", + this, controllerName, topic, factClass, configFilters, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not acceptable")) + .build(); + } + } + + @GET + @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rules") + @ApiOperation(value = "Gets the filter rules attached to a topic decoder of a controller", + notes = "Decoders are associated with networked topics. A Policy Controller manages " + + "multiple topics and therefore its attached decoders. " + + "A Policy Controller uses filters to further specify the fact mapping. " + + "Filters are applied on a per fact type and are composed of field matching rules. ", + responseContainer = "List", response = FilterRule.class) + @ApiResponses(value = { + @ApiResponse(code = 404, message = "The controller, topic, or fact type cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response decoderFilterRules( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic, + @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final ProtocolCoderToolset decoder = EventProtocolCoder.manager + .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); + + final CoderFilters filters = decoder.getCoder(factClass); + if (filters == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " does not exist")) + .build(); + + final JsonProtocolFilter filter = filters.getFilter(); + if (filter == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " no filters")) + .build(); + + return Response.status(Response.Status.OK).entity(filter.getRules()).build(); + } catch (final IllegalArgumentException e) { + logger.debug( + "{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}", + this, controllerName, topic, factClass, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug( + "{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}", + this, controllerName, topic, factClass, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not acceptable")) + .build(); + } + } + + @GET + @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rules/{ruleName}") + @ApiOperation(value = "Gets a filter rule by name attached to a topic decoder of a controller", + notes = "Decoders are associated with networked topics. A Policy Controller manages " + + "multiple topics and therefore its attached decoders. " + + "A Policy Controller uses filters to further specify the fact mapping. " + + "Filters are applied on a per fact type and are composed of field matching rules. ", + responseContainer = "List", response = FilterRule.class) + @ApiResponses(value = { + @ApiResponse(code = 404, + message = "The controller, topic, fact type, or rule name cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response decoderFilterRules( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic, + @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass, + @ApiParam(value = "Rule Name", required = true) @PathParam("ruleName") String ruleName) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final ProtocolCoderToolset decoder = EventProtocolCoder.manager + .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); + + final CoderFilters filters = decoder.getCoder(factClass); + if (filters == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " does not exist")) + .build(); + + final JsonProtocolFilter filter = filters.getFilter(); + if (filter == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " no filters")) + .build(); + + return Response.status(Response.Status.OK).entity(filter.getRules(ruleName)).build(); + } catch (final IllegalArgumentException e) { + logger.debug( + "{}: cannot get decoder filters for policy-controller {} topic {} type {} rule {} because of {}", + this, controllerName, topic, factClass, ruleName, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error( + controllerName + ":" + topic + ":" + factClass + ": " + ruleName + " not found")) + .build(); + } catch (final IllegalStateException e) { + logger.debug( + "{}: cannot get decoder filters for policy-controller {} topic {} type {} rule {} because of {}", + this, controllerName, topic, factClass, ruleName, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error( + controllerName + ":" + topic + ":" + factClass + ":" + ruleName + " not acceptable")) + .build(); + } + } + + @DELETE + @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rules/{ruleName}") + @ApiOperation(value = "Deletes a filter rule by name attached to a topic decoder of a controller", + notes = "Decoders are associated with networked topics. A Policy Controller manages " + + "multiple topics and therefore its attached decoders. " + + "A Policy Controller uses filters to further specify the fact mapping. " + + "Filters are applied on a per fact type and are composed of field matching rules. ", + responseContainer = "List", response = FilterRule.class) + @ApiResponses(value = { + @ApiResponse(code = 404, + message = "The controller, topic, fact type, or rule name cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response decoderFilterRuleDelete( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic, + @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass, + @ApiParam(value = "Rule Name", required = true) @PathParam("ruleName") String ruleName, + @ApiParam(value = "Filter Rule", required = true) FilterRule rule) { + + try { + final DroolsController drools = this.getDroolsController(controllerName); + final ProtocolCoderToolset decoder = EventProtocolCoder.manager + .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); + + final CoderFilters filters = decoder.getCoder(factClass); + if (filters == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " does not exist")) + .build(); + + final JsonProtocolFilter filter = filters.getFilter(); + if (filter == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " no filters")) + .build(); + + if (rule == null) { + filter.deleteRules(ruleName); + return Response.status(Response.Status.OK).entity(filter.getRules()).build(); + } + + if (rule.getName() == null || !rule.getName().equals(ruleName)) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + ":" + ruleName + + " rule name request inconsistencies (" + rule.getName() + ")")) + .build(); + + filter.deleteRule(ruleName, rule.getRegex()); + return Response.status(Response.Status.OK).entity(filter.getRules()).build(); + } catch (final IllegalArgumentException e) { + logger.debug( + "{}: cannot get decoder filters for policy-controller {} topic {} type {} rule {} because of {}", + this, controllerName, topic, factClass, ruleName, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error( + controllerName + ":" + topic + ":" + factClass + ": " + ruleName + " not found")) + .build(); + } catch (final IllegalStateException e) { + logger.debug( + "{}: cannot get decoder filters for policy-controller {} topic {} type {} rule {} because of {}", + this, controllerName, topic, factClass, ruleName, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error( + controllerName + ":" + topic + ":" + factClass + ":" + ruleName + " not acceptable")) + .build(); + } + } + + @PUT + @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}/rules") + @ApiOperation(value = "Places a new filter rule in a topic decoder", + notes = "Decoders are associated with networked topics. A Policy Controller manages " + + "multiple topics and therefore its attached decoders. " + + "A Policy Controller uses filters to further specify the fact mapping. " + + "Filters are applied on a per fact type and are composed of field matching rules. ", + responseContainer = "List", response = FilterRule.class) + @ApiResponses(value = { + @ApiResponse(code = 404, message = "The controller, topic, or fact type cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response decoderFilterRule( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic, + @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass, + @ApiParam(value = "Rule Name", required = true) @PathParam("ruleName") String ruleName, + @ApiParam(value = "Filter Rule", required = true) FilterRule rule) { + + try { + final DroolsController drools = this.getDroolsController(controllerName); + final ProtocolCoderToolset decoder = EventProtocolCoder.manager + .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); + + final CoderFilters filters = decoder.getCoder(factClass); + if (filters == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " does not exist")) + .build(); + + final JsonProtocolFilter filter = filters.getFilter(); + if (filter == null) + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " no filters")) + .build(); + + if (rule.getName() == null) + return Response + .status(Response.Status.BAD_REQUEST).entity(new Error(controllerName + ":" + topic + ":" + + factClass + " rule name request inconsistencies (" + rule.getName() + ")")) + .build(); + + filter.addRule(rule.getName(), rule.getRegex()); + return Response.status(Response.Status.OK).entity(filter.getRules()).build(); + } catch (final IllegalArgumentException e) { + logger.debug( + "{}: cannot access decoder filter rules for policy-controller {} topic {} type {} rule {} because of {}", + this, controllerName, topic, factClass, ruleName, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug( + "{}: cannot access decoder filter rules for policy-controller {} topic {} type {} rule {} because of {}", + this, controllerName, topic, factClass, ruleName, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not acceptable")) + .build(); + } + } + + @POST + @Path("engine/controllers/{controller}/decoders/{topic}") + @Consumes(MediaType.TEXT_PLAIN) + @ApiOperation(value = "Decodes a string into a fact object, and encodes it back into a string", + notes = "Tests the decode/encode functions of a controller", response = CodingResult.class) + @ApiResponses(value = {@ApiResponse(code = 400, message = "Bad input has been provided"), + @ApiResponse(code = 404, message = "The controller cannot be found"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response decode( + @ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic, + @ApiParam(value = "JSON String to decode", required = true) String json) { + + PolicyController policyController; + try { + policyController = PolicyController.factory.get(controllerName); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, + controllerName, topic, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + topic + ":" + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, + controllerName, topic, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + topic + ":" + " not acceptable")).build(); } - - @PUT - @Path("engine/topics/sources/dmaap/{topic}/switches/lock") - @ApiOperation( - value="Locks an DMaaP Source topic", - response=DmaapTopicSource.class - ) - @ApiResponses(value = { - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response dmmapTopicLock(@ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic) { - DmaapTopicSource source = TopicEndpoint.manager.getDmaapTopicSource(topic); - boolean success = source.lock(); - if (success) - return Response.status(Status.OK). - entity(source). - build(); - else - return Response.status(Status.NOT_ACCEPTABLE). - entity(new Error("cannot perform operation on " + topic)). - build(); + + final CodingResult result = new CodingResult(); + result.decoding = false; + result.encoding = false; + result.jsonEncoding = null; + + Object event; + try { + event = EventProtocolCoder.manager.decode(policyController.getDrools().getGroupId(), + policyController.getDrools().getArtifactId(), topic, json); + result.decoding = true; + } catch (final Exception e) { + logger.debug("{}: cannot get policy-controller {} topic {} because of {}", this, + controllerName, topic, e.getMessage(), e); + return Response.status(Response.Status.BAD_REQUEST).entity(new Error(e.getMessage())).build(); } - - @DELETE - @Path("engine/topics/sources/dmaap/{topic}/switches/lock") - @ApiOperation( - value="Unlocks an DMaaP Source topic", - response=DmaapTopicSource.class - ) - @ApiResponses(value = { - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled") - }) - public Response dmaapTopicUnlock(@ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic) { - DmaapTopicSource source = TopicEndpoint.manager.getDmaapTopicSource(topic); - boolean success = source.unlock(); - if (success) - return Response.status(Status.OK). - entity(source). - build(); - else - return Response.status(Status.SERVICE_UNAVAILABLE). - entity(new Error("cannot perform operation on " + topic)). - build(); + + try { + result.jsonEncoding = EventProtocolCoder.manager.encode(topic, event); + result.encoding = true; + } catch (final Exception e) { + // continue so to propagate decoding results .. + logger.debug("{}: cannot encode for policy-controller {} topic {} because of {}", this, + controllerName, topic, e.getMessage(), e); } - - @PUT - @Path("engine/topics/sources/ueb/{topic}/events") - @Consumes(MediaType.TEXT_PLAIN) - @ApiOperation( - value="Offers an event to an UEB topic for internal processing by the engine", - notes="The offered event is treated as it was incoming from the network", - responseContainer="List" - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The topic information cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled"), - @ApiResponse(code=500, message="A server error has occurred processing this request") - }) - public Response uebOffer(@ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic, - @ApiParam(value="Network Message", required=true) - String json) { - try { - UebTopicSource uebReader = TopicEndpoint.manager.getUebTopicSource(topic); - boolean success = uebReader.offer(json); - if (success) - return Response.status(Status.OK). - entity(Arrays.asList(TopicEndpoint.manager.getUebTopicSource(topic).getRecentEvents())). - build(); - else - return Response.status(Status.NOT_ACCEPTABLE). - entity(new Error("Failure to inject event over " + topic)). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot offer for encoder ueb topic for {} because of {}", - this, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(topic + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot offer for encoder ueb topic for {} because of {}", - this, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(topic + " not acceptable due to current state")). - build(); - } catch (Exception e) { - logger.debug("{}: cannot offer for encoder ueb topic for {} because of {}", - this, topic, e.getMessage(), e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR). - entity(new Error(e.getMessage())). - build(); - } + + return Response.status(Response.Status.OK).entity(result).build(); + } + + @GET + @Path("engine/controllers/{controller}/encoders") + @ApiOperation(value = "Retrieves the encoder filters of a controller", + notes = "The encoders serializes a fact object, typically for network transmission", + responseContainer = "List", response = CoderFilters.class) + @ApiResponses(value = {@ApiResponse(code = 400, message = "Bad input has been provided"), + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response encoderFilters(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + List<CoderFilters> encoders; + try { + final PolicyController controller = PolicyController.factory.get(controllerName); + final DroolsController drools = controller.getDrools(); + encoders = + EventProtocolCoder.manager.getEncoderFilters(drools.getGroupId(), drools.getArtifactId()); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get encoder filters for policy-controller {} because of {}", this, + controllerName, e.getMessage(), e); + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + " not found: " + e.getMessage())).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get encoder filters for policy-controller {} because of {}", this, + controllerName, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + " is not accepting the request")).build(); } - - @PUT - @Path("engine/topics/sources/dmaap/{topic}/events") - @Consumes(MediaType.TEXT_PLAIN) - @ApiOperation( - value="Offers an event to a DMaaP topic for internal processing by the engine", - notes="The offered event is treated as it was incoming from the network", - responseContainer="List" - ) - @ApiResponses(value = { - @ApiResponse(code=404, message="The topic information cannot be found"), - @ApiResponse(code=406, message="The system is an administrative state that prevents " + - "this request to be fulfilled"), - @ApiResponse(code=500, message="A server error has occurred processing this request") - }) - public Response dmaapOffer(@ApiParam(value="Topic Name", required=true) - @PathParam("topic") String topic, - @ApiParam(value="Network Message", required=true) - String json) { - try { - DmaapTopicSource dmaapReader = TopicEndpoint.manager.getDmaapTopicSource(topic); - boolean success = dmaapReader.offer(json); - if (success) - return Response.status(Status.OK). - entity(Arrays.asList(TopicEndpoint.manager.getDmaapTopicSource(topic).getRecentEvents())). - build(); - else - return Response.status(Status.NOT_ACCEPTABLE). - entity(new Error("Failure to inject event over " + topic)). - build(); - } catch (IllegalArgumentException e) { - logger.debug("{}: cannot offer for encoder dmaap topic for {} because of {}", - this, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND). - entity(new Error(topic + " not found")). - build(); - } catch (IllegalStateException e) { - logger.debug("{}: cannot offer for encoder dmaap topic for {} because of {}", - this, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE). - entity(new Error(topic + " not acceptable due to current state")). - build(); - } catch (Exception e) { - logger.debug("{}: cannot offer for encoder dmaap topic for {} because of {}", - this, topic, e.getMessage(), e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR). - entity(new Error(e.getMessage())). - build(); - } + + return Response.status(Response.Status.OK).entity(encoders).build(); + } + + @GET + @Path("engine/topics") + @ApiOperation(value = "Retrieves the managed topics", notes = "Network Topics Aggregation", + response = TopicEndpoint.class) + public Response topics() { + return Response.status(Response.Status.OK).entity(TopicEndpoint.manager).build(); + } + + @GET + @Path("engine/topics/switches") + @ApiOperation(value = "Topics Control Switches", notes = "List of the Topic Control Switches", + responseContainer = "List") + public Response topicSwitches() { + return Response.status(Response.Status.OK).entity(Arrays.asList(Switches.values())).build(); + } + + @PUT + @Path("engine/topics/switches/lock") + @ApiOperation(value = "Locks all the managed topics", + notes = "The operation affects all managed sources and sinks", response = TopicEndpoint.class) + @ApiResponses(value = { + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response topicsLock() { + final boolean success = TopicEndpoint.manager.lock(); + if (success) + return Response.status(Status.OK).entity(TopicEndpoint.manager).build(); + else + return Response.status(Status.NOT_ACCEPTABLE).entity(new Error("cannot perform operation")) + .build(); + } + + @DELETE + @Path("engine/topics/switches/lock") + @ApiOperation(value = "Unlocks all the managed topics", + notes = "The operation affects all managed sources and sinks", response = TopicEndpoint.class) + @ApiResponses(value = { + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response topicsUnlock() { + final boolean success = TopicEndpoint.manager.unlock(); + if (success) + return Response.status(Status.OK).entity(TopicEndpoint.manager).build(); + else + return Response.status(Status.NOT_ACCEPTABLE).entity(new Error("cannot perform operation")) + .build(); + } + + @GET + @Path("engine/topics/sources") + @ApiOperation(value = "Retrieves the managed topic sources", + notes = "Network Topic Sources Agregation", responseContainer = "List", + response = TopicSource.class) + public Response sources() { + return Response.status(Response.Status.OK).entity(TopicEndpoint.manager.getTopicSources()) + .build(); + } + + @GET + @Path("engine/topics/sinks") + @ApiOperation(value = "Retrieves the managed topic sinks", + notes = "Network Topic Sinks Agregation", responseContainer = "List", + response = TopicSink.class) + public Response sinks() { + return Response.status(Response.Status.OK).entity(TopicEndpoint.manager.getTopicSinks()) + .build(); + } + + @GET + @Path("engine/topics/sources/ueb") + @ApiOperation(value = "Retrieves the UEB managed topic sources", + notes = "UEB Topic Sources Agregation", responseContainer = "List", + response = UebTopicSource.class) + public Response uebSources() { + return Response.status(Response.Status.OK).entity(TopicEndpoint.manager.getUebTopicSources()) + .build(); + } + + @GET + @Path("engine/topics/sinks/ueb") + @ApiOperation(value = "Retrieves the UEB managed topic sinks", + notes = "UEB Topic Sinks Agregation", responseContainer = "List", + response = UebTopicSource.class) + public Response uebSinks() { + return Response.status(Response.Status.OK).entity(TopicEndpoint.manager.getUebTopicSinks()) + .build(); + } + + @GET + @Path("engine/topics/sources/dmaap") + @ApiOperation(value = "Retrieves the DMaaP managed topic sources", + notes = "DMaaP Topic Sources Agregation", responseContainer = "List", + response = DmaapTopicSource.class) + public Response dmaapSources() { + return Response.status(Response.Status.OK).entity(TopicEndpoint.manager.getDmaapTopicSources()) + .build(); + } + + @GET + @Path("engine/topics/sinks/dmaap") + @ApiOperation(value = "Retrieves the DMaaP managed topic sinks", + notes = "DMaaP Topic Sinks Agregation", responseContainer = "List", + response = DmaapTopicSink.class) + public Response dmaapSinks() { + return Response.status(Response.Status.OK).entity(TopicEndpoint.manager.getDmaapTopicSinks()) + .build(); + } + + @GET + @Path("engine/topics/sources/ueb/{topic}") + @ApiOperation(value = "Retrieves an UEB managed topic source", + notes = "This is an UEB Network Communicaton Endpoint source of messages for the Engine", + response = UebTopicSource.class) + public Response uebSourceTopic( + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic) { + return Response.status(Response.Status.OK) + .entity(TopicEndpoint.manager.getUebTopicSource(topic)).build(); + } + + @GET + @Path("engine/topics/sinks/ueb/{topic}") + @ApiOperation(value = "Retrieves an UEB managed topic sink", + notes = "This is an UEB Network Communicaton Endpoint destination of messages from the Engine", + response = UebTopicSink.class) + public Response uebSinkTopic( + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic) { + return Response.status(Response.Status.OK).entity(TopicEndpoint.manager.getUebTopicSink(topic)) + .build(); + } + + @GET + @Path("engine/topics/sources/dmaap/{topic}") + @ApiOperation(value = "Retrieves a DMaaP managed topic source", + notes = "This is a DMaaP Network Communicaton Endpoint source of messages for the Engine", + response = DmaapTopicSource.class) + public Response dmaapSourceTopic( + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic) { + return Response.status(Response.Status.OK) + .entity(TopicEndpoint.manager.getDmaapTopicSource(topic)).build(); + } + + @GET + @Path("engine/topics/sinks/dmaap/{topic}") + @ApiOperation(value = "Retrieves a DMaaP managed topic sink", + notes = "This is a DMaaP Network Communicaton Endpoint destination of messages from the Engine", + response = DmaapTopicSink.class) + public Response dmaapSinkTopic( + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic) { + return Response.status(Response.Status.OK) + .entity(TopicEndpoint.manager.getDmaapTopicSink(topic)).build(); + } + + @GET + @Path("engine/topics/sources/ueb/{topic}/events") + @ApiOperation(value = "Retrieves the latest events received by an UEB topic", + notes = "This is a UEB Network Communicaton Endpoint source of messages for the Engine", + responseContainer = "List") + public Response uebSourceEvents( + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic) { + return Response.status(Status.OK) + .entity(Arrays.asList(TopicEndpoint.manager.getUebTopicSource(topic).getRecentEvents())) + .build(); + } + + @GET + @Path("engine/topics/sinks/ueb/{topic}/events") + @ApiOperation(value = "Retrieves the latest events sent from a topic", + notes = "This is a UEB Network Communicaton Endpoint sink of messages from the Engine", + responseContainer = "List") + public Response uebSinkEvents( + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic) { + return Response.status(Status.OK) + .entity(Arrays.asList(TopicEndpoint.manager.getUebTopicSink(topic).getRecentEvents())) + .build(); + } + + @GET + @Path("engine/topics/sources/dmaap/{topic}/events") + @ApiOperation(value = "Retrieves the latest events received by a DMaaP topic", + notes = "This is a DMaaP Network Communicaton Endpoint source of messages for the Engine", + responseContainer = "List") + public Response dmaapSourceEvents( + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic) { + return Response.status(Status.OK) + .entity(Arrays.asList(TopicEndpoint.manager.getDmaapTopicSource(topic).getRecentEvents())) + .build(); + } + + @GET + @Path("engine/topics/sinks/dmaap/{topic}/events") + @ApiOperation(value = "Retrieves the latest events send through a DMaaP topic", + notes = "This is a DMaaP Network Communicaton Endpoint destination of messages from the Engine", + responseContainer = "List") + public Response dmaapSinkEvents(@PathParam("topic") String topic) { + return Response.status(Status.OK) + .entity(Arrays.asList(TopicEndpoint.manager.getDmaapTopicSink(topic).getRecentEvents())) + .build(); + } + + @GET + @Path("engine/topics/sources/ueb/{topic}/switches") + @ApiOperation(value = "UEB Topic Control Switches", + notes = "List of the UEB Topic Control Switches", responseContainer = "List") + public Response uebTopicSwitches() { + return Response.status(Response.Status.OK).entity(Arrays.asList(Switches.values())).build(); + } + + @PUT + @Path("engine/topics/sources/ueb/{topic}/switches/lock") + @ApiOperation(value = "Locks an UEB Source topic", response = UebTopicSource.class) + @ApiResponses(value = { + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response uebTopicLock( + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic) { + final UebTopicSource source = TopicEndpoint.manager.getUebTopicSource(topic); + final boolean success = source.lock(); + if (success) + return Response.status(Status.OK).entity(source).build(); + else + return Response.status(Status.NOT_ACCEPTABLE) + .entity(new Error("cannot perform operation on " + topic)).build(); + } + + @DELETE + @Path("engine/topics/sources/ueb/{topic}/switches/lock") + @ApiOperation(value = "Unlocks an UEB Source topic", response = UebTopicSource.class) + @ApiResponses(value = { + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response uebTopicUnlock( + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic) { + final UebTopicSource source = TopicEndpoint.manager.getUebTopicSource(topic); + final boolean success = source.unlock(); + if (success) + return Response.status(Status.OK).entity(source).build(); + else + return Response.status(Status.NOT_ACCEPTABLE) + .entity(new Error("cannot perform operation on " + topic)).build(); + } + + @GET + @Path("engine/topics/sources/dmaap/{topic}/switches") + @ApiOperation(value = "DMaaP Topic Control Switches", + notes = "List of the DMaaP Topic Control Switches", responseContainer = "List") + public Response dmaapTopicSwitches() { + return Response.status(Response.Status.OK).entity(Arrays.asList(Switches.values())).build(); + } + + @PUT + @Path("engine/topics/sources/dmaap/{topic}/switches/lock") + @ApiOperation(value = "Locks an DMaaP Source topic", response = DmaapTopicSource.class) + @ApiResponses(value = { + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response dmmapTopicLock( + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic) { + final DmaapTopicSource source = TopicEndpoint.manager.getDmaapTopicSource(topic); + final boolean success = source.lock(); + if (success) + return Response.status(Status.OK).entity(source).build(); + else + return Response.status(Status.NOT_ACCEPTABLE) + .entity(new Error("cannot perform operation on " + topic)).build(); + } + + @DELETE + @Path("engine/topics/sources/dmaap/{topic}/switches/lock") + @ApiOperation(value = "Unlocks an DMaaP Source topic", response = DmaapTopicSource.class) + @ApiResponses(value = { + @ApiResponse(code = 406, message = "The system is an administrative state that prevents " + + "this request to be fulfilled")}) + public Response dmaapTopicUnlock( + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic) { + final DmaapTopicSource source = TopicEndpoint.manager.getDmaapTopicSource(topic); + final boolean success = source.unlock(); + if (success) + return Response.status(Status.OK).entity(source).build(); + else + return Response.status(Status.SERVICE_UNAVAILABLE) + .entity(new Error("cannot perform operation on " + topic)).build(); + } + + @PUT + @Path("engine/topics/sources/ueb/{topic}/events") + @Consumes(MediaType.TEXT_PLAIN) + @ApiOperation(value = "Offers an event to an UEB topic for internal processing by the engine", + notes = "The offered event is treated as it was incoming from the network", + responseContainer = "List") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "The topic information cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + + "this request to be fulfilled"), + @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) + public Response uebOffer( + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic, + @ApiParam(value = "Network Message", required = true) String json) { + try { + final UebTopicSource uebReader = TopicEndpoint.manager.getUebTopicSource(topic); + final boolean success = uebReader.offer(json); + if (success) + return Response.status(Status.OK) + .entity(Arrays.asList(TopicEndpoint.manager.getUebTopicSource(topic).getRecentEvents())) + .build(); + else + return Response.status(Status.NOT_ACCEPTABLE) + .entity(new Error("Failure to inject event over " + topic)).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot offer for encoder ueb topic for {} because of {}", this, topic, + e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND).entity(new Error(topic + " not found")) + .build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot offer for encoder ueb topic for {} because of {}", this, topic, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(topic + " not acceptable due to current state")).build(); + } catch (final Exception e) { + logger.debug("{}: cannot offer for encoder ueb topic for {} because of {}", this, topic, + e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(new Error(e.getMessage())).build(); + } + } + + @PUT + @Path("engine/topics/sources/dmaap/{topic}/events") + @Consumes(MediaType.TEXT_PLAIN) + @ApiOperation(value = "Offers an event to a DMaaP topic for internal processing by the engine", + notes = "The offered event is treated as it was incoming from the network", + responseContainer = "List") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "The topic information cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + + "this request to be fulfilled"), + @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) + public Response dmaapOffer( + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic, + @ApiParam(value = "Network Message", required = true) String json) { + try { + final DmaapTopicSource dmaapReader = TopicEndpoint.manager.getDmaapTopicSource(topic); + final boolean success = dmaapReader.offer(json); + if (success) + return Response.status(Status.OK) + .entity( + Arrays.asList(TopicEndpoint.manager.getDmaapTopicSource(topic).getRecentEvents())) + .build(); + else + return Response.status(Status.NOT_ACCEPTABLE) + .entity(new Error("Failure to inject event over " + topic)).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot offer for encoder dmaap topic for {} because of {}", this, topic, + e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND).entity(new Error(topic + " not found")) + .build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot offer for encoder dmaap topic for {} because of {}", this, topic, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(topic + " not acceptable due to current state")).build(); + } catch (final Exception e) { + logger.debug("{}: cannot offer for encoder dmaap topic for {} because of {}", this, topic, + e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(new Error(e.getMessage())).build(); + } + } + + @GET + @Path("engine/tools/uuid") + @ApiOperation(value = "Produces an UUID", notes = "UUID generation utility") + @Produces(MediaType.TEXT_PLAIN) + public Response uuid() { + return Response.status(Status.OK).entity(UUID.randomUUID().toString()).build(); + } + + @GET + @Path("engine/tools/loggers") + @ApiOperation(value = "all active loggers", responseContainer = "List") + @ApiResponses(value = {@ApiResponse(code = 500, message = "logging misconfiguration")}) + public Response loggers() { + final List<String> names = new ArrayList<String>(); + if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) { + logger.warn("The SLF4J logger factory is not configured for logback"); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(names).build(); } - - @GET - @Path("engine/tools/uuid") - @ApiOperation( - value="Produces an UUID", - notes="UUID generation utility" - ) - @Produces(MediaType.TEXT_PLAIN) - public Response uuid() { - return Response.status(Status.OK). - entity(UUID.randomUUID().toString()). - build(); + + final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + for (final Logger logger : context.getLoggerList()) { + names.add(logger.getName()); } - - @GET - @Path("engine/tools/loggers") - @ApiOperation( - value="all active loggers", - responseContainer="List" - ) - @ApiResponses(value = { - @ApiResponse(code=500, message="logging misconfiguration") - }) - public Response loggers() { - List<String> names = new ArrayList<String>(); - if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) { - logger.warn("The SLF4J logger factory is not configured for logback"); - return Response.status(Status.INTERNAL_SERVER_ERROR). - entity(names).build(); - } - - LoggerContext context = - (LoggerContext) LoggerFactory.getILoggerFactory(); - for (Logger logger: context.getLoggerList()) { - names.add(logger.getName()); - } - - return Response.status(Status.OK). - entity(names). - build(); + + return Response.status(Status.OK).entity(names).build(); + } + + @GET + @Path("engine/tools/loggers/{logger}") + @Produces(MediaType.TEXT_PLAIN) + @ApiOperation(value = "logging level of a logger") + @ApiResponses(value = {@ApiResponse(code = 500, message = "logging misconfiguration"), + @ApiResponse(code = 404, message = "logger not found")}) + public Response loggerName( + @ApiParam(value = "Logger Name", required = true) @PathParam("logger") String loggerName) { + if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) { + logger.warn("The SLF4J logger factory is not configured for logback"); + return Response.status(Status.INTERNAL_SERVER_ERROR).build(); } - - @GET - @Path("engine/tools/loggers/{logger}") - @Produces(MediaType.TEXT_PLAIN) - @ApiOperation( - value="logging level of a logger" - ) - @ApiResponses(value = { - @ApiResponse(code=500, message="logging misconfiguration"), - @ApiResponse(code=404, message="logger not found") - }) - public Response loggerName(@ApiParam(value="Logger Name", required=true) - @PathParam("logger") String loggerName) { - if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) { - logger.warn("The SLF4J logger factory is not configured for logback"); - return Response.status(Status.INTERNAL_SERVER_ERROR).build(); - } - - LoggerContext context = - (LoggerContext) LoggerFactory.getILoggerFactory(); - ch.qos.logback.classic.Logger logger = context.getLogger(loggerName); - if (logger == null) { - return Response.status(Status.NOT_FOUND).build(); - } - - String loggerLevel = (logger.getLevel() != null) ? logger.getLevel().toString() : ""; - return Response.status(Status.OK).entity(loggerLevel).build(); + + final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + final ch.qos.logback.classic.Logger logger = context.getLogger(loggerName); + if (logger == null) { + return Response.status(Status.NOT_FOUND).build(); } - - @PUT - @Path("engine/tools/loggers/{logger}/{level}") - @Produces(MediaType.TEXT_PLAIN) - @Consumes(MediaType.TEXT_PLAIN) - @ApiOperation( - value="sets the logger level", - notes="Please use the SLF4J logger levels" - ) - @ApiResponses(value = { - @ApiResponse(code=500, message="logging misconfiguration"), - @ApiResponse(code=404, message="logger not found") - }) - public Response loggerName(@ApiParam(value="Logger Name", required=true) - @PathParam("logger") String loggerName, - @ApiParam(value="Logger Level", required=true) - @PathParam("level") String loggerLevel) { - if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) { - logger.warn("The SLF4J logger factory is not configured for logback"); - return Response.status(Status.INTERNAL_SERVER_ERROR).build(); - } - - LoggerContext context = - (LoggerContext) LoggerFactory.getILoggerFactory(); - ch.qos.logback.classic.Logger logger = context.getLogger(loggerName); - if (logger == null) { - return Response.status(Status.NOT_FOUND).build(); - } - - logger.setLevel(ch.qos.logback.classic.Level.toLevel(loggerLevel)); - return Response.status(Status.OK).entity(logger.getLevel().toString()).build(); + + final String loggerLevel = (logger.getLevel() != null) ? logger.getLevel().toString() : ""; + return Response.status(Status.OK).entity(loggerLevel).build(); + } + + @PUT + @Path("engine/tools/loggers/{logger}/{level}") + @Produces(MediaType.TEXT_PLAIN) + @Consumes(MediaType.TEXT_PLAIN) + @ApiOperation(value = "sets the logger level", notes = "Please use the SLF4J logger levels") + @ApiResponses(value = {@ApiResponse(code = 500, message = "logging misconfiguration"), + @ApiResponse(code = 404, message = "logger not found")}) + public Response loggerName( + @ApiParam(value = "Logger Name", required = true) @PathParam("logger") String loggerName, + @ApiParam(value = "Logger Level", required = true) @PathParam("level") String loggerLevel) { + + String newLevel; + try { + newLevel = LoggerUtil.setLevel(loggerName, loggerLevel); + } catch (final IllegalArgumentException e) { + logger.warn("{}: no logger {}", this, loggerName, loggerLevel, e); + return Response.status(Status.NOT_FOUND).build(); + } catch (final IllegalStateException e) { + logger.warn("{}: logging framework unavailable for {} / {}", this, loggerName, loggerLevel, + e); + return Response.status(Status.INTERNAL_SERVER_ERROR).build(); } - + + return Response.status(Status.OK).entity(newLevel + + ).build(); + } + + /** + * gets the underlying drools controller from the named policy controller + * + * @param controllerName the policy controller name + * @return the underlying drools controller + * @throws IllegalArgumentException if an invalid controller name has been passed in + */ + protected DroolsController getDroolsController(String controllerName) { + final PolicyController controller = PolicyController.factory.get(controllerName); + if (controller == null) + throw new IllegalArgumentException(controllerName + " does not exist"); + + final DroolsController drools = controller.getDrools(); + if (drools == null) + throw new IllegalArgumentException(controllerName + " has no drools configuration"); + + return drools; + } + + /* + * Helper classes for aggregation of results + */ + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("rest-telemetry-api []"); + return builder.toString(); + } + + /** + * Coding/Encoding Results Aggregation Helper class + */ + public static class CodingResult { /** - * gets the underlying drools controller from the named policy controller - * @param controllerName the policy controller name - * @return the underlying drools controller - * @throws IllegalArgumentException if an invalid controller name has been passed in + * serialized output */ - protected DroolsController getDroolsController(String controllerName) { - PolicyController controller = PolicyController.factory.get(controllerName); - if (controller == null) - throw new IllegalArgumentException(controllerName + " does not exist"); - - DroolsController drools = controller.getDrools(); - if (drools == null) - throw new IllegalArgumentException(controllerName + " has no drools configuration"); - - return drools; - } - - /* - * Helper classes for aggregation of results + + public String jsonEncoding; + /** + * encoding result + */ + + public Boolean encoding; + + /** + * decoding result */ - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("rest-telemetry-api []"); - return builder.toString(); - } - - /** - * Coding/Encoding Results Aggregation Helper class - */ - public static class CodingResult { - /** - * serialized output - */ - - public String jsonEncoding; - /** - * encoding result - */ - - public Boolean encoding; - - /** - * decoding result - */ - public Boolean decoding; - } - - /** - * Generic Error Reporting class - */ - public static class Error { - public String error; - - public Error(String error) { - this.error = error; - } - } - - /** - * Feed Ports into Resources - */ - public enum Inputs { - configuration, - } - - /** - * Resource Toggles - */ - public enum Switches { - activation, - lock, - } + public Boolean decoding; + } + + /** + * Generic Error Reporting class + */ + public static class Error { + public String error; + + public Error(String error) { + this.error = error; + } + } + + /** + * Feed Ports into Resources + */ + public enum Inputs { + configuration, + } + + /** + * Resource Toggles + */ + public enum Switches { + activation, lock, + } } diff --git a/policy-management/src/main/java/org/onap/policy/drools/system/Main.java b/policy-management/src/main/java/org/onap/policy/drools/system/Main.java index 49dfafca..bcc59c71 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/system/Main.java +++ b/policy-management/src/main/java/org/onap/policy/drools/system/Main.java @@ -7,9 +7,9 @@ * 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. @@ -20,15 +20,14 @@ package org.onap.policy.drools.system; -import java.io.File; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.Properties; import org.onap.policy.drools.persistence.SystemPersistence; -import org.onap.policy.drools.utils.PropertyUtil; +import org.onap.policy.drools.properties.PolicyProperties; +import org.onap.policy.drools.utils.LoggerUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,116 +36,110 @@ import org.slf4j.LoggerFactory; */ public class Main { - /** - * logback configuration file system property - */ - public static final String LOGBACK_CONFIGURATION_FILE_SYSTEM_PROPERTY = "logback.configurationFile"; - - /** - * logback configuration file system property - */ - public static final String LOGBACK_CONFIGURATION_FILE_DEFAULT = "config/logback.xml"; - - /** - * constructor (hides public default one) - */ - private Main() {} - - /** - * main - * - * @param args program arguments - * @throws IOException - */ - public static void main(String args[]) { - - /* make sure the configuration directory exists */ - - Path configDir = Paths.get(SystemPersistence.CONFIG_DIR_NAME); - if (Files.notExists(configDir)) { - try { - Files.createDirectories(configDir); - } catch (IOException e) { - throw new IllegalStateException("cannot create " + SystemPersistence.CONFIG_DIR_NAME, e); - } - } - - if (!Files.isDirectory(configDir)) - throw new IllegalStateException - ("config directory: " + configDir + " is not a directory"); - - /* logging defaults */ - - if (System.getProperty(LOGBACK_CONFIGURATION_FILE_SYSTEM_PROPERTY) == null) - System.setProperty(LOGBACK_CONFIGURATION_FILE_SYSTEM_PROPERTY, LOGBACK_CONFIGURATION_FILE_DEFAULT); - - /* 0. boot */ - - PolicyEngine.manager.boot(args); - - /* start logger */ - - Logger logger = LoggerFactory.getLogger(Main.class); - - /* 1. Configure the Engine */ - - Path policyEnginePath = Paths.get(configDir.toString(), SystemPersistence.PROPERTIES_FILE_ENGINE); - try { - if (Files.exists(policyEnginePath)) - PolicyEngine.manager.configure(PropertyUtil.getProperties(policyEnginePath.toFile())); - else - PolicyEngine.manager.configure(PolicyEngine.manager.defaultTelemetryConfig()); - } catch (Exception e) { - logger.warn("Main: {} could not find custom configuration in {}.", - PolicyEngine.manager, SystemPersistence.PROPERTIES_FILE_ENGINE, e); - - /* continue without telemetry or other custom components - this is OK */ - } - - /* 2. Start the Engine with the basic services only (no Policy Controllers) */ - - try { - boolean success = PolicyEngine.manager.start(); - if (!success) { - logger.warn("Main: {} has been partially started", PolicyEngine.manager); - } - } catch (IllegalStateException e) { - logger.warn("Main: cannot start {} (bad state) because of {}", PolicyEngine.manager, e.getMessage(), e); - } catch (Exception e) { - logger.warn("Main: cannot start {} because of {}", PolicyEngine.manager, e.getMessage(), e); - System.exit(1); - } - - /* 3. Create and start the controllers */ - - File[] controllerFiles = configDir.toFile().listFiles(); - for (File config : controllerFiles) { - - if (config.getName().endsWith(SystemPersistence.PROPERTIES_FILE_CONTROLLER_SUFFIX)) { - int idxSuffix = - config.getName().indexOf(SystemPersistence.PROPERTIES_FILE_CONTROLLER_SUFFIX); - int lastIdxSuffix = - config.getName().lastIndexOf(SystemPersistence.PROPERTIES_FILE_CONTROLLER_SUFFIX); - if (idxSuffix != lastIdxSuffix) { - throw new IllegalArgumentException - ("Improper naming of controller properties file: " + - "Expected <controller-name>" + - SystemPersistence.PROPERTIES_FILE_CONTROLLER_SUFFIX); - } - - String name = - config.getName().substring(0, lastIdxSuffix); - try { - Properties properties = PropertyUtil.getProperties(config); - PolicyController controller = PolicyEngine.manager.createPolicyController(name, properties); - controller.start(); - } catch (Exception e) { - logger.error("Main: cannot instantiate policy-controller {} because of {}", name, e.getMessage(), e); - } catch (LinkageError e) { - logger.warn("Main: cannot instantiate policy-controller {} (linkage) because of {}", - name, e.getMessage(), e); - } - } - } - } + /** + * logback configuration file system property + */ + public static final String LOGBACK_CONFIGURATION_FILE_SYSTEM_PROPERTY = + "logback.configurationFile"; + + /** + * logback configuration file system property + */ + public static final String LOGBACK_CONFIGURATION_FILE_DEFAULT = "config/logback.xml"; + + /** + * constructor (hides public default one) + */ + private Main() {} + + /** + * main + * + * @param args program arguments + * @throws IOException + */ + public static void main(String args[]) { + + /* logging defaults */ + + if (System.getProperty(LOGBACK_CONFIGURATION_FILE_SYSTEM_PROPERTY) == null) { + if (Files.exists(Paths.get(LOGBACK_CONFIGURATION_FILE_DEFAULT))) { + System.setProperty(LOGBACK_CONFIGURATION_FILE_SYSTEM_PROPERTY, + LOGBACK_CONFIGURATION_FILE_DEFAULT); + } else { + LoggerUtil.setLevel(LoggerUtil.ROOT_LOGGER, ch.qos.logback.classic.Level.INFO.toString()); + } + } + + /* make sure the default configuration directory is properly set up */ + + SystemPersistence.manager.setConfigurationDir(null); + + /* logging defaults */ + + if (System.getProperty(LOGBACK_CONFIGURATION_FILE_SYSTEM_PROPERTY) == null) { + if (Files.exists(Paths.get(LOGBACK_CONFIGURATION_FILE_DEFAULT))) { + System.setProperty(LOGBACK_CONFIGURATION_FILE_SYSTEM_PROPERTY, + LOGBACK_CONFIGURATION_FILE_DEFAULT); + } else { + LoggerUtil.setLevel(LoggerUtil.ROOT_LOGGER, ch.qos.logback.classic.Level.INFO.toString()); + } + } + + /* 0. boot */ + + PolicyEngine.manager.boot(args); + + /* start logger */ + + final Logger logger = LoggerFactory.getLogger(Main.class); + + /* 1.a. Configure the Engine */ + + Properties engineProperties = SystemPersistence.manager.getEngineProperties(); + if (engineProperties == null) + engineProperties = PolicyEngine.manager.defaultTelemetryConfig(); + + PolicyEngine.manager.configure(PolicyEngine.manager.defaultTelemetryConfig()); + + /* 1.b. Load Installation Environment(s) */ + + for (final Properties env : SystemPersistence.manager.getEnvironmentProperties()) { + PolicyEngine.manager.setEnvironment(env); + } + + /* 2. Start the Engine with the basic services only (no Policy Controllers) */ + + try { + final boolean success = PolicyEngine.manager.start(); + if (!success) { + logger.warn("Main: {} has been partially started", PolicyEngine.manager); + } + } catch (final IllegalStateException e) { + logger.warn("Main: cannot start {} (bad state) because of {}", PolicyEngine.manager, + e.getMessage(), e); + } catch (final Exception e) { + logger.warn("Main: cannot start {} because of {}", PolicyEngine.manager, e.getMessage(), e); + System.exit(1); + } + + /* 3. Create and start the controllers */ + + for (final Properties controllerProperties : SystemPersistence.manager + .getControllerProperties()) { + final String controllerName = + controllerProperties.getProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME); + try { + final PolicyController controller = + PolicyEngine.manager.createPolicyController(controllerName, controllerProperties); + controller.start(); + } catch (final Exception e) { + logger.error("Main: cannot instantiate policy-controller {} because of {}", controllerName, + e.getMessage(), e); + } catch (final LinkageError e) { + logger.warn("Main: cannot instantiate policy-controller {} (linkage) because of {}", + controllerName, e.getMessage(), e); + } + } + } } diff --git a/policy-management/src/main/java/org/onap/policy/drools/system/PolicyEngine.java b/policy-management/src/main/java/org/onap/policy/drools/system/PolicyEngine.java index bfda2450..a262352b 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/system/PolicyEngine.java +++ b/policy-management/src/main/java/org/onap/policy/drools/system/PolicyEngine.java @@ -7,9 +7,9 @@ * 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. @@ -24,8 +24,6 @@ import java.util.ArrayList; import java.util.List; import java.util.Properties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.onap.policy.drools.controller.DroolsController; import org.onap.policy.drools.core.PolicyContainer; import org.onap.policy.drools.core.jmx.PdpJmxListener; @@ -46,6 +44,8 @@ import org.onap.policy.drools.protocol.coders.EventProtocolCoder; import org.onap.policy.drools.protocol.configuration.ControllerConfiguration; import org.onap.policy.drools.protocol.configuration.PdpdConfiguration; import org.onap.policy.drools.server.restful.RestManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; @@ -53,1358 +53,1387 @@ import com.google.gson.Gson; import com.google.gson.GsonBuilder; /** - * Policy Engine, the top abstraction for the Drools PDP Policy Engine. - * It abstracts away a Drools PDP Engine from management purposes. - * This is the best place to looking at the code from a top down approach. - * Other managed entities can be obtained from the PolicyEngine, hierarchically. - * <br> - * PolicyEngine 1 --- * PolicyController 1 --- 1 DroolsController 1 --- 1 PolicyContainer 1 --- * PolicySession - * <br> - * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 UebTopicReader - * <br> - * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 DmaapTopicReader - * <br> - * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 DmaapTopicWriter - * <br> - * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 RestTopicReader - * <br> - * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 RestTopicWriter - * <br> + * Policy Engine, the top abstraction for the Drools PDP Policy Engine. It abstracts away a Drools + * PDP Engine from management purposes. This is the best place to looking at the code from a top + * down approach. Other managed entities can be obtained from the PolicyEngine, hierarchically. <br> + * PolicyEngine 1 --- * PolicyController 1 --- 1 DroolsController 1 --- 1 PolicyContainer 1 --- * + * PolicySession <br> + * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 UebTopicReader <br> + * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 DmaapTopicReader <br> + * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 DmaapTopicWriter <br> + * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 RestTopicReader <br> + * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 RestTopicWriter <br> * PolicyEngine 1 --- 1 ManagementServer */ -public interface PolicyEngine extends Startable, Lockable, TopicListener { - /** - * Default Telemetry Server Port - */ - public static final int TELEMETRY_SERVER_DEFAULT_PORT = 9696; - - /** - * Default Telemetry Server Hostname - */ - public static final String TELEMETRY_SERVER_DEFAULT_HOST = "localhost"; - - /** - * Default Telemetry Server Name - */ - public static final String TELEMETRY_SERVER_DEFAULT_NAME = "TELEMETRY"; - - /** - * Boot the engine - * - * @param cliArgs command line arguments - */ - public void boot(String cliArgs[]); - - /** - * configure the policy engine according to the given properties - * - * @param properties Policy Engine properties - * @throws IllegalArgumentException when invalid or insufficient - * properties are provided - */ - public void configure(Properties properties); - - /** - * registers a new Policy Controller with the Policy Engine - * initialized per properties. - * - * @param controller name - * @param properties properties to initialize the Policy Controller - * @throws IllegalArgumentException when invalid or insufficient - * properties are provided - * @throws IllegalStateException when the engine is in a state where - * this operation is not permitted. - * @return the newly instantiated Policy Controller - */ - public PolicyController createPolicyController(String name, Properties properties); - - /** - * updates the Policy Engine with the given configuration - * - * @param configuration the configuration - * @return success or failure - * @throws IllegalArgumentException if invalid argument provided - * @throws IllegalStateException if the system is in an invalid state - */ - public boolean configure(PdpdConfiguration configuration); - - /** - * updates a set of Policy Controllers with configuration information - * - * @param configuration - * @return - * @throws IllegalArgumentException - * @throws IllegalStateException - */ - public List<PolicyController> updatePolicyControllers(List<ControllerConfiguration> configuration); - - /** - * updates an already existing Policy Controller with configuration information - * - * @param configuration configuration - * - * @return the updated Policy Controller - * @throws IllegalArgumentException in the configuration is invalid - * @throws IllegalStateException if the controller is in a bad state - * @throws Exception any other reason - */ - public PolicyController updatePolicyController(ControllerConfiguration configuration); - - /** - * removes the Policy Controller identified by its name from the Policy Engine - * - * @param name name of the Policy Controller - * @return the removed Policy Controller - */ - public void removePolicyController(String name); - - /** - * removes a Policy Controller from the Policy Engine - * @param controller the Policy Controller to remove from the Policy Engine - */ - public void removePolicyController(PolicyController controller); - - /** - * returns a list of the available Policy Controllers - * - * @return list of Policy Controllers - */ - public List<PolicyController> getPolicyControllers(); - - - /** - * get policy controller names - * - * @return list of controller names - */ - public List<String> getPolicyControllerIds(); - - /** - * get unmanaged sources - * - * @return unmanaged sources - */ - public List<TopicSource> getSources(); - - /** - * get unmanaged sinks - * - * @return unmanaged sinks - */ - public List<TopicSink> getSinks(); - - /** - * get unmmanaged http servers list - * @return http servers - */ - public List<HttpServletServer> getHttpServers(); - - /** - * get properties configuration - * - * @return properties objects - */ - public Properties getProperties(); - - /** - * get features attached to the Policy Engine - * @return list of features - */ - public List<PolicyEngineFeatureAPI> getFeatureProviders(); - - /** - * get named feature attached to the Policy Engine - * @return the feature - */ - public PolicyEngineFeatureAPI getFeatureProvider(String featureName) - throws IllegalArgumentException; - - /** - * get features attached to the Policy Engine - * @return list of features - */ - public List<String> getFeatures(); - - /** - * Attempts the dispatching of an "event" object - * - * @param topic topic - * @param event the event object to send - * - * @return true if successful, false if a failure has occurred. - * @throws IllegalArgumentException when invalid or insufficient - * properties are provided - * @throws IllegalStateException when the engine is in a state where - * this operation is not permitted (ie. locked or stopped). - */ - public boolean deliver(String topic, Object event) - throws IllegalArgumentException, IllegalStateException; - - /** - * Attempts the dispatching of an "event" object over communication - * infrastructure "busType" - * - * @param eventBus Communication infrastructure identifier - * @param topic topic - * @param event the event object to send - * - * @return true if successful, false if a failure has occurred. - * @throws IllegalArgumentException when invalid or insufficient - * properties are provided - * @throws IllegalStateException when the engine is in a state where - * this operation is not permitted (ie. locked or stopped). - * @throws UnsupportedOperationException when the engine cannot deliver due - * to the functionality missing (ie. communication infrastructure - * not supported. - */ - public boolean deliver(String busType, String topic, Object event) - throws IllegalArgumentException, IllegalStateException, - UnsupportedOperationException; - - /** - * Attempts the dispatching of an "event" object over communication - * infrastructure "busType" - * - * @param eventBus Communication infrastructure enum - * @param topic topic - * @param event the event object to send - * - * @return true if successful, false if a failure has occurred. - * @throws IllegalArgumentException when invalid or insufficient - * properties are provided - * @throws IllegalStateException when the engine is in a state where - * this operation is not permitted (ie. locked or stopped). - * @throws UnsupportedOperationException when the engine cannot deliver due - * to the functionality missing (ie. communication infrastructure - * not supported. - */ - public boolean deliver(CommInfrastructure busType, String topic, Object event) - throws IllegalArgumentException, IllegalStateException, - UnsupportedOperationException; - - /** - * Attempts delivering of an String over communication - * infrastructure "busType" - * - * @param eventBus Communication infrastructure identifier - * @param topic topic - * @param event the event object to send - * - * @return true if successful, false if a failure has occurred. - * @throws IllegalArgumentException when invalid or insufficient - * properties are provided - * @throws IllegalStateException when the engine is in a state where - * this operation is not permitted (ie. locked or stopped). - * @throws UnsupportedOperationException when the engine cannot deliver due - * to the functionality missing (ie. communication infrastructure - * not supported. - */ - public boolean deliver(CommInfrastructure busType, String topic, - String event) - throws IllegalArgumentException, IllegalStateException, - UnsupportedOperationException; - - /** - * Invoked when the host goes into the active state. - */ - public void activate(); - - /** - * Invoked when the host goes into the standby state. - */ - public void deactivate(); - - /** - * produces a default telemetry configuration - * - * @return policy engine configuration - */ - public Properties defaultTelemetryConfig(); - - /** - * Policy Engine Manager - */ - public final static PolicyEngine manager = new PolicyEngineManager(); +public interface PolicyEngine extends Startable, Lockable, TopicListener { + /** + * Default Telemetry Server Port + */ + public static final int TELEMETRY_SERVER_DEFAULT_PORT = 9696; + + /** + * Default Telemetry Server Hostname + */ + public static final String TELEMETRY_SERVER_DEFAULT_HOST = "localhost"; + + /** + * Default Telemetry Server Name + */ + public static final String TELEMETRY_SERVER_DEFAULT_NAME = "TELEMETRY"; + + /** + * Boot the engine + * + * @param cliArgs command line arguments + */ + public void boot(String cliArgs[]); + + /** + * configure the policy engine according to the given properties + * + * @param properties Policy Engine properties + * @throws IllegalArgumentException when invalid or insufficient properties are provided + */ + public void configure(Properties properties); + + /** + * configure the engine's environment. General lab installation configuration is made available to + * the Engine. Typically, custom lab installation that may be needed by arbitrary drools + * applications are made available, for example network component and database host addresses. + * Multiple environments can be passed in and tracked by the engine. + * + * @param properties an environment properties + */ + public void setEnvironment(Properties properties); + + /** + * gets the engine's environment + * + * @return + */ + public Properties getEnvironment(); + + /** + * gets an environment's value, by 1) first from the engine's environment, and 2) from the OS + * environment + * + * @param key environment key + * @return environment value or null if absent + */ + public String getEnvironmentProperty(String key); + + /** + * sets an engine's environment property + * + * @param key + * @param value + * @return + */ + public String setEnvironmentProperty(String key, String value); + + /** + * registers a new Policy Controller with the Policy Engine initialized per properties. + * + * @param controller name + * @param properties properties to initialize the Policy Controller + * @throws IllegalArgumentException when invalid or insufficient properties are provided + * @throws IllegalStateException when the engine is in a state where this operation is not + * permitted. + * @return the newly instantiated Policy Controller + */ + public PolicyController createPolicyController(String name, Properties properties); + + /** + * updates the Policy Engine with the given configuration + * + * @param configuration the configuration + * @return success or failure + * @throws IllegalArgumentException if invalid argument provided + * @throws IllegalStateException if the system is in an invalid state + */ + public boolean configure(PdpdConfiguration configuration); + + /** + * updates a set of Policy Controllers with configuration information + * + * @param configuration + * @return + * @throws IllegalArgumentException + * @throws IllegalStateException + */ + public List<PolicyController> updatePolicyControllers( + List<ControllerConfiguration> configuration); + + /** + * updates an already existing Policy Controller with configuration information + * + * @param configuration configuration + * + * @return the updated Policy Controller + * @throws IllegalArgumentException in the configuration is invalid + * @throws IllegalStateException if the controller is in a bad state + * @throws Exception any other reason + */ + public PolicyController updatePolicyController(ControllerConfiguration configuration); + + /** + * removes the Policy Controller identified by its name from the Policy Engine + * + * @param name name of the Policy Controller + * @return the removed Policy Controller + */ + public void removePolicyController(String name); + + /** + * removes a Policy Controller from the Policy Engine + * + * @param controller the Policy Controller to remove from the Policy Engine + */ + public void removePolicyController(PolicyController controller); + + /** + * returns a list of the available Policy Controllers + * + * @return list of Policy Controllers + */ + public List<PolicyController> getPolicyControllers(); + + + /** + * get policy controller names + * + * @return list of controller names + */ + public List<String> getPolicyControllerIds(); + + /** + * get unmanaged sources + * + * @return unmanaged sources + */ + public List<TopicSource> getSources(); + + /** + * get unmanaged sinks + * + * @return unmanaged sinks + */ + public List<TopicSink> getSinks(); + + /** + * get unmmanaged http servers list + * + * @return http servers + */ + public List<HttpServletServer> getHttpServers(); + + /** + * get properties configuration + * + * @return properties objects + */ + public Properties getProperties(); + + /** + * get features attached to the Policy Engine + * + * @return list of features + */ + public List<PolicyEngineFeatureAPI> getFeatureProviders(); + + /** + * get named feature attached to the Policy Engine + * + * @return the feature + */ + public PolicyEngineFeatureAPI getFeatureProvider(String featureName) + throws IllegalArgumentException; + + /** + * get features attached to the Policy Engine + * + * @return list of features + */ + public List<String> getFeatures(); + + /** + * Attempts the dispatching of an "event" object + * + * @param topic topic + * @param event the event object to send + * + * @return true if successful, false if a failure has occurred. + * @throws IllegalArgumentException when invalid or insufficient properties are provided + * @throws IllegalStateException when the engine is in a state where this operation is not + * permitted (ie. locked or stopped). + */ + public boolean deliver(String topic, Object event) + throws IllegalArgumentException, IllegalStateException; + + /** + * Attempts the dispatching of an "event" object over communication infrastructure "busType" + * + * @param eventBus Communication infrastructure identifier + * @param topic topic + * @param event the event object to send + * + * @return true if successful, false if a failure has occurred. + * @throws IllegalArgumentException when invalid or insufficient properties are provided + * @throws IllegalStateException when the engine is in a state where this operation is not + * permitted (ie. locked or stopped). + * @throws UnsupportedOperationException when the engine cannot deliver due to the functionality + * missing (ie. communication infrastructure not supported. + */ + public boolean deliver(String busType, String topic, Object event) + throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException; + + /** + * Attempts the dispatching of an "event" object over communication infrastructure "busType" + * + * @param eventBus Communication infrastructure enum + * @param topic topic + * @param event the event object to send + * + * @return true if successful, false if a failure has occurred. + * @throws IllegalArgumentException when invalid or insufficient properties are provided + * @throws IllegalStateException when the engine is in a state where this operation is not + * permitted (ie. locked or stopped). + * @throws UnsupportedOperationException when the engine cannot deliver due to the functionality + * missing (ie. communication infrastructure not supported. + */ + public boolean deliver(CommInfrastructure busType, String topic, Object event) + throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException; + + /** + * Attempts delivering of an String over communication infrastructure "busType" + * + * @param eventBus Communication infrastructure identifier + * @param topic topic + * @param event the event object to send + * + * @return true if successful, false if a failure has occurred. + * @throws IllegalArgumentException when invalid or insufficient properties are provided + * @throws IllegalStateException when the engine is in a state where this operation is not + * permitted (ie. locked or stopped). + * @throws UnsupportedOperationException when the engine cannot deliver due to the functionality + * missing (ie. communication infrastructure not supported. + */ + public boolean deliver(CommInfrastructure busType, String topic, String event) + throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException; + + /** + * Invoked when the host goes into the active state. + */ + public void activate(); + + /** + * Invoked when the host goes into the standby state. + */ + public void deactivate(); + + /** + * produces a default telemetry configuration + * + * @return policy engine configuration + */ + public Properties defaultTelemetryConfig(); + + /** + * Policy Engine Manager + */ + public final static PolicyEngine manager = new PolicyEngineManager(); } + /** * Policy Engine Manager Implementation */ class PolicyEngineManager implements PolicyEngine { - - /** - * logger - */ - private static Logger logger = LoggerFactory.getLogger(PolicyEngineManager.class); - - /** - * Is the Policy Engine running? - */ - protected boolean alive = false; - - /** - * Is the engine locked? - */ - protected boolean locked = false; - - /** - * Properties used to initialize the engine - */ - protected Properties properties; - - /** - * Policy Engine Sources - */ - protected List<? extends TopicSource> sources = new ArrayList<>(); - - /** - * Policy Engine Sinks - */ - protected List<? extends TopicSink> sinks = new ArrayList<>(); - - /** - * Policy Engine HTTP Servers - */ - protected List<HttpServletServer> httpServers = new ArrayList<HttpServletServer>(); - - /** - * gson parser to decode configuration requests - */ - protected Gson decoder = new GsonBuilder().disableHtmlEscaping().create(); - - - @Override - public synchronized void boot(String cliArgs[]) { - - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.beforeBoot(this, cliArgs)) - return; - } catch (Exception e) { - logger.error("{}: feature {} before-boot failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - try { - PolicyContainer.globalInit(cliArgs); - } catch (Exception e) { - logger.error("{}: cannot init policy-container because of {}", this, e.getMessage(), e); - } - - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.afterBoot(this)) - return; - } catch (Exception e) { - logger.error("{}: feature {} after-boot failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - } - - - /** - * produces a minimum configuration with the telemetry service enabled - * - * @return policy engine configuration - */ - @Override - public final Properties defaultTelemetryConfig() { - Properties defaultConfig = new Properties(); - - defaultConfig.put(PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES, "TELEMETRY"); - defaultConfig.put(PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + - TELEMETRY_SERVER_DEFAULT_NAME + - PolicyProperties.PROPERTY_HTTP_HOST_SUFFIX, - TELEMETRY_SERVER_DEFAULT_HOST); - defaultConfig.put(PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + - TELEMETRY_SERVER_DEFAULT_NAME + - PolicyProperties.PROPERTY_HTTP_PORT_SUFFIX, - "" + TELEMETRY_SERVER_DEFAULT_PORT); - defaultConfig.put(PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + - TELEMETRY_SERVER_DEFAULT_NAME + - PolicyProperties.PROPERTY_HTTP_REST_PACKAGES_SUFFIX, - RestManager.class.getPackage().getName()); - defaultConfig.put(PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + - TELEMETRY_SERVER_DEFAULT_NAME + - PolicyProperties.PROPERTY_HTTP_SWAGGER_SUFFIX, - "" + Boolean.TRUE); - defaultConfig.put(PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + - TELEMETRY_SERVER_DEFAULT_NAME + - PolicyProperties.PROPERTY_MANAGED_SUFFIX, - "" + Boolean.FALSE); - - return defaultConfig; - } - - @Override - public synchronized void configure(Properties properties) { - - if (properties == null) { - logger.warn("No properties provided"); - throw new IllegalArgumentException("No properties provided"); - } - - /* policy-engine dispatch pre configure hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.beforeConfigure(this, properties)) - return; - } catch (Exception e) { - logger.error("{}: feature {} before-configure failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - this.properties = properties; - - try { - this.sources = TopicEndpoint.manager.addTopicSources(properties); - for (TopicSource source: this.sources) { - source.register(this); - } - } catch (Exception e) { - logger.error("{}: add-sources failed", this, e); - } - - try { - this.sinks = TopicEndpoint.manager.addTopicSinks(properties); - } catch (IllegalArgumentException e) { - logger.error("{}: add-sinks failed", this, e); - } - - try { - this.httpServers = HttpServletServer.factory.build(properties); - } catch (IllegalArgumentException e) { - logger.error("{}: add-http-servers failed", this, e); - } - - /* policy-engine dispatch post configure hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.afterConfigure(this)) - return; - } catch (Exception e) { - logger.error("{}: feature {} after-configure failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - return; - } - - @Override - public synchronized PolicyController createPolicyController(String name, Properties properties) - throws IllegalArgumentException, IllegalStateException { - - // check if a PROPERTY_CONTROLLER_NAME property is present - // if so, override the given name - - String propertyControllerName = properties.getProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME); - if (propertyControllerName != null && !propertyControllerName.isEmpty()) { - if (!propertyControllerName.equals(name)) { - throw new IllegalStateException("Proposed name (" + name + - ") and properties name (" + propertyControllerName + - ") don't match"); - } - name = propertyControllerName; - } - - PolicyController controller; - for (PolicyControllerFeatureAPI controllerFeature : PolicyControllerFeatureAPI.providers.getList()) { - try { - controller = controllerFeature.beforeCreate(name, properties); - if (controller != null) - return controller; - } catch (Exception e) { - logger.error("{}: feature {} before-controller-create failure because of {}", - this, controllerFeature.getClass().getName(), e.getMessage(), e); - } - } - - controller = PolicyController.factory.build(name, properties); - if (this.isLocked()) - controller.lock(); - - // feature hook - for (PolicyControllerFeatureAPI controllerFeature : PolicyControllerFeatureAPI.providers.getList()) { - try { - if (controllerFeature.afterCreate(controller)) - return controller; - } catch (Exception e) { - logger.error("{}: feature {} after-controller-create failure because of {}", - this, controllerFeature.getClass().getName(), e.getMessage(), e); - } - } - - return controller; - } - - - @Override - public boolean configure(PdpdConfiguration config) { - - if (config == null) - throw new IllegalArgumentException("No configuration provided"); - - String entity = config.getEntity(); - - switch (entity) { - case PdpdConfiguration.CONFIG_ENTITY_CONTROLLER: - /* only this one supported for now */ - List<ControllerConfiguration> configControllers = config.getControllers(); - if (configControllers == null || configControllers.isEmpty()) { - if (logger.isInfoEnabled()) - logger.info("No controller configuration provided: " + config); - return false; - } - List<PolicyController> policyControllers = this.updatePolicyControllers(config.getControllers()); - if (policyControllers == null || policyControllers.isEmpty()) - return false; - else if (policyControllers.size() == configControllers.size()) - return true; - - return false; - default: - String msg = "Configuration Entity is not supported: " + entity; - logger.warn(msg); - throw new IllegalArgumentException(msg); - } - } - - @Override - public List<PolicyController> updatePolicyControllers(List<ControllerConfiguration> configControllers) - throws IllegalArgumentException, IllegalStateException { - - List<PolicyController> policyControllers = new ArrayList<PolicyController>(); - if (configControllers == null || configControllers.isEmpty()) { - if (logger.isInfoEnabled()) - logger.info("No controller configuration provided: " + configControllers); - return policyControllers; - } - - for (ControllerConfiguration configController: configControllers) { - try { - PolicyController policyController = this.updatePolicyController(configController); - policyControllers.add(policyController); - } catch (Exception e) { - logger.error("{}: cannot update-policy-controllers because of {}", this, e.getMessage(), e); - } - } - - return policyControllers; - } - - @Override - public PolicyController updatePolicyController(ControllerConfiguration configController) { - - if (configController == null) - throw new IllegalArgumentException("No controller configuration has been provided"); - - String controllerName = configController.getName(); - if (controllerName == null || controllerName.isEmpty()) { - logger.warn("controller-name must be provided"); - throw new IllegalArgumentException("No controller configuration has been provided"); - } - - PolicyController policyController = null; - try { - String operation = configController.getOperation(); - if (operation == null || operation.isEmpty()) { - logger.warn("operation must be provided"); - throw new IllegalArgumentException("operation must be provided"); - } - - try { - policyController = PolicyController.factory.get(controllerName); - } catch (IllegalArgumentException e) { - // not found - logger.warn("Policy Controller " + controllerName + " not found", e); - } - - if (policyController == null) { - - if (operation.equalsIgnoreCase(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_LOCK) || - operation.equalsIgnoreCase(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UNLOCK)) { - throw new IllegalArgumentException(controllerName + " is not available for operation " + operation); - } - - /* Recovery case */ - - logger.warn("controller " + controllerName + " does not exist. " + - "Attempting recovery from disk"); - - Properties properties = - SystemPersistence.manager.getControllerProperties(controllerName); - - /* - * returned properties cannot be null (per implementation) - * assert (properties != null) - */ - - if (properties == null) { - throw new IllegalArgumentException(controllerName + " is invalid"); - } - - logger.warn("controller " + controllerName + " being recovered. " + - "Reset controller's bad maven coordinates to brainless"); - - /* - * try to bring up bad controller in brainless mode, - * after having it working, apply the new create/update operation. - */ - properties.setProperty(PolicyProperties.RULES_GROUPID, DroolsController.NO_GROUP_ID); - properties.setProperty(PolicyProperties.RULES_ARTIFACTID, DroolsController.NO_ARTIFACT_ID); - properties.setProperty(PolicyProperties.RULES_VERSION, DroolsController.NO_VERSION); - - policyController = PolicyEngine.manager.createPolicyController(controllerName, properties); - - /* fall through to do brain update operation*/ - } - - switch (operation) { - case ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_CREATE: - PolicyController.factory.patch(policyController, configController.getDrools()); - break; - case ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UPDATE: - policyController.unlock(); - PolicyController.factory.patch(policyController, configController.getDrools()); - break; - case ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_LOCK: - policyController.lock(); - break; - case ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UNLOCK: - policyController.unlock(); - break; - default: - String msg = "Controller Operation Configuration is not supported: " + - operation + " for " + controllerName; - logger.warn(msg); - throw new IllegalArgumentException(msg); - } - - return policyController; - } catch (Exception e) { - logger.error("{}: cannot update-policy-controller because of {}", this, e.getMessage(), e); - throw e; - } catch (LinkageError e) { - logger.error("{}: cannot update-policy-controllers (rules) because of {}", this, e.getMessage(), e); - throw new IllegalStateException(e); - } - } - - @Override - public synchronized boolean start() { - - /* policy-engine dispatch pre start hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.beforeStart(this)) - return true; - } catch (Exception e) { - logger.error("{}: feature {} before-start failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - boolean success = true; - if (this.locked) - throw new IllegalStateException("Engine is locked"); - - this.alive = true; - - /* Start Policy Engine exclusively-owned (unmanaged) http servers */ - - for (HttpServletServer httpServer: this.httpServers) { - try { - if (!httpServer.waitedStart(5 * 1000L)) - success = false; - } catch (Exception e) { - logger.error("{}: cannot start http-server {} because of {}", this, - httpServer, e.getMessage(), e); - } - } - - /* Start Policy Engine exclusively-owned (unmanaged) sources */ - - for (TopicSource source: this.sources) { - try { - if (!source.start()) - success = false; - } catch (Exception e) { - logger.error("{}: cannot start topic-source {} because of {}", this, - source, e.getMessage(), e); - } - } - - /* Start Policy Engine owned (unmanaged) sinks */ - - for (TopicSink sink: this.sinks) { - try { - if (!sink.start()) - success = false; - } catch (Exception e) { - logger.error("{}: cannot start topic-sink {} because of {}", this, - sink, e.getMessage(), e); - } - } - - /* Start Policy Controllers */ - - List<PolicyController> controllers = PolicyController.factory.inventory(); - for (PolicyController controller : controllers) { - try { - if (!controller.start()) - success = false; - } catch (Exception e) { - logger.error("{}: cannot start policy-controller {} because of {}", this, - controller, e.getMessage(), e); - success = false; - } - } - - /* Start managed Topic Endpoints */ - - try { - if (!TopicEndpoint.manager.start()) - success = false; - } catch (IllegalStateException e) { - logger.warn("{}: Topic Endpoint Manager is in an invalid state because of {}", this, e.getMessage(), e); - } - - - // Start the JMX listener - - PdpJmxListener.start(); - - /* policy-engine dispatch after start hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.afterStart(this)) - return success; - } catch (Exception e) { - logger.error("{}: feature {} after-start failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - return success; - } - - @Override - public synchronized boolean stop() { - - /* policy-engine dispatch pre stop hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.beforeStop(this)) - return true; - } catch (Exception e) { - logger.error("{}: feature {} before-stop failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - /* stop regardless of the lock state */ - - boolean success = true; - if (!this.alive) - return true; - - this.alive = false; - - List<PolicyController> controllers = PolicyController.factory.inventory(); - for (PolicyController controller : controllers) { - try { - if (!controller.stop()) - success = false; - } catch (Exception e) { - logger.error("{}: cannot stop policy-controller {} because of {}", this, - controller, e.getMessage(), e); - success = false; - } - } - - /* Stop Policy Engine owned (unmanaged) sources */ - for (TopicSource source: this.sources) { - try { - if (!source.stop()) - success = false; - } catch (Exception e) { - logger.error("{}: cannot start topic-source {} because of {}", this, - source, e.getMessage(), e); - } - } - - /* Stop Policy Engine owned (unmanaged) sinks */ - for (TopicSink sink: this.sinks) { - try { - if (!sink.stop()) - success = false; - } catch (Exception e) { - logger.error("{}: cannot start topic-sink {} because of {}", this, - sink, e.getMessage(), e); - } - } - - /* stop all managed topics sources and sinks */ - if (!TopicEndpoint.manager.stop()) - success = false; - - /* stop all unmanaged http servers */ - for (HttpServletServer httpServer: this.httpServers) { - try { - if (!httpServer.stop()) - success = false; - } catch (Exception e) { - logger.error("{}: cannot start http-server {} because of {}", this, - httpServer, e.getMessage(), e); - } - } - - /* policy-engine dispatch pre stop hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.afterStop(this)) - return success; - } catch (Exception e) { - logger.error("{}: feature {} after-stop failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - return success; - } - - @Override - public synchronized void shutdown() { - - /* policy-engine dispatch pre shutdown hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.beforeShutdown(this)) - return; - } catch (Exception e) { - logger.error("{}: feature {} before-shutdown failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - this.alive = false; - - /* Shutdown Policy Engine owned (unmanaged) sources */ - for (TopicSource source: this.sources) { - try { - source.shutdown(); - } catch (Exception e) { - logger.error("{}: cannot shutdown topic-source {} because of {}", this, - source, e.getMessage(), e); - } - } - - /* Shutdown Policy Engine owned (unmanaged) sinks */ - for (TopicSink sink: this.sinks) { - try { - sink.shutdown(); - } catch (Exception e) { - logger.error("{}: cannot shutdown topic-sink {} because of {}", this, - sink, e.getMessage(), e); - } - } - - /* Shutdown managed resources */ - PolicyController.factory.shutdown(); - TopicEndpoint.manager.shutdown(); - HttpServletServer.factory.destroy(); - - // Stop the JMX listener - - PdpJmxListener.stop(); - - /* policy-engine dispatch post shutdown hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.afterShutdown(this)) - return; - } catch (Exception e) { - logger.error("{}: feature {} after-shutdown failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - - new Thread(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(5000L); - } catch (InterruptedException e) { - logger.warn("{}: interrupted-exception while shutting down management server: ", this); - } - - /* shutdown all unmanaged http servers */ - for (HttpServletServer httpServer: getHttpServers()) { - try { - httpServer.shutdown(); - } catch (Exception e) { - logger.error("{}: cannot shutdown http-server {} because of {}", this, - httpServer, e.getMessage(), e); - } - } - - try { - Thread.sleep(5000L); - } catch (InterruptedException e) { - logger.warn("{}: interrupted-exception while shutting down management server: ", this); - } - - System.exit(0); - } - }).start(); - } - - @Override - public synchronized boolean isAlive() { - return this.alive; - } - - @Override - public synchronized boolean lock() { - - /* policy-engine dispatch pre lock hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.beforeLock(this)) - return true; - } catch (Exception e) { - logger.error("{}: feature {} before-lock failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - if (this.locked) - return true; - - this.locked = true; - - boolean success = true; - List<PolicyController> controllers = PolicyController.factory.inventory(); - for (PolicyController controller : controllers) { - try { - success = controller.lock() && success; - } catch (Exception e) { - logger.error("{}: cannot lock policy-controller {} because of {}", this, - controller, e.getMessage(), e); - success = false; - } - } - - success = TopicEndpoint.manager.lock() && success; - - /* policy-engine dispatch post lock hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.afterLock(this)) - return success; - } catch (Exception e) { - logger.error("{}: feature {} after-lock failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - return success; - } - - @Override - public synchronized boolean unlock() { - - /* policy-engine dispatch pre unlock hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.beforeUnlock(this)) - return true; - } catch (Exception e) { - logger.error("{}: feature {} before-unlock failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - if (!this.locked) - return true; - - this.locked = false; - - boolean success = true; - List<PolicyController> controllers = PolicyController.factory.inventory(); - for (PolicyController controller : controllers) { - try { - success = controller.unlock() && success; - } catch (Exception e) { - logger.error("{}: cannot unlock policy-controller {} because of {}", this, - controller, e.getMessage(), e); - success = false; - } - } - - success = TopicEndpoint.manager.unlock() && success; - - /* policy-engine dispatch after unlock hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.afterUnlock(this)) - return success; - } catch (Exception e) { - logger.error("{}: feature {} after-unlock failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - return success; - } - - @Override - public synchronized boolean isLocked() { - return this.locked; - } - - @Override - public void removePolicyController(String name) { - PolicyController.factory.destroy(name); - } - - @Override - public void removePolicyController(PolicyController controller) { - PolicyController.factory.destroy(controller); - } - - @JsonIgnore - @Override - public List<PolicyController> getPolicyControllers() { - return PolicyController.factory.inventory(); - } - - @JsonProperty("controllers") - @Override - public List<String> getPolicyControllerIds() { - List<String> controllerNames = new ArrayList<String>(); - for (PolicyController controller: PolicyController.factory.inventory()) { - controllerNames.add(controller.getName()); - } - return controllerNames; - } - - @Override - @JsonIgnore - public Properties getProperties() { - return this.properties; - } - - - @SuppressWarnings("unchecked") - @Override - public List<TopicSource> getSources() { - return (List<TopicSource>) this.sources; - } - - @SuppressWarnings("unchecked") - @Override - public List<TopicSink> getSinks() { - return (List<TopicSink>) this.sinks; - } - - @Override - public List<HttpServletServer> getHttpServers() { - return this.httpServers; - } - - @Override - public List<String> getFeatures() { - List<String> features = new ArrayList<String>(); - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - features.add(feature.getName()); - } - return features; - } - - @JsonIgnore - @Override - public List<PolicyEngineFeatureAPI> getFeatureProviders() { - return PolicyEngineFeatureAPI.providers.getList(); - } - - @Override - public PolicyEngineFeatureAPI getFeatureProvider(String featureName) { - if (featureName == null || featureName.isEmpty()) - throw new IllegalArgumentException("A feature name must be provided"); - - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - if (feature.getName().equals(featureName)) - return feature; - } - - throw new IllegalArgumentException("Invalid Feature Name: " + featureName); - } - - @Override - public void onTopicEvent(CommInfrastructure commType, String topic, String event) { - /* configuration request */ - try { - PdpdConfiguration configuration = this.decoder.fromJson(event, PdpdConfiguration.class); - this.configure(configuration); - } catch (Exception e) { - logger.error("{}: configuration-error due to {} because of {}", - this, event, e.getMessage(), e); - } - } - - @Override - public boolean deliver(String topic, Object event) - throws IllegalArgumentException, IllegalStateException { - - /* - * Note this entry point is usually from the DRL - */ - - if (topic == null || topic.isEmpty()) - throw new IllegalArgumentException("Invalid Topic"); - - if (event == null) - throw new IllegalArgumentException("Invalid Event"); - - if (!this.isAlive()) - throw new IllegalStateException("Policy Engine is stopped"); - - if (this.isLocked()) - throw new IllegalStateException("Policy Engine is locked"); - - List<? extends TopicSink> sinks = - TopicEndpoint.manager.getTopicSinks(topic); - if (sinks == null || sinks.isEmpty() || sinks.size() > 1) - throw new IllegalStateException - ("Cannot ensure correct delivery on topic " + topic + ": " + sinks); - - return this.deliver(sinks.get(0).getTopicCommInfrastructure(), - topic, event); - } - - @Override - public boolean deliver(String busType, String topic, Object event) - throws IllegalArgumentException, IllegalStateException, - UnsupportedOperationException { - - /* - * Note this entry point is usually from the DRL (one of the reasons - * busType is String. - */ - - if (busType == null || busType.isEmpty()) - throw new IllegalArgumentException - ("Invalid Communication Infrastructure"); - - if (topic == null || topic.isEmpty()) - throw new IllegalArgumentException("Invalid Topic"); - - if (event == null) - throw new IllegalArgumentException("Invalid Event"); - - boolean valid = false; - for (Topic.CommInfrastructure comm: Topic.CommInfrastructure.values()) { - if (comm.name().equals(busType)) { - valid = true; - } - } - - if (!valid) - throw new IllegalArgumentException - ("Invalid Communication Infrastructure: " + busType); - - - if (!this.isAlive()) - throw new IllegalStateException("Policy Engine is stopped"); - - if (this.isLocked()) - throw new IllegalStateException("Policy Engine is locked"); - - - return this.deliver(Topic.CommInfrastructure.valueOf(busType), - topic, event); - } - - @Override - public boolean deliver(Topic.CommInfrastructure busType, - String topic, Object event) - throws IllegalArgumentException, IllegalStateException, - UnsupportedOperationException { - - if (topic == null || topic.isEmpty()) - throw new IllegalArgumentException("Invalid Topic"); - - if (event == null) - throw new IllegalArgumentException("Invalid Event"); - - if (!this.isAlive()) - throw new IllegalStateException("Policy Engine is stopped"); - - if (this.isLocked()) - throw new IllegalStateException("Policy Engine is locked"); - - /* Try to send through the controller, this is the - * preferred way, since it may want to apply additional - * processing - */ - try { - DroolsController droolsController = - EventProtocolCoder.manager.getDroolsController(topic, event); - PolicyController controller = PolicyController.factory.get(droolsController); - if (controller != null) - return controller.deliver(busType, topic, event); - } catch (Exception e) { - logger.warn("{}: cannot find policy-controller to deliver {} over {}:{} because of {}", - this, event, busType, topic, e.getMessage(), e); - - /* continue (try without routing through the controller) */ - } - - /* - * cannot route through the controller, send directly through - * the topic sink - */ - try { - String json = EventProtocolCoder.manager.encode(topic, event); - return this.deliver(busType, topic, json); - - } catch (Exception e) { - logger.warn("{}: cannot deliver {} over {}:{} because of {}", - this, event, busType, topic, e.getMessage(), e); - throw e; - } - } - - @Override - public boolean deliver(Topic.CommInfrastructure busType, - String topic, String event) - throws IllegalArgumentException, IllegalStateException, - UnsupportedOperationException { - - if (topic == null || topic.isEmpty()) - throw new IllegalArgumentException("Invalid Topic"); - - if (event == null || event.isEmpty()) - throw new IllegalArgumentException("Invalid Event"); - - if (!this.isAlive()) - throw new IllegalStateException("Policy Engine is stopped"); - - if (this.isLocked()) - throw new IllegalStateException("Policy Engine is locked"); - - try { - TopicSink sink = - TopicEndpoint.manager.getTopicSink - (busType, topic); - - if (sink == null) - throw new IllegalStateException("Inconsistent State: " + this); - - return sink.send(event); - - } catch (Exception e) { - logger.warn("{}: cannot deliver {} over {}:{} because of {}", - this, event, busType, topic, e.getMessage(), e); - throw e; - } - } - - @Override - public synchronized void activate() { - - /* policy-engine dispatch pre activate hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.beforeActivate(this)) - return; - } catch (Exception e) { - logger.error("{}: feature {} before-activate failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - // activate 'policy-management' - for (PolicyController policyController : getPolicyControllers()) { - try { - policyController.unlock(); - policyController.start(); - } catch (Exception e) { - logger.error("{}: cannot activate of policy-controller {} because of {}", - this, policyController,e.getMessage(), e); - } catch (LinkageError e) { - logger.error("{}: cannot activate (rules compilation) of policy-controller {} because of {}", - this, policyController,e.getMessage(), e); - } - } - - this.unlock(); - - /* policy-engine dispatch post activate hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.afterActivate(this)) - return; - } catch (Exception e) { - logger.error("{}: feature {} after-activate failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - } - - @Override - public synchronized void deactivate() { - - /* policy-engine dispatch pre deactivate hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.beforeDeactivate(this)) - return; - } catch (Exception e) { - logger.error("{}: feature {} before-deactivate failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - this.lock(); - - for (PolicyController policyController : getPolicyControllers()) { - try { - policyController.stop(); - } catch (Exception e) { - logger.error("{}: cannot deactivate (stop) policy-controller {} because of {}", - this, policyController, e.getMessage(), e); - } catch (LinkageError e) { - logger.error("{}: cannot deactivate (stop) policy-controller {} because of {}", - this, policyController, e.getMessage(), e); - } - } - - /* policy-engine dispatch post deactivate hook */ - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.afterDeactivate(this)) - return; - } catch (Exception e) { - logger.error("{}: feature {} after-deactivate failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("PolicyEngineManager [alive=").append(alive).append(", locked=").append(locked).append("]"); - return builder.toString(); - } - + /** + * logger + */ + private static final Logger logger = LoggerFactory.getLogger(PolicyEngineManager.class); + + /** + * Is the Policy Engine running? + */ + protected boolean alive = false; + + /** + * Is the engine locked? + */ + protected boolean locked = false; + + /** + * Properties used to initialize the engine + */ + protected Properties properties; + + /** + * Environment Properties + */ + protected final Properties environment = new Properties(); + + /** + * Policy Engine Sources + */ + protected List<? extends TopicSource> sources = new ArrayList<>(); + + /** + * Policy Engine Sinks + */ + protected List<? extends TopicSink> sinks = new ArrayList<>(); + + /** + * Policy Engine HTTP Servers + */ + protected List<HttpServletServer> httpServers = new ArrayList<HttpServletServer>(); + + /** + * gson parser to decode configuration requests + */ + protected final Gson decoder = new GsonBuilder().disableHtmlEscaping().create(); + + + @Override + public synchronized void boot(String cliArgs[]) { + + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.beforeBoot(this, cliArgs)) + return; + } catch (final Exception e) { + logger.error("{}: feature {} before-boot failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + try { + PolicyContainer.globalInit(cliArgs); + } catch (final Exception e) { + logger.error("{}: cannot init policy-container because of {}", this, e.getMessage(), e); + } + + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.afterBoot(this)) + return; + } catch (final Exception e) { + logger.error("{}: feature {} after-boot failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + } + + @Override + public synchronized void setEnvironment(Properties properties) { + this.environment.putAll(properties); + } + + @JsonIgnore + @Override + public synchronized Properties getEnvironment() { + return this.environment; + } + + @Override + public synchronized String getEnvironmentProperty(String envKey) { + String value = this.environment.getProperty(envKey); + if (value == null) + value = System.getenv(envKey); + return value; + } + + @Override + public synchronized String setEnvironmentProperty(String envKey, String envValue) { + return (String) this.environment.setProperty(envKey, envValue); + } + + @Override + public final Properties defaultTelemetryConfig() { + final Properties defaultConfig = new Properties(); + + defaultConfig.put(PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES, "TELEMETRY"); + defaultConfig.put(PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + + TELEMETRY_SERVER_DEFAULT_NAME + PolicyProperties.PROPERTY_HTTP_HOST_SUFFIX, + TELEMETRY_SERVER_DEFAULT_HOST); + defaultConfig.put(PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + + TELEMETRY_SERVER_DEFAULT_NAME + PolicyProperties.PROPERTY_HTTP_PORT_SUFFIX, + "" + TELEMETRY_SERVER_DEFAULT_PORT); + defaultConfig.put( + PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + TELEMETRY_SERVER_DEFAULT_NAME + + PolicyProperties.PROPERTY_HTTP_REST_PACKAGES_SUFFIX, + RestManager.class.getPackage().getName()); + defaultConfig.put(PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + + TELEMETRY_SERVER_DEFAULT_NAME + PolicyProperties.PROPERTY_HTTP_SWAGGER_SUFFIX, + "" + Boolean.TRUE); + defaultConfig.put(PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + + TELEMETRY_SERVER_DEFAULT_NAME + PolicyProperties.PROPERTY_MANAGED_SUFFIX, + "" + Boolean.FALSE); + + return defaultConfig; + } + + @Override + public synchronized void configure(Properties properties) { + + if (properties == null) { + logger.warn("No properties provided"); + throw new IllegalArgumentException("No properties provided"); + } + + /* policy-engine dispatch pre configure hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.beforeConfigure(this, properties)) + return; + } catch (final Exception e) { + logger.error("{}: feature {} before-configure failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + this.properties = properties; + + try { + this.sources = TopicEndpoint.manager.addTopicSources(properties); + for (final TopicSource source : this.sources) { + source.register(this); + } + } catch (final Exception e) { + logger.error("{}: add-sources failed", this, e); + } + + try { + this.sinks = TopicEndpoint.manager.addTopicSinks(properties); + } catch (final IllegalArgumentException e) { + logger.error("{}: add-sinks failed", this, e); + } + + try { + this.httpServers = HttpServletServer.factory.build(properties); + } catch (final IllegalArgumentException e) { + logger.error("{}: add-http-servers failed", this, e); + } + + /* policy-engine dispatch post configure hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.afterConfigure(this)) + return; + } catch (final Exception e) { + logger.error("{}: feature {} after-configure failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + return; + } + + @Override + public synchronized PolicyController createPolicyController(String name, Properties properties) + throws IllegalArgumentException, IllegalStateException { + + // check if a PROPERTY_CONTROLLER_NAME property is present + // if so, override the given name + + final String propertyControllerName = + properties.getProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME); + if (propertyControllerName != null && !propertyControllerName.isEmpty()) { + if (!propertyControllerName.equals(name)) { + throw new IllegalStateException("Proposed name (" + name + ") and properties name (" + + propertyControllerName + ") don't match"); + } + name = propertyControllerName; + } + + PolicyController controller; + for (final PolicyControllerFeatureAPI controllerFeature : PolicyControllerFeatureAPI.providers + .getList()) { + try { + controller = controllerFeature.beforeCreate(name, properties); + if (controller != null) + return controller; + } catch (final Exception e) { + logger.error("{}: feature {} before-controller-create failure because of {}", this, + controllerFeature.getClass().getName(), e.getMessage(), e); + } + } + + controller = PolicyController.factory.build(name, properties); + if (this.isLocked()) + controller.lock(); + + // feature hook + for (final PolicyControllerFeatureAPI controllerFeature : PolicyControllerFeatureAPI.providers + .getList()) { + try { + if (controllerFeature.afterCreate(controller)) + return controller; + } catch (final Exception e) { + logger.error("{}: feature {} after-controller-create failure because of {}", this, + controllerFeature.getClass().getName(), e.getMessage(), e); + } + } + + return controller; + } + + + @Override + public boolean configure(PdpdConfiguration config) { + + if (config == null) + throw new IllegalArgumentException("No configuration provided"); + + final String entity = config.getEntity(); + + switch (entity) { + case PdpdConfiguration.CONFIG_ENTITY_CONTROLLER: + /* only this one supported for now */ + final List<ControllerConfiguration> configControllers = config.getControllers(); + if (configControllers == null || configControllers.isEmpty()) { + if (logger.isInfoEnabled()) + logger.info("No controller configuration provided: " + config); + return false; + } + final List<PolicyController> policyControllers = + this.updatePolicyControllers(config.getControllers()); + if (policyControllers == null || policyControllers.isEmpty()) + return false; + else if (policyControllers.size() == configControllers.size()) + return true; + + return false; + default: + final String msg = "Configuration Entity is not supported: " + entity; + logger.warn(msg); + throw new IllegalArgumentException(msg); + } + } + + @Override + public List<PolicyController> updatePolicyControllers( + List<ControllerConfiguration> configControllers) + throws IllegalArgumentException, IllegalStateException { + + final List<PolicyController> policyControllers = new ArrayList<PolicyController>(); + if (configControllers == null || configControllers.isEmpty()) { + if (logger.isInfoEnabled()) + logger.info("No controller configuration provided: " + configControllers); + return policyControllers; + } + + for (final ControllerConfiguration configController : configControllers) { + try { + final PolicyController policyController = this.updatePolicyController(configController); + policyControllers.add(policyController); + } catch (final Exception e) { + logger.error("{}: cannot update-policy-controllers because of {}", this, e.getMessage(), e); + } + } + + return policyControllers; + } + + @Override + public PolicyController updatePolicyController(ControllerConfiguration configController) { + + if (configController == null) + throw new IllegalArgumentException("No controller configuration has been provided"); + + final String controllerName = configController.getName(); + if (controllerName == null || controllerName.isEmpty()) { + logger.warn("controller-name must be provided"); + throw new IllegalArgumentException("No controller configuration has been provided"); + } + + PolicyController policyController = null; + try { + final String operation = configController.getOperation(); + if (operation == null || operation.isEmpty()) { + logger.warn("operation must be provided"); + throw new IllegalArgumentException("operation must be provided"); + } + + try { + policyController = PolicyController.factory.get(controllerName); + } catch (final IllegalArgumentException e) { + // not found + logger.warn("Policy Controller " + controllerName + " not found", e); + } + + if (policyController == null) { + + if (operation.equalsIgnoreCase(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_LOCK) + || operation + .equalsIgnoreCase(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UNLOCK)) { + throw new IllegalArgumentException( + controllerName + " is not available for operation " + operation); + } + + /* Recovery case */ + + logger.warn("controller " + controllerName + " does not exist. " + + "Attempting recovery from disk"); + + final Properties properties = + SystemPersistence.manager.getControllerProperties(controllerName); + + /* + * returned properties cannot be null (per implementation) assert (properties != null) + */ + + if (properties == null) { + throw new IllegalArgumentException(controllerName + " is invalid"); + } + + logger.warn("controller " + controllerName + " being recovered. " + + "Reset controller's bad maven coordinates to brainless"); + + /* + * try to bring up bad controller in brainless mode, after having it working, apply the new + * create/update operation. + */ + properties.setProperty(PolicyProperties.RULES_GROUPID, DroolsController.NO_GROUP_ID); + properties.setProperty(PolicyProperties.RULES_ARTIFACTID, DroolsController.NO_ARTIFACT_ID); + properties.setProperty(PolicyProperties.RULES_VERSION, DroolsController.NO_VERSION); + + policyController = PolicyEngine.manager.createPolicyController(controllerName, properties); + + /* fall through to do brain update operation */ + } + + switch (operation) { + case ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_CREATE: + PolicyController.factory.patch(policyController, configController.getDrools()); + break; + case ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UPDATE: + policyController.unlock(); + PolicyController.factory.patch(policyController, configController.getDrools()); + break; + case ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_LOCK: + policyController.lock(); + break; + case ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UNLOCK: + policyController.unlock(); + break; + default: + final String msg = "Controller Operation Configuration is not supported: " + operation + + " for " + controllerName; + logger.warn(msg); + throw new IllegalArgumentException(msg); + } + + return policyController; + } catch (final Exception e) { + logger.error("{}: cannot update-policy-controller because of {}", this, e.getMessage(), e); + throw e; + } catch (final LinkageError e) { + logger.error("{}: cannot update-policy-controllers (rules) because of {}", this, + e.getMessage(), e); + throw new IllegalStateException(e); + } + } + + @Override + public synchronized boolean start() { + + /* policy-engine dispatch pre start hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.beforeStart(this)) + return true; + } catch (final Exception e) { + logger.error("{}: feature {} before-start failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + boolean success = true; + if (this.locked) + throw new IllegalStateException("Engine is locked"); + + this.alive = true; + + /* Start Policy Engine exclusively-owned (unmanaged) http servers */ + + for (final HttpServletServer httpServer : this.httpServers) { + try { + if (!httpServer.waitedStart(5 * 1000L)) + success = false; + } catch (final Exception e) { + logger.error("{}: cannot start http-server {} because of {}", this, httpServer, + e.getMessage(), e); + } + } + + /* Start Policy Engine exclusively-owned (unmanaged) sources */ + + for (final TopicSource source : this.sources) { + try { + if (!source.start()) + success = false; + } catch (final Exception e) { + logger.error("{}: cannot start topic-source {} because of {}", this, source, e.getMessage(), + e); + } + } + + /* Start Policy Engine owned (unmanaged) sinks */ + + for (final TopicSink sink : this.sinks) { + try { + if (!sink.start()) + success = false; + } catch (final Exception e) { + logger.error("{}: cannot start topic-sink {} because of {}", this, sink, e.getMessage(), e); + } + } + + /* Start Policy Controllers */ + + final List<PolicyController> controllers = PolicyController.factory.inventory(); + for (final PolicyController controller : controllers) { + try { + if (!controller.start()) + success = false; + } catch (final Exception e) { + logger.error("{}: cannot start policy-controller {} because of {}", this, controller, + e.getMessage(), e); + success = false; + } + } + + /* Start managed Topic Endpoints */ + + try { + if (!TopicEndpoint.manager.start()) + success = false; + } catch (final IllegalStateException e) { + logger.warn("{}: Topic Endpoint Manager is in an invalid state because of {}", this, + e.getMessage(), e); + } + + + // Start the JMX listener + + PdpJmxListener.start(); + + /* policy-engine dispatch after start hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.afterStart(this)) + return success; + } catch (final Exception e) { + logger.error("{}: feature {} after-start failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + return success; + } + + @Override + public synchronized boolean stop() { + + /* policy-engine dispatch pre stop hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.beforeStop(this)) + return true; + } catch (final Exception e) { + logger.error("{}: feature {} before-stop failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + /* stop regardless of the lock state */ + + boolean success = true; + if (!this.alive) + return true; + + this.alive = false; + + final List<PolicyController> controllers = PolicyController.factory.inventory(); + for (final PolicyController controller : controllers) { + try { + if (!controller.stop()) + success = false; + } catch (final Exception e) { + logger.error("{}: cannot stop policy-controller {} because of {}", this, controller, + e.getMessage(), e); + success = false; + } + } + + /* Stop Policy Engine owned (unmanaged) sources */ + for (final TopicSource source : this.sources) { + try { + if (!source.stop()) + success = false; + } catch (final Exception e) { + logger.error("{}: cannot start topic-source {} because of {}", this, source, e.getMessage(), + e); + } + } + + /* Stop Policy Engine owned (unmanaged) sinks */ + for (final TopicSink sink : this.sinks) { + try { + if (!sink.stop()) + success = false; + } catch (final Exception e) { + logger.error("{}: cannot start topic-sink {} because of {}", this, sink, e.getMessage(), e); + } + } + + /* stop all managed topics sources and sinks */ + if (!TopicEndpoint.manager.stop()) + success = false; + + /* stop all unmanaged http servers */ + for (final HttpServletServer httpServer : this.httpServers) { + try { + if (!httpServer.stop()) + success = false; + } catch (final Exception e) { + logger.error("{}: cannot start http-server {} because of {}", this, httpServer, + e.getMessage(), e); + } + } + + /* policy-engine dispatch pre stop hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.afterStop(this)) + return success; + } catch (final Exception e) { + logger.error("{}: feature {} after-stop failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + return success; + } + + @Override + public synchronized void shutdown() { + + /* policy-engine dispatch pre shutdown hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.beforeShutdown(this)) + return; + } catch (final Exception e) { + logger.error("{}: feature {} before-shutdown failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + this.alive = false; + + /* Shutdown Policy Engine owned (unmanaged) sources */ + for (final TopicSource source : this.sources) { + try { + source.shutdown(); + } catch (final Exception e) { + logger.error("{}: cannot shutdown topic-source {} because of {}", this, source, + e.getMessage(), e); + } + } + + /* Shutdown Policy Engine owned (unmanaged) sinks */ + for (final TopicSink sink : this.sinks) { + try { + sink.shutdown(); + } catch (final Exception e) { + logger.error("{}: cannot shutdown topic-sink {} because of {}", this, sink, e.getMessage(), + e); + } + } + + /* Shutdown managed resources */ + PolicyController.factory.shutdown(); + TopicEndpoint.manager.shutdown(); + HttpServletServer.factory.destroy(); + + // Stop the JMX listener + + PdpJmxListener.stop(); + + /* policy-engine dispatch post shutdown hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.afterShutdown(this)) + return; + } catch (final Exception e) { + logger.error("{}: feature {} after-shutdown failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(5000L); + } catch (final InterruptedException e) { + logger.warn("{}: interrupted-exception while shutting down management server: ", this); + } + + /* shutdown all unmanaged http servers */ + for (final HttpServletServer httpServer : PolicyEngineManager.this.getHttpServers()) { + try { + httpServer.shutdown(); + } catch (final Exception e) { + logger.error("{}: cannot shutdown http-server {} because of {}", this, httpServer, + e.getMessage(), e); + } + } + + try { + Thread.sleep(5000L); + } catch (final InterruptedException e) { + logger.warn("{}: interrupted-exception while shutting down management server: ", this); + } + + System.exit(0); + } + }).start(); + } + + @Override + public synchronized boolean isAlive() { + return this.alive; + } + + @Override + public synchronized boolean lock() { + + /* policy-engine dispatch pre lock hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.beforeLock(this)) + return true; + } catch (final Exception e) { + logger.error("{}: feature {} before-lock failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + if (this.locked) + return true; + + this.locked = true; + + boolean success = true; + final List<PolicyController> controllers = PolicyController.factory.inventory(); + for (final PolicyController controller : controllers) { + try { + success = controller.lock() && success; + } catch (final Exception e) { + logger.error("{}: cannot lock policy-controller {} because of {}", this, controller, + e.getMessage(), e); + success = false; + } + } + + success = TopicEndpoint.manager.lock() && success; + + /* policy-engine dispatch post lock hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.afterLock(this)) + return success; + } catch (final Exception e) { + logger.error("{}: feature {} after-lock failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + return success; + } + + @Override + public synchronized boolean unlock() { + + /* policy-engine dispatch pre unlock hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.beforeUnlock(this)) + return true; + } catch (final Exception e) { + logger.error("{}: feature {} before-unlock failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + if (!this.locked) + return true; + + this.locked = false; + + boolean success = true; + final List<PolicyController> controllers = PolicyController.factory.inventory(); + for (final PolicyController controller : controllers) { + try { + success = controller.unlock() && success; + } catch (final Exception e) { + logger.error("{}: cannot unlock policy-controller {} because of {}", this, controller, + e.getMessage(), e); + success = false; + } + } + + success = TopicEndpoint.manager.unlock() && success; + + /* policy-engine dispatch after unlock hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.afterUnlock(this)) + return success; + } catch (final Exception e) { + logger.error("{}: feature {} after-unlock failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + return success; + } + + @Override + public synchronized boolean isLocked() { + return this.locked; + } + + @Override + public void removePolicyController(String name) { + PolicyController.factory.destroy(name); + } + + @Override + public void removePolicyController(PolicyController controller) { + PolicyController.factory.destroy(controller); + } + + @JsonIgnore + @Override + public List<PolicyController> getPolicyControllers() { + return PolicyController.factory.inventory(); + } + + @JsonProperty("controllers") + @Override + public List<String> getPolicyControllerIds() { + final List<String> controllerNames = new ArrayList<String>(); + for (final PolicyController controller : PolicyController.factory.inventory()) { + controllerNames.add(controller.getName()); + } + return controllerNames; + } + + @Override + @JsonIgnore + public Properties getProperties() { + return this.properties; + } + + + @SuppressWarnings("unchecked") + @Override + public List<TopicSource> getSources() { + return (List<TopicSource>) this.sources; + } + + @SuppressWarnings("unchecked") + @Override + public List<TopicSink> getSinks() { + return (List<TopicSink>) this.sinks; + } + + @Override + public List<HttpServletServer> getHttpServers() { + return this.httpServers; + } + + @Override + public List<String> getFeatures() { + final List<String> features = new ArrayList<String>(); + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + features.add(feature.getName()); + } + return features; + } + + @JsonIgnore + @Override + public List<PolicyEngineFeatureAPI> getFeatureProviders() { + return PolicyEngineFeatureAPI.providers.getList(); + } + + @Override + public PolicyEngineFeatureAPI getFeatureProvider(String featureName) { + if (featureName == null || featureName.isEmpty()) + throw new IllegalArgumentException("A feature name must be provided"); + + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + if (feature.getName().equals(featureName)) + return feature; + } + + throw new IllegalArgumentException("Invalid Feature Name: " + featureName); + } + + @Override + public void onTopicEvent(CommInfrastructure commType, String topic, String event) { + /* configuration request */ + try { + final PdpdConfiguration configuration = this.decoder.fromJson(event, PdpdConfiguration.class); + this.configure(configuration); + } catch (final Exception e) { + logger.error("{}: configuration-error due to {} because of {}", this, event, e.getMessage(), + e); + } + } + + @Override + public boolean deliver(String topic, Object event) + throws IllegalArgumentException, IllegalStateException { + + /* + * Note this entry point is usually from the DRL + */ + + if (topic == null || topic.isEmpty()) + throw new IllegalArgumentException("Invalid Topic"); + + if (event == null) + throw new IllegalArgumentException("Invalid Event"); + + if (!this.isAlive()) + throw new IllegalStateException("Policy Engine is stopped"); + + if (this.isLocked()) + throw new IllegalStateException("Policy Engine is locked"); + + final List<? extends TopicSink> sinks = TopicEndpoint.manager.getTopicSinks(topic); + if (sinks == null || sinks.isEmpty() || sinks.size() > 1) + throw new IllegalStateException( + "Cannot ensure correct delivery on topic " + topic + ": " + sinks); + + return this.deliver(sinks.get(0).getTopicCommInfrastructure(), topic, event); + } + + @Override + public boolean deliver(String busType, String topic, Object event) + throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException { + + /* + * Note this entry point is usually from the DRL (one of the reasons busType is String. + */ + + if (busType == null || busType.isEmpty()) + throw new IllegalArgumentException("Invalid Communication Infrastructure"); + + if (topic == null || topic.isEmpty()) + throw new IllegalArgumentException("Invalid Topic"); + + if (event == null) + throw new IllegalArgumentException("Invalid Event"); + + boolean valid = false; + for (final Topic.CommInfrastructure comm : Topic.CommInfrastructure.values()) { + if (comm.name().equals(busType)) { + valid = true; + } + } + + if (!valid) + throw new IllegalArgumentException("Invalid Communication Infrastructure: " + busType); + + + if (!this.isAlive()) + throw new IllegalStateException("Policy Engine is stopped"); + + if (this.isLocked()) + throw new IllegalStateException("Policy Engine is locked"); + + + return this.deliver(Topic.CommInfrastructure.valueOf(busType), topic, event); + } + + @Override + public boolean deliver(Topic.CommInfrastructure busType, String topic, Object event) + throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException { + + if (topic == null || topic.isEmpty()) + throw new IllegalArgumentException("Invalid Topic"); + + if (event == null) + throw new IllegalArgumentException("Invalid Event"); + + if (!this.isAlive()) + throw new IllegalStateException("Policy Engine is stopped"); + + if (this.isLocked()) + throw new IllegalStateException("Policy Engine is locked"); + + /* + * Try to send through the controller, this is the preferred way, since it may want to apply + * additional processing + */ + try { + final DroolsController droolsController = + EventProtocolCoder.manager.getDroolsController(topic, event); + final PolicyController controller = PolicyController.factory.get(droolsController); + if (controller != null) + return controller.deliver(busType, topic, event); + } catch (final Exception e) { + logger.warn("{}: cannot find policy-controller to deliver {} over {}:{} because of {}", this, + event, busType, topic, e.getMessage(), e); + + /* continue (try without routing through the controller) */ + } + + /* + * cannot route through the controller, send directly through the topic sink + */ + try { + final String json = EventProtocolCoder.manager.encode(topic, event); + return this.deliver(busType, topic, json); + + } catch (final Exception e) { + logger.warn("{}: cannot deliver {} over {}:{} because of {}", this, event, busType, topic, + e.getMessage(), e); + throw e; + } + } + + @Override + public boolean deliver(Topic.CommInfrastructure busType, String topic, String event) + throws IllegalArgumentException, IllegalStateException, UnsupportedOperationException { + + if (topic == null || topic.isEmpty()) + throw new IllegalArgumentException("Invalid Topic"); + + if (event == null || event.isEmpty()) + throw new IllegalArgumentException("Invalid Event"); + + if (!this.isAlive()) + throw new IllegalStateException("Policy Engine is stopped"); + + if (this.isLocked()) + throw new IllegalStateException("Policy Engine is locked"); + + try { + final TopicSink sink = TopicEndpoint.manager.getTopicSink(busType, topic); + + if (sink == null) + throw new IllegalStateException("Inconsistent State: " + this); + + return sink.send(event); + + } catch (final Exception e) { + logger.warn("{}: cannot deliver {} over {}:{} because of {}", this, event, busType, topic, + e.getMessage(), e); + throw e; + } + } + + @Override + public synchronized void activate() { + + /* policy-engine dispatch pre activate hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.beforeActivate(this)) + return; + } catch (final Exception e) { + logger.error("{}: feature {} before-activate failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + // activate 'policy-management' + for (final PolicyController policyController : this.getPolicyControllers()) { + try { + policyController.unlock(); + policyController.start(); + } catch (final Exception e) { + logger.error("{}: cannot activate of policy-controller {} because of {}", this, + policyController, e.getMessage(), e); + } catch (final LinkageError e) { + logger.error( + "{}: cannot activate (rules compilation) of policy-controller {} because of {}", this, + policyController, e.getMessage(), e); + } + } + + this.unlock(); + + /* policy-engine dispatch post activate hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.afterActivate(this)) + return; + } catch (final Exception e) { + logger.error("{}: feature {} after-activate failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + } + + @Override + public synchronized void deactivate() { + + /* policy-engine dispatch pre deactivate hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.beforeDeactivate(this)) + return; + } catch (final Exception e) { + logger.error("{}: feature {} before-deactivate failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + + this.lock(); + + for (final PolicyController policyController : this.getPolicyControllers()) { + try { + policyController.stop(); + } catch (final Exception e) { + logger.error("{}: cannot deactivate (stop) policy-controller {} because of {}", this, + policyController, e.getMessage(), e); + } catch (final LinkageError e) { + logger.error("{}: cannot deactivate (stop) policy-controller {} because of {}", this, + policyController, e.getMessage(), e); + } + } + + /* policy-engine dispatch post deactivate hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.afterDeactivate(this)) + return; + } catch (final Exception e) { + logger.error("{}: feature {} after-deactivate failure because of {}", this, + feature.getClass().getName(), e.getMessage(), e); + } + } + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("PolicyEngineManager [alive=").append(this.alive).append(", locked=") + .append(this.locked).append("]"); + return builder.toString(); + } + } |