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