From f6679d84b20e79e8f9753fbdea08ecd20b913e75 Mon Sep 17 00:00:00 2001 From: Jorge Hernandez Date: Thu, 7 Sep 2017 00:07:32 -0500 Subject: 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 --- .../drools/testtransaction/TestTransaction.java | 350 +- .../testtransaction/TestTransactionTest.java | 220 +- packages/install/pom.xml | 6 + .../drools/persistence/FileSystemPersistence.java | 300 ++ .../drools/persistence/SystemPersistence.java | 323 +- .../policy/drools/server/restful/RestManager.java | 4298 +++++++++----------- .../java/org/onap/policy/drools/system/Main.java | 227 +- .../onap/policy/drools/system/PolicyEngine.java | 2725 +++++++------ policy-management/src/main/server-gen/bin/features | 14 +- .../persistence/test/SystemPersistenceTest.java | 129 + .../drools/system/test/PolicyEngineTest.java | 374 +- .../org/onap/policy/drools/utils/LoggerUtil.java | 54 + 12 files changed, 4532 insertions(+), 4488 deletions(-) create mode 100644 policy-management/src/main/java/org/onap/policy/drools/persistence/FileSystemPersistence.java create mode 100644 policy-management/src/test/java/org/onap/policy/drools/persistence/test/SystemPersistenceTest.java create mode 100644 policy-utils/src/main/java/org/onap/policy/drools/utils/LoggerUtil.java diff --git a/feature-test-transaction/src/main/java/org/onap/policy/drools/testtransaction/TestTransaction.java b/feature-test-transaction/src/main/java/org/onap/policy/drools/testtransaction/TestTransaction.java index b167898a..4da6b6ee 100644 --- a/feature-test-transaction/src/main/java/org/onap/policy/drools/testtransaction/TestTransaction.java +++ b/feature-test-transaction/src/main/java/org/onap/policy/drools/testtransaction/TestTransaction.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,204 +24,190 @@ import java.util.HashMap; import java.util.List; import java.util.Map; - - import org.onap.policy.drools.controller.DroolsController; -import org.onap.policy.drools.controller.internal.MavenDroolsController; import org.onap.policy.drools.system.PolicyController; import org.slf4j.Logger; import org.slf4j.LoggerFactory; + /** - * TestTransaction interface + * TestTransaction interface * */ public interface TestTransaction { - public static final String TT_FPC = "TT.FPC"; - public static final String TT_COUNTER = "$ttc"; - public static final String TT_UUID = "43868e59-d1f3-43c2-bd6f-86f89a61eea5"; - public static long DEFAULT_TT_TASK_SLEEP = 20000; - - public static final TestTransaction manager = new TTImpl(); + public static final String TT_FPC = "TT.FPC"; + public static final String TT_COUNTER = "$ttc"; + public static final String TT_UUID = "43868e59-d1f3-43c2-bd6f-86f89a61eea5"; + public static long DEFAULT_TT_TASK_SLEEP = 20000; - public void register(PolicyController controller); - public void unregister(PolicyController controller); + public static final TestTransaction manager = new TTImpl(); + + public void register(PolicyController controller); + + public void unregister(PolicyController controller); } + /** - * Implementation of TestTransaction interface. - * Controls the registering/unregistering of - * PolicyController objects and the management - * of their related TTControllerTask threads. + * Implementation of TestTransaction interface. Controls the registering/unregistering of + * PolicyController objects and the management of their related TTControllerTask threads. */ class TTImpl implements TestTransaction { - - final protected Map controllers = new HashMap<>(); - - @Override - public synchronized void register(PolicyController controller) { - if (controllers.containsValue(controller)) { - TTControllerTask controllerTask = controllers.get(controller.getName()); - if (controllerTask.isAlive()) - return; - - // continue : unregister, register operation - } - - TTControllerTask controllerTask = new TTControllerTask(controller); - controllers.put(controller.getName(), controllerTask); - } - - @Override - public synchronized void unregister(PolicyController controller) { - if (!controllers.containsValue(controller)) - return; - - TTControllerTask controllerTask = controllers.get(controller.getName()); - controllerTask.stop(); - - controllers.remove(controller.getName()); - } + + final protected Map controllers = new HashMap<>(); + + @Override + public synchronized void register(PolicyController controller) { + if (this.controllers.containsValue(controller)) { + final TTControllerTask controllerTask = this.controllers.get(controller.getName()); + if (controllerTask.isAlive()) + return; + + // continue : unregister, register operation + } + + final TTControllerTask controllerTask = new TTControllerTask(controller); + this.controllers.put(controller.getName(), controllerTask); + } + + @Override + public synchronized void unregister(PolicyController controller) { + if (!this.controllers.containsValue(controller)) + return; + + final TTControllerTask controllerTask = this.controllers.get(controller.getName()); + controllerTask.stop(); + + this.controllers.remove(controller.getName()); + } } + /** - * TTControllerTask implements the Runnabale interface - * Carries out the injection of an event into a drools - * session and subsequent query of a counter to ensure - * that forward progress is occuring. - * + * TTControllerTask implements the Runnabale interface Carries out the injection of an event into a + * drools session and subsequent query of a counter to ensure that forward progress is occuring. + * */ class TTControllerTask implements Runnable { - // get an instance of logger - private static final Logger logger = LoggerFactory.getLogger(TTControllerTask.class); - - protected final PolicyController controller; - - protected volatile boolean alive = true; - protected final Thread thread = new Thread(this); - - public TTControllerTask(PolicyController controller) { - this.controller = controller; - thread.setName("tt-controller-task-" + controller.getName()); - thread.start(); - } - - public PolicyController getController() { - return controller; - } - - public synchronized boolean isAlive() { - return alive; - } - - public synchronized void stop() { - this.alive = false; - thread.interrupt(); - try { - thread.join(1000); - } catch (InterruptedException e) { - logger.error("TestTransaction thread threw", e); - thread.interrupt(); - } - } - - public Thread getThread() { - return thread; - } - - @Override - public void run() { - try { - List sessions = - controller.getDrools().getSessionNames(); - - if (!(controller.getDrools().isBrained())) { - alive = false; - logger.error(this + ": unknown drools controller"); - return; - } - - DroolsController drools = controller.getDrools(); - - HashMap fpcs = new HashMap<>(); - for (String session: sessions) { - fpcs.put(session, -1L); - } - - while (controller.isAlive() && - !controller.isLocked() && - drools.isBrained() && - alive) { - - for (String session : sessions) { - List facts = controller.getDrools().factQuery(session, - TestTransaction.TT_FPC, - TestTransaction.TT_COUNTER, - false); - if (facts == null || facts.size() != 1) { - /* - * unexpected something wrong here, can't expect to recover - * note this exception is caught right below at the exit of run() - */ - logger.error("Controller: {}, with rules artifact: (group) {}, (artifact) {}, (version) {} - FPC query failed after EventObject insertion! ", - controller.getName(), - controller.getDrools().getGroupId(), - controller.getDrools().getArtifactId(), - controller.getDrools().getVersion()); - break; - } - logger.debug("Facts: {}", facts); - - long fpc = (Long) facts.get(0); - if (fpc != fpcs.get(session)) - logger.info("Controller: {} , session {} - Forward progress successful: {} -> {}", - controller.getName(), - session, - fpcs.get(session), - fpc); - else - logger.error("Controller: {}, session {} - Forward progress failure: {}", - controller.getName(), - session, - fpc); - - fpcs.put(session, fpc); - drools.getContainer().insert(session, new EventObject(TestTransaction.TT_UUID)); - } - - if (!alive) - return; - - if (!Thread.currentThread().isInterrupted()) - Thread.sleep(TestTransaction.DEFAULT_TT_TASK_SLEEP); - } - } catch (InterruptedException e) { - logger.info("{}: stopping ...", this, e); - } - catch (IllegalArgumentException e) { - logger.error("{}: controller {} has not been enabled for testing: ", this, controller.getName(), e.getMessage()); - } catch (Exception e) { - logger.error("Controller: {} is not testable - TestTransaction caught exception: {} ", - controller.getName(), - e.getMessage()); - logger.error("TestTransaction thread threw", e); - } finally { - logger.info("Exiting: {}", this); - alive = false; - } - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("TTControllerTask [controller="); - builder.append(controller); - builder.append(", alive="); - builder.append(alive); - builder.append(", thread="); - builder.append(thread.getName()); - builder.append("]"); - return builder.toString(); - } - + // get an instance of logger + private static final Logger logger = LoggerFactory.getLogger(TTControllerTask.class); + + protected final PolicyController controller; + + protected volatile boolean alive = true; + protected final Thread thread = new Thread(this); + + public TTControllerTask(PolicyController controller) { + this.controller = controller; + this.thread.setName("tt-controller-task-" + controller.getName()); + this.thread.start(); + } + + public PolicyController getController() { + return this.controller; + } + + public synchronized boolean isAlive() { + return this.alive; + } + + public synchronized void stop() { + this.alive = false; + this.thread.interrupt(); + try { + this.thread.join(1000); + } catch (final InterruptedException e) { + logger.error("TestTransaction thread threw", e); + this.thread.interrupt(); + } + } + + public Thread getThread() { + return this.thread; + } + + @Override + public void run() { + try { + final List sessions = this.controller.getDrools().getSessionNames(); + + if (!(this.controller.getDrools().isBrained())) { + this.alive = false; + logger.error(this + ": unknown drools controller"); + return; + } + + final DroolsController drools = this.controller.getDrools(); + + final HashMap fpcs = new HashMap<>(); + for (final String session : sessions) { + fpcs.put(session, -1L); + } + + while (this.controller.isAlive() && !this.controller.isLocked() && drools.isBrained() + && this.alive) { + + for (final String session : sessions) { + final List facts = this.controller.getDrools().factQuery(session, + TestTransaction.TT_FPC, TestTransaction.TT_COUNTER, false); + if (facts == null || facts.size() != 1) { + /* + * unexpected something wrong here, can't expect to recover note this exception is + * caught right below at the exit of run() + */ + logger.error( + "Controller: {}, with rules artifact: (group) {}, (artifact) {}, (version) {} - FPC query failed after EventObject insertion! ", + this.controller.getName(), this.controller.getDrools().getGroupId(), + this.controller.getDrools().getArtifactId(), + this.controller.getDrools().getVersion()); + break; + } + logger.debug("Facts: {}", facts); + + final long fpc = (Long) facts.get(0); + if (fpc != fpcs.get(session)) + logger.info("Controller: {} , session {} - Forward progress successful: {} -> {}", + this.controller.getName(), session, fpcs.get(session), fpc); + else + logger.error("Controller: {}, session {} - Forward progress failure: {}", + this.controller.getName(), session, fpc); + + fpcs.put(session, fpc); + drools.getContainer().insert(session, new EventObject(TestTransaction.TT_UUID)); + } + + if (!this.alive) + return; + + if (!Thread.currentThread().isInterrupted()) + Thread.sleep(TestTransaction.DEFAULT_TT_TASK_SLEEP); + } + } catch (final InterruptedException e) { + logger.info("{}: stopping ...", this, e); + } catch (final IllegalArgumentException e) { + logger.error("{}: controller {} has not been enabled for testing: ", this, + this.controller.getName(), e.getMessage()); + } catch (final Exception e) { + logger.error("Controller: {} is not testable - TestTransaction caught exception: {} ", + this.controller.getName(), e.getMessage()); + logger.error("TestTransaction thread threw", e); + } finally { + logger.info("Exiting: {}", this); + this.alive = false; + } + } + + @Override + public String toString() { + final StringBuilder builder = new StringBuilder(); + builder.append("TTControllerTask [controller="); + builder.append(this.controller); + builder.append(", alive="); + builder.append(this.alive); + builder.append(", thread="); + builder.append(this.thread.getName()); + builder.append("]"); + return builder.toString(); + } + } diff --git a/feature-test-transaction/src/test/java/org/onap/policy/drools/testtransaction/TestTransactionTest.java b/feature-test-transaction/src/test/java/org/onap/policy/drools/testtransaction/TestTransactionTest.java index 2a44e1c1..6c60c5ac 100644 --- a/feature-test-transaction/src/test/java/org/onap/policy/drools/testtransaction/TestTransactionTest.java +++ b/feature-test-transaction/src/test/java/org/onap/policy/drools/testtransaction/TestTransactionTest.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. @@ -40,113 +40,111 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class TestTransactionTest { - /** - * Test JUnit Controller Name - */ - public static final String TEST_CONTROLLER_NAME = "unnamed"; - /** - * Controller Configuration File - */ - public static final String TEST_CONTROLLER_FILE = TEST_CONTROLLER_NAME + "-controller.properties"; - - /** - * Controller Configuration Backup File - */ - public static final String TEST_CONTROLLER_FILE_BAK = TEST_CONTROLLER_NAME + "-controller.properties.bak"; - - - /** - * logger - */ - private static Logger logger = LoggerFactory.getLogger(TestTransactionTest.class); - - - - @BeforeClass - public static void startUp() throws IOException { - logger.info("enter"); - - cleanUpWorkingDir(); - - /* ensure presence of config directory */ - Path configDir = Paths.get(SystemPersistence.CONFIG_DIR_NAME); - if (Files.notExists(configDir)) - Files.createDirectories(configDir); - } - - @Test - public void registerUnregisterTest() { - Properties controllerProperties = new Properties(); - controllerProperties.put(PolicyProperties.PROPERTY_CONTROLLER_NAME, TEST_CONTROLLER_NAME); - PolicyController controller = PolicyEngine.manager.createPolicyController(TEST_CONTROLLER_NAME, controllerProperties); - Thread ttThread = null; - - TestTransaction.manager.register(controller); - assertNotNull(TestTransaction.manager); - - /* - * If the controller was successfully registered - * it will have a thread created. - */ - ttThread = getThread("tt-controller-task-" + TEST_CONTROLLER_NAME); - assertNotNull(ttThread); - - /* - * Unregistering the controller should - * terminate its TestTransaction thread - * if it hasn't already been terminated - */ - TestTransaction.manager.unregister(controller); - - /* - * Put this thread to sleep so the TestTransaction - * thread has enough time to terminate before - * we check. - */ - try { - Thread.sleep(2000); - } catch (InterruptedException e) { - - } - ttThread = getThread("tt-controller-task-" + TEST_CONTROLLER_NAME); - assertEquals(null, ttThread); - - - } - - /* - * Returns thread object based on - * String name - */ - public Thread getThread(String threadName) { - - Set threadSet = Thread.getAllStackTraces().keySet(); - for (Thread thread : threadSet) { - if (thread.getName().equals(threadName)) { - return thread; - } - - } - return null; - } - - /** - * clean up working directory - */ - protected static void cleanUpWorkingDir() { - Path testControllerPath = Paths.get(SystemPersistence.CONFIG_DIR_NAME, TEST_CONTROLLER_FILE); - try { - Files.deleteIfExists(testControllerPath); - } catch (Exception e) { - logger.info("Problem cleaning {}", testControllerPath, e); - } - - Path testControllerBakPath = Paths.get(SystemPersistence.CONFIG_DIR_NAME, TEST_CONTROLLER_FILE_BAK); - try { - Files.deleteIfExists(testControllerBakPath); - } catch (Exception e) { - logger.info("Problem cleaning {}", testControllerBakPath, e); - } - } - + /** + * Test JUnit Controller Name + */ + public static final String TEST_CONTROLLER_NAME = "unnamed"; + /** + * Controller Configuration File + */ + public static final String TEST_CONTROLLER_FILE = TEST_CONTROLLER_NAME + "-controller.properties"; + + /** + * Controller Configuration Backup File + */ + public static final String TEST_CONTROLLER_FILE_BAK = + TEST_CONTROLLER_NAME + "-controller.properties.bak"; + + + /** + * logger + */ + private static Logger logger = LoggerFactory.getLogger(TestTransactionTest.class); + + + + @BeforeClass + public static void startUp() throws IOException { + logger.info("enter"); + + cleanUpWorkingDir(); + + /* ensure presence of config directory */ + SystemPersistence.manager.setConfigurationDir(null); + } + + @Test + public void registerUnregisterTest() { + final Properties controllerProperties = new Properties(); + controllerProperties.put(PolicyProperties.PROPERTY_CONTROLLER_NAME, TEST_CONTROLLER_NAME); + final PolicyController controller = + PolicyEngine.manager.createPolicyController(TEST_CONTROLLER_NAME, controllerProperties); + Thread ttThread = null; + + TestTransaction.manager.register(controller); + assertNotNull(TestTransaction.manager); + + /* + * If the controller was successfully registered it will have a thread created. + */ + ttThread = this.getThread("tt-controller-task-" + TEST_CONTROLLER_NAME); + assertNotNull(ttThread); + + /* + * Unregistering the controller should terminate its TestTransaction thread if it hasn't already + * been terminated + */ + TestTransaction.manager.unregister(controller); + + /* + * Put this thread to sleep so the TestTransaction thread has enough time to terminate before we + * check. + */ + try { + Thread.sleep(2000); + } catch (final InterruptedException e) { + + } + ttThread = this.getThread("tt-controller-task-" + TEST_CONTROLLER_NAME); + assertEquals(null, ttThread); + + + } + + /* + * Returns thread object based on String name + */ + public Thread getThread(String threadName) { + + final Set threadSet = Thread.getAllStackTraces().keySet(); + for (final Thread thread : threadSet) { + if (thread.getName().equals(threadName)) { + return thread; + } + + } + return null; + } + + /** + * clean up working directory + */ + protected static void cleanUpWorkingDir() { + final Path testControllerPath = Paths + .get(SystemPersistence.manager.getConfigurationPath().toString(), TEST_CONTROLLER_FILE); + try { + Files.deleteIfExists(testControllerPath); + } catch (final Exception e) { + logger.info("Problem cleaning {}", testControllerPath, e); + } + + final Path testControllerBakPath = Paths + .get(SystemPersistence.manager.getConfigurationPath().toString(), TEST_CONTROLLER_FILE_BAK); + try { + Files.deleteIfExists(testControllerBakPath); + } catch (final Exception e) { + logger.info("Problem cleaning {}", testControllerBakPath, e); + } + } + } diff --git a/packages/install/pom.xml b/packages/install/pom.xml index db71e872..2b3a136d 100644 --- a/packages/install/pom.xml +++ b/packages/install/pom.xml @@ -89,6 +89,12 @@ ${project.version} zip + + org.onap.policy.drools-pdp + feature-test-transaction + ${project.version} + zip + 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 getControllerProperties() { + final List 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 " + + 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 getEnvironmentProperties() { + final List 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 getControllerProperties(); + + /** + * get environments + * + * @param environment name + */ + public List 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 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 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 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 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 queryParameters) { - try { - DroolsController drools = getDroolsController(controllerName); - List 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 queryParameters) { - try { - DroolsController drools = getDroolsController(controllerName); - List 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 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 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 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 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 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 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 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 queryParameters) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + List 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 queryParameters) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + List 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 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 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 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 names = new ArrayList(); + 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 names = new ArrayList(); - 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 " + - 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. - *
- * PolicyEngine 1 --- * PolicyController 1 --- 1 DroolsController 1 --- 1 PolicyContainer 1 --- * PolicySession - *
- * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 UebTopicReader - *
- * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 DmaapTopicReader - *
- * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 DmaapTopicWriter - *
- * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 RestTopicReader - *
- * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 RestTopicWriter - *
+ * 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.
+ * PolicyEngine 1 --- * PolicyController 1 --- 1 DroolsController 1 --- 1 PolicyContainer 1 --- * + * PolicySession
+ * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 UebTopicReader
+ * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 DmaapTopicReader
+ * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 DmaapTopicWriter
+ * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 RestTopicReader
+ * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 RestTopicWriter
* 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 updatePolicyControllers(List 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 getPolicyControllers(); - - - /** - * get policy controller names - * - * @return list of controller names - */ - public List getPolicyControllerIds(); - - /** - * get unmanaged sources - * - * @return unmanaged sources - */ - public List getSources(); - - /** - * get unmanaged sinks - * - * @return unmanaged sinks - */ - public List getSinks(); - - /** - * get unmmanaged http servers list - * @return http servers - */ - public List getHttpServers(); - - /** - * get properties configuration - * - * @return properties objects - */ - public Properties getProperties(); - - /** - * get features attached to the Policy Engine - * @return list of features - */ - public List 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 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 updatePolicyControllers( + List 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 getPolicyControllers(); + + + /** + * get policy controller names + * + * @return list of controller names + */ + public List getPolicyControllerIds(); + + /** + * get unmanaged sources + * + * @return unmanaged sources + */ + public List getSources(); + + /** + * get unmanaged sinks + * + * @return unmanaged sinks + */ + public List getSinks(); + + /** + * get unmmanaged http servers list + * + * @return http servers + */ + public List getHttpServers(); + + /** + * get properties configuration + * + * @return properties objects + */ + public Properties getProperties(); + + /** + * get features attached to the Policy Engine + * + * @return list of features + */ + public List 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 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 sources = new ArrayList<>(); - - /** - * Policy Engine Sinks - */ - protected List sinks = new ArrayList<>(); - - /** - * Policy Engine HTTP Servers - */ - protected List httpServers = new ArrayList(); - - /** - * 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 configControllers = config.getControllers(); - if (configControllers == null || configControllers.isEmpty()) { - if (logger.isInfoEnabled()) - logger.info("No controller configuration provided: " + config); - return false; - } - List 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 updatePolicyControllers(List configControllers) - throws IllegalArgumentException, IllegalStateException { - - List policyControllers = new ArrayList(); - 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 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 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 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 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 getPolicyControllers() { - return PolicyController.factory.inventory(); - } - - @JsonProperty("controllers") - @Override - public List getPolicyControllerIds() { - List controllerNames = new ArrayList(); - 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 getSources() { - return (List) this.sources; - } - - @SuppressWarnings("unchecked") - @Override - public List getSinks() { - return (List) this.sinks; - } - - @Override - public List getHttpServers() { - return this.httpServers; - } - - @Override - public List getFeatures() { - List features = new ArrayList(); - for (PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - features.add(feature.getName()); - } - return features; - } - - @JsonIgnore - @Override - public List 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 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 sources = new ArrayList<>(); + + /** + * Policy Engine Sinks + */ + protected List sinks = new ArrayList<>(); + + /** + * Policy Engine HTTP Servers + */ + protected List httpServers = new ArrayList(); + + /** + * 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 configControllers = config.getControllers(); + if (configControllers == null || configControllers.isEmpty()) { + if (logger.isInfoEnabled()) + logger.info("No controller configuration provided: " + config); + return false; + } + final List 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 updatePolicyControllers( + List configControllers) + throws IllegalArgumentException, IllegalStateException { + + final List policyControllers = new ArrayList(); + 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 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 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 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 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 getPolicyControllers() { + return PolicyController.factory.inventory(); + } + + @JsonProperty("controllers") + @Override + public List getPolicyControllerIds() { + final List controllerNames = new ArrayList(); + 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 getSources() { + return (List) this.sources; + } + + @SuppressWarnings("unchecked") + @Override + public List getSinks() { + return (List) this.sinks; + } + + @Override + public List getHttpServers() { + return this.httpServers; + } + + @Override + public List getFeatures() { + final List features = new ArrayList(); + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + features.add(feature.getName()); + } + return features; + } + + @JsonIgnore + @Override + public List 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 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(); + } + } diff --git a/policy-management/src/main/server-gen/bin/features b/policy-management/src/main/server-gen/bin/features index 80a1b279..b2e9bd5b 100644 --- a/policy-management/src/main/server-gen/bin/features +++ b/policy-management/src/main/server-gen/bin/features @@ -142,6 +142,7 @@ LIB=${POLICY_HOME}/lib CONFIG=${POLICY_HOME}/config DB=${POLICY_HOME}/etc/db/migration FEATURES=${POLICY_HOME}/features +PROFILED=${POLICY_HOME}/etc/profile.d if [[ ! ( -d "${LIB}" && -x "${LIB}" ) ]]; then echo "error: no ${LIB} directory" @@ -171,6 +172,7 @@ FEATURE_SQL="sql" UPGRADE_SQL_SUFFIX=".upgrade.sql" DOWNGRADE_SQL_SUFFIX=".downgrade.sql" +ENVIRONMENT_SUFFIX=".environment" featureJars=$(find "${FEATURES}" -name "feature-*.jar" -type f -exec basename {} \; 2> /dev/null) @@ -422,6 +424,7 @@ function enableFeatureConfig() fi local featureName="$1" + local featureInstallConf=feature-"${featureName}".conf local featureConfigs featureConfigPath if [[ -z ${featureName} ]]; then @@ -432,7 +435,11 @@ function enableFeatureConfig() featureConfigs=$(find "${FEATURES}"/"${featureName}"/"${FEATURE_CONFIG}"/ -type f -maxdepth 1 2> /dev/null) for featureConfigPath in ${featureConfigs}; do ln -s -f "${featureConfigPath}" "${CONFIG}/" - done + done + + if [[ -f "${PROFILED}"/"${featureInstallConf}" ]]; then + ln -s -f "${PROFILED}"/"${featureInstallConf}" "${CONFIG}"/"${featureInstallConf}""${ENVIRONMENT_SUFFIX}" + fi } # ########################################################## @@ -697,6 +704,7 @@ function disableFeatureConfig() fi local featureName="$1" + local featureInstallConf=feature-"${featureName}".conf local featureConfigs featureConfigPath if [[ -z ${featureName} ]]; then @@ -708,7 +716,9 @@ function disableFeatureConfig() for featureConfigPath in ${featureConfigs}; do configFileName=$(basename "${featureConfigPath}") rm -f "${CONFIG}"/"${configFileName}" 2> /dev/null - done + done + + rm -f "${CONFIG}"/"${featureInstallConf}""${ENVIRONMENT_SUFFIX}" 2> /dev/null } # ########################################################## diff --git a/policy-management/src/test/java/org/onap/policy/drools/persistence/test/SystemPersistenceTest.java b/policy-management/src/test/java/org/onap/policy/drools/persistence/test/SystemPersistenceTest.java new file mode 100644 index 00000000..db8f306c --- /dev/null +++ b/policy-management/src/test/java/org/onap/policy/drools/persistence/test/SystemPersistenceTest.java @@ -0,0 +1,129 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * 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.test; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +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.junit.BeforeClass; +import org.junit.Test; +import org.onap.policy.drools.persistence.SystemPersistence; +import org.onap.policy.drools.properties.PolicyProperties; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * (File) System Persistence Tests + */ +public class SystemPersistenceTest { + + /** + * logger + */ + private static final Logger logger = LoggerFactory.getLogger(SystemPersistenceTest.class); + + /** + * sample configuration dir + */ + public static final String OTHER_CONFIG_DIR = "tmp"; + + /** + * Test JUnit Controller Name + */ + public static final String TEST_CONTROLLER_NAME = "blue"; + + /** + * Test JUnit Controller Name + */ + public static final String TEST_CONTROLLER_FILE = TEST_CONTROLLER_NAME + "-controller.properties"; + + /** + * Test JUnit Controller Name Backup + */ + public static final String TEST_CONTROLLER_FILE_BAK = + TEST_CONTROLLER_NAME + "-controller.properties.bak"; + + @Test + public void nonDefaultConfigDir() throws IOException { + logger.info("enter"); + + SystemPersistence.manager.setConfigurationDir(OTHER_CONFIG_DIR); + assertTrue( + SystemPersistence.manager.getConfigurationPath().toString().equals(OTHER_CONFIG_DIR)); + + SystemPersistence.manager.setConfigurationDir(null); + assertTrue(SystemPersistence.manager.getConfigurationPath().toString() + .equals(SystemPersistence.DEFAULT_CONFIGURATION_DIR)); + + this.persistConfiguration(); + + cleanUpWorkingDirs(); + } + + public void persistConfiguration() { + logger.info("enter"); + + final Path controllerPath = Paths + .get(SystemPersistence.manager.getConfigurationPath().toString(), TEST_CONTROLLER_FILE); + + final Path controllerBakPath = Paths + .get(SystemPersistence.manager.getConfigurationPath().toString(), TEST_CONTROLLER_FILE_BAK); + + assertTrue(Files.notExists(controllerPath)); + assertTrue(Files.notExists(controllerBakPath)); + + Properties properties = new Properties(); + properties.put(PolicyProperties.PROPERTY_CONTROLLER_NAME, TEST_CONTROLLER_NAME); + SystemPersistence.manager.storeController(TEST_CONTROLLER_NAME, properties); + + assertTrue(Files.exists(controllerPath)); + + properties = SystemPersistence.manager.getControllerProperties(TEST_CONTROLLER_NAME); + assertTrue(properties != null); + + SystemPersistence.manager.backupController(TEST_CONTROLLER_NAME); + assertTrue(Files.exists(controllerBakPath)); + + assertFalse(SystemPersistence.manager.getControllerProperties().isEmpty()); + + SystemPersistence.manager.deleteController(TEST_CONTROLLER_NAME); + assertTrue(Files.notExists(controllerPath)); + } + + @BeforeClass + public static void cleanUpWorkingDirs() throws IOException { + final Path testControllerPath = Paths + .get(SystemPersistence.manager.getConfigurationPath().toString(), TEST_CONTROLLER_FILE); + + final Path testControllerBakPath = Paths + .get(SystemPersistence.manager.getConfigurationPath().toString(), TEST_CONTROLLER_FILE_BAK); + + Files.deleteIfExists(testControllerPath); + Files.deleteIfExists(testControllerBakPath); + Files.deleteIfExists(Paths.get(OTHER_CONFIG_DIR)); + } + +} diff --git a/policy-management/src/test/java/org/onap/policy/drools/system/test/PolicyEngineTest.java b/policy-management/src/test/java/org/onap/policy/drools/system/test/PolicyEngineTest.java index 4928ca0a..5ab6c580 100644 --- a/policy-management/src/test/java/org/onap/policy/drools/system/test/PolicyEngineTest.java +++ b/policy-management/src/test/java/org/onap/policy/drools/system/test/PolicyEngineTest.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. @@ -46,189 +46,191 @@ import org.slf4j.LoggerFactory; @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class PolicyEngineTest { - /** - * Default Telemetry port for JUnits - */ - public static final int DEFAULT_TELEMETRY_PORT = 9698; - - /** - * Test JUnit Controller Name - */ - public static final String TEST_CONTROLLER_NAME = "unnamed"; - - /** - * Controller Configuration File - */ - public static final String TEST_CONTROLLER_FILE = TEST_CONTROLLER_NAME + "-controller.properties"; - - /** - * Controller Configuration Backup File - */ - public static final String TEST_CONTROLLER_FILE_BAK = TEST_CONTROLLER_NAME + "-controller.properties.bak"; - - /** - * logger - */ - private static Logger logger = LoggerFactory.getLogger(PolicyEngineTest.class); - - /** - * clean up working directory - */ - protected static void cleanUpWorkingDir() { - Path testControllerPath = Paths.get(SystemPersistence.CONFIG_DIR_NAME, TEST_CONTROLLER_FILE); - try { - Files.deleteIfExists(testControllerPath); - } catch (Exception e) { - logger.info("Problem cleaning {}", testControllerPath, e); - } - - Path testControllerBakPath = Paths.get(SystemPersistence.CONFIG_DIR_NAME, TEST_CONTROLLER_FILE_BAK); - try { - Files.deleteIfExists(testControllerBakPath); - } catch (Exception e) { - logger.info("Problem cleaning {}", testControllerBakPath, e); - } - } - - @BeforeClass - public static void startUp() throws IOException { - logger.info("enter"); - - cleanUpWorkingDir(); - - /* ensure presence of config directory */ - Path configDir = Paths.get(SystemPersistence.CONFIG_DIR_NAME); - if (Files.notExists(configDir)) - Files.createDirectories(configDir); - } - - @AfterClass - public static void tearDown() throws IOException { - logger.info("enter"); - cleanUpWorkingDir(); - } - - @Test - public void test100Configure() { - logger.info("enter"); - - Properties engineProps = PolicyEngine.manager.defaultTelemetryConfig(); - - /* override default port */ - engineProps.put(PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + - PolicyEngine.TELEMETRY_SERVER_DEFAULT_NAME + - PolicyProperties.PROPERTY_HTTP_PORT_SUFFIX, - ""+DEFAULT_TELEMETRY_PORT); - - assertFalse(PolicyEngine.manager.isAlive()); - PolicyEngine.manager.configure(engineProps); - assertFalse(PolicyEngine.manager.isAlive()); - - logger.info("policy-engine {} has configuration {}", PolicyEngine.manager, engineProps); - } - - @Test - public void test200Start() { - logger.info("enter"); - - PolicyEngine.manager.start(); - - assertTrue(PolicyEngine.manager.isAlive()); - assertFalse(PolicyEngine.manager.isLocked()); - assertFalse(PolicyEngine.manager.getHttpServers().isEmpty()); - assertTrue(PolicyEngine.manager.getHttpServers().get(0).isAlive()); - } - - @Test - public void test300Lock() { - logger.info("enter"); - - PolicyEngine.manager.lock(); - - assertTrue(PolicyEngine.manager.isAlive()); - assertTrue(PolicyEngine.manager.isLocked()); - assertFalse(PolicyEngine.manager.getHttpServers().isEmpty()); - assertTrue(PolicyEngine.manager.getHttpServers().get(0).isAlive()); - } - - @Test - public void test301Unlock() { - logger.info("enter"); - - PolicyEngine.manager.unlock(); - - assertTrue(PolicyEngine.manager.isAlive()); - assertFalse(PolicyEngine.manager.isLocked()); - assertFalse(PolicyEngine.manager.getHttpServers().isEmpty()); - assertTrue(PolicyEngine.manager.getHttpServers().get(0).isAlive()); - } - - @Test - public void test400ControllerAdd() throws Exception { - logger.info("enter"); - - Properties controllerProperties = new Properties(); - controllerProperties.put(PolicyProperties.PROPERTY_CONTROLLER_NAME, TEST_CONTROLLER_NAME); - PolicyEngine.manager.createPolicyController(TEST_CONTROLLER_NAME, controllerProperties); - - assertTrue(PolicyController.factory.inventory().size() == 1); - } - - @Test - public void test401ControllerVerify() { - logger.info("enter"); - - PolicyController testController = PolicyController.factory.get(TEST_CONTROLLER_NAME); - - assertFalse(testController.isAlive()); - assertFalse(testController.isLocked()); - - testController.start(); - - assertTrue(testController.isAlive()); - assertFalse(testController.isLocked()); - } - - @Test - public void test500Deactivate() throws Exception { - logger.info("enter"); - - PolicyEngine.manager.deactivate(); - - PolicyController testController = PolicyController.factory.get(TEST_CONTROLLER_NAME); - assertFalse(testController.isAlive()); - assertTrue(testController.isLocked()); - assertTrue(PolicyEngine.manager.isLocked()); - assertTrue(PolicyEngine.manager.isAlive()); - } - - @Test - public void test501Activate() throws Exception { - logger.info("enter"); - - PolicyEngine.manager.activate(); - - PolicyController testController = PolicyController.factory.get(TEST_CONTROLLER_NAME); - assertTrue(testController.isAlive()); - assertFalse(testController.isLocked()); - assertFalse(PolicyEngine.manager.isLocked()); - assertTrue(PolicyEngine.manager.isAlive()); - } - - @Test - public void test900ControllerRemove() throws Exception { - logger.info("enter"); - - PolicyEngine.manager.removePolicyController(TEST_CONTROLLER_NAME); - assertTrue(PolicyController.factory.inventory().isEmpty()); - } - - @Test - public void test901Stop() { - logger.info("enter"); - - PolicyEngine.manager.stop(); - assertFalse(PolicyEngine.manager.isAlive()); - } + /** + * Default Telemetry port for JUnits + */ + public static final int DEFAULT_TELEMETRY_PORT = 9698; + + /** + * Test JUnit Controller Name + */ + public static final String TEST_CONTROLLER_NAME = "unnamed"; + + /** + * Controller Configuration File + */ + public static final String TEST_CONTROLLER_FILE = TEST_CONTROLLER_NAME + "-controller.properties"; + + /** + * Controller Configuration Backup File + */ + public static final String TEST_CONTROLLER_FILE_BAK = + TEST_CONTROLLER_NAME + "-controller.properties.bak"; + + /** + * logger + */ + private static Logger logger = LoggerFactory.getLogger(PolicyEngineTest.class); + + /** + * clean up working directory + */ + protected static void cleanUpWorkingDir() { + final Path testControllerPath = Paths + .get(SystemPersistence.manager.getConfigurationPath().toString(), TEST_CONTROLLER_FILE); + try { + Files.deleteIfExists(testControllerPath); + } catch (final Exception e) { + logger.info("Problem cleaning {}", testControllerPath, e); + } + + final Path testControllerBakPath = Paths + .get(SystemPersistence.manager.getConfigurationPath().toString(), TEST_CONTROLLER_FILE_BAK); + try { + Files.deleteIfExists(testControllerBakPath); + } catch (final Exception e) { + logger.info("Problem cleaning {}", testControllerBakPath, e); + } + } + + @BeforeClass + public static void startUp() throws IOException { + logger.info("enter"); + + cleanUpWorkingDir(); + + /* ensure presence of config directory */ + final Path configDir = Paths.get(SystemPersistence.DEFAULT_CONFIGURATION_DIR); + if (Files.notExists(configDir)) + Files.createDirectories(configDir); + } + + @AfterClass + public static void tearDown() throws IOException { + logger.info("enter"); + cleanUpWorkingDir(); + } + + @Test + public void test100Configure() { + logger.info("enter"); + + final Properties engineProps = PolicyEngine.manager.defaultTelemetryConfig(); + + /* override default port */ + engineProps.put(PolicyProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + + PolicyEngine.TELEMETRY_SERVER_DEFAULT_NAME + PolicyProperties.PROPERTY_HTTP_PORT_SUFFIX, + "" + DEFAULT_TELEMETRY_PORT); + + assertFalse(PolicyEngine.manager.isAlive()); + PolicyEngine.manager.configure(engineProps); + assertFalse(PolicyEngine.manager.isAlive()); + + logger.info("policy-engine {} has configuration {}", PolicyEngine.manager, engineProps); + } + + @Test + public void test200Start() { + logger.info("enter"); + + PolicyEngine.manager.start(); + + assertTrue(PolicyEngine.manager.isAlive()); + assertFalse(PolicyEngine.manager.isLocked()); + assertFalse(PolicyEngine.manager.getHttpServers().isEmpty()); + assertTrue(PolicyEngine.manager.getHttpServers().get(0).isAlive()); + } + + @Test + public void test300Lock() { + logger.info("enter"); + + PolicyEngine.manager.lock(); + + assertTrue(PolicyEngine.manager.isAlive()); + assertTrue(PolicyEngine.manager.isLocked()); + assertFalse(PolicyEngine.manager.getHttpServers().isEmpty()); + assertTrue(PolicyEngine.manager.getHttpServers().get(0).isAlive()); + } + + @Test + public void test301Unlock() { + logger.info("enter"); + + PolicyEngine.manager.unlock(); + + assertTrue(PolicyEngine.manager.isAlive()); + assertFalse(PolicyEngine.manager.isLocked()); + assertFalse(PolicyEngine.manager.getHttpServers().isEmpty()); + assertTrue(PolicyEngine.manager.getHttpServers().get(0).isAlive()); + } + + @Test + public void test400ControllerAdd() throws Exception { + logger.info("enter"); + + final Properties controllerProperties = new Properties(); + controllerProperties.put(PolicyProperties.PROPERTY_CONTROLLER_NAME, TEST_CONTROLLER_NAME); + PolicyEngine.manager.createPolicyController(TEST_CONTROLLER_NAME, controllerProperties); + + assertTrue(PolicyController.factory.inventory().size() == 1); + } + + @Test + public void test401ControllerVerify() { + logger.info("enter"); + + final PolicyController testController = PolicyController.factory.get(TEST_CONTROLLER_NAME); + + assertFalse(testController.isAlive()); + assertFalse(testController.isLocked()); + + testController.start(); + + assertTrue(testController.isAlive()); + assertFalse(testController.isLocked()); + } + + @Test + public void test500Deactivate() throws Exception { + logger.info("enter"); + + PolicyEngine.manager.deactivate(); + + final PolicyController testController = PolicyController.factory.get(TEST_CONTROLLER_NAME); + assertFalse(testController.isAlive()); + assertTrue(testController.isLocked()); + assertTrue(PolicyEngine.manager.isLocked()); + assertTrue(PolicyEngine.manager.isAlive()); + } + + @Test + public void test501Activate() throws Exception { + logger.info("enter"); + + PolicyEngine.manager.activate(); + + final PolicyController testController = PolicyController.factory.get(TEST_CONTROLLER_NAME); + assertTrue(testController.isAlive()); + assertFalse(testController.isLocked()); + assertFalse(PolicyEngine.manager.isLocked()); + assertTrue(PolicyEngine.manager.isAlive()); + } + + @Test + public void test900ControllerRemove() throws Exception { + logger.info("enter"); + + PolicyEngine.manager.removePolicyController(TEST_CONTROLLER_NAME); + assertTrue(PolicyController.factory.inventory().isEmpty()); + } + + @Test + public void test901Stop() { + logger.info("enter"); + + PolicyEngine.manager.stop(); + assertFalse(PolicyEngine.manager.isAlive()); + } } diff --git a/policy-utils/src/main/java/org/onap/policy/drools/utils/LoggerUtil.java b/policy-utils/src/main/java/org/onap/policy/drools/utils/LoggerUtil.java new file mode 100644 index 00000000..257d2dae --- /dev/null +++ b/policy-utils/src/main/java/org/onap/policy/drools/utils/LoggerUtil.java @@ -0,0 +1,54 @@ +/*- + * ============LICENSE_START======================================================= + * ONAP + * ================================================================================ + * 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.utils; + +import org.slf4j.LoggerFactory; + +import ch.qos.logback.classic.LoggerContext; + +/** + * Loger Utils + */ +public class LoggerUtil { + + /** + * Root logger + */ + public static final String ROOT_LOGGER = "ROOT"; + + /** + * set the log level of a logger + * + * @param loggerName logger name + * @param loggerLevel logger level + */ + public static String setLevel(String loggerName, String loggerLevel) { + if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) + throw new IllegalStateException("The SLF4J logger factory is not configured for logback"); + + final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + final ch.qos.logback.classic.Logger logger = context.getLogger(loggerName); + if (logger == null) + throw new IllegalArgumentException("no logger " + loggerName); + + logger.setLevel(ch.qos.logback.classic.Level.toLevel(loggerLevel)); + return logger.getLevel().toString(); + } +} -- cgit 1.2.3-korg