From 64f53ef14f5a9ea98208fd2b835bfb01fda9a5f9 Mon Sep 17 00:00:00 2001 From: mmis Date: Thu, 19 Jul 2018 13:21:08 +0100 Subject: Copy policy-endpoints from drools-pdp to common Removed policy-endpoints, and 3 classes from policy-core. Replaced refenences to the deleted classes with references to the corresponding classes in policy-common Issue-ID: POLICY-967 Change-Id: I547cde4894424b8f40b7ddd4e2342ebb729cb588 Signed-off-by: mmis --- .../policy/drools/controller/DroolsController.java | 371 +- .../drools/controller/DroolsControllerFactory.java | 924 +++-- .../controller/internal/MavenDroolsController.java | 2 +- .../controller/internal/NullDroolsController.java | 2 +- .../features/PolicyControllerFeatureAPI.java | 2 +- .../drools/persistence/FileSystemPersistence.java | 6 +- .../policy/drools/server/restful/RestManager.java | 3960 ++++++++++---------- .../java/org/onap/policy/drools/system/Main.java | 4 +- .../policy/drools/system/PolicyController.java | 146 +- .../onap/policy/drools/system/PolicyEngine.java | 2538 +++++++------ .../internal/AggregatedPolicyController.java | 1192 +++--- 11 files changed, 4515 insertions(+), 4632 deletions(-) (limited to 'policy-management/src/main/java') diff --git a/policy-management/src/main/java/org/onap/policy/drools/controller/DroolsController.java b/policy-management/src/main/java/org/onap/policy/drools/controller/DroolsController.java index bdb95e77..7f68930e 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/controller/DroolsController.java +++ b/policy-management/src/main/java/org/onap/policy/drools/controller/DroolsController.java @@ -23,194 +23,195 @@ package org.onap.policy.drools.controller; import java.util.List; import java.util.Map; +import org.onap.policy.common.capabilities.Lockable; +import org.onap.policy.common.capabilities.Startable; +import org.onap.policy.common.endpoints.event.comm.TopicSink; import org.onap.policy.drools.core.PolicyContainer; -import org.onap.policy.drools.event.comm.TopicSink; -import org.onap.policy.drools.properties.Lockable; -import org.onap.policy.drools.properties.Startable; import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration; /** - * Drools Controller is the abstractions that wraps the - * drools layer (policy-core) + * Drools Controller is the abstractions that wraps the drools layer (policy-core) */ -public interface DroolsController extends Startable, Lockable { - - /** - * No Group ID identifier - */ - public static final String NO_GROUP_ID = "NO-GROUP-ID"; - - /** - * No Artifact ID identifier - */ - public static final String NO_ARTIFACT_ID = "NO-ARTIFACT-ID"; - - /** - * No version identifier - */ - public static final String NO_VERSION = "NO-VERSION"; - - /** - * Factory to track and manage drools controllers - */ - public static final DroolsControllerFactory factory = - new IndexedDroolsControllerFactory(); - - /** - * get group id - * @return group id - */ - public String getGroupId(); - - /** - * get artifact id - * @return artifact id - */ - public String getArtifactId(); - - /** - * get version - * @return version - */ - public String getVersion(); - - /** - * return the policy session names - * - * @return policy session - */ - public List getSessionNames(); - - /** - * return the policy full session names - * - * @return policy session - */ - public List getCanonicalSessionNames(); - - /** - * offers an event to this controller for processing - * - * @param topic topic associated with the event - * @param event the event - * - * @return true if the operation was successful - */ - public boolean offer(String topic, String event); - - /** - * delivers "event" to "sink" - * - * @param sink destination - * @param event - * @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(TopicSink sink, Object event); - - /** - * - * @return the most recent received events - */ - public Object[] getRecentSourceEvents(); - - /** - * - * @return the most recent delivered events - */ - public String[] getRecentSinkEvents(); - - /** - * @return the underlying policy container - */ - public PolicyContainer getContainer(); - - /** - * Supports this encoder? - * - * @param encodedObject - * @return - */ - public boolean ownsCoder(Class coderClass, int modelHash); - - /** - * fetches a class from the model - * - * @param className the class to fetch - * @return the actual class object, or null if not found - */ - public Class fetchModelClass(String className); - - /** - * is this controller Smart? - */ - public boolean isBrained(); - - /** - * update the new version of the maven jar rules file - * - * @param newGroupId - new group id - * @param newArtifactId - new artifact id - * @param newVersion - new version - * @param decoderConfigurations - decoder configurations - * @param encoderConfigurations - encoder configurations - * - * @throws Exception from within drools libraries - * @throws LinkageError from within drools libraries - * @throws ArgumentException bad parameter passed in - */ - public void updateToVersion(String newGroupId, String newArtifactId, String newVersion, - List decoderConfigurations, - List encoderConfigurations) - throws LinkageError; - - /** - * gets the classnames of facts as well as the current count - * @param sessionName the session name - * @return map of class to count - */ - public Map factClassNames(String sessionName); - - /** - * gets the count of facts for a given session - * @param sessionName the session name - * @return the fact count - * @throws IllegalArgumentException - */ - public long factCount(String sessionName); - - /** - * gets all the facts of a given class for a given session - * - * @param sessionName the session identifier - * @param className the class type - * @param delete retract from drools the results of the query? - * @return the list of facts returned by the query - */ - public List facts(String sessionName, String className, boolean delete); - - /** - * gets the facts associated with a query for a give session for a given queried entity - * - * @param sessionName the session - * @param queryName the query identifier - * @param queriedEntity the queried entity - * @param delete retract from drools the results of the query? - * @param queryParams query parameters - * @return list of facts returned by the query - */ - public List factQuery(String sessionName, String queryName, String queriedEntity, - boolean delete, Object... queryParams); - - /** - * halts and permanently releases all resources - * @throws IllegalStateException - */ - public void halt(); +public interface DroolsController extends Startable, Lockable { + + /** + * No Group ID identifier + */ + public static final String NO_GROUP_ID = "NO-GROUP-ID"; + + /** + * No Artifact ID identifier + */ + public static final String NO_ARTIFACT_ID = "NO-ARTIFACT-ID"; + + /** + * No version identifier + */ + public static final String NO_VERSION = "NO-VERSION"; + + /** + * Factory to track and manage drools controllers + */ + public static final DroolsControllerFactory factory = new IndexedDroolsControllerFactory(); + + /** + * get group id + * + * @return group id + */ + public String getGroupId(); + + /** + * get artifact id + * + * @return artifact id + */ + public String getArtifactId(); + + /** + * get version + * + * @return version + */ + public String getVersion(); + + /** + * return the policy session names + * + * @return policy session + */ + public List getSessionNames(); + + /** + * return the policy full session names + * + * @return policy session + */ + public List getCanonicalSessionNames(); + + /** + * offers an event to this controller for processing + * + * @param topic topic associated with the event + * @param event the event + * + * @return true if the operation was successful + */ + public boolean offer(String topic, String event); + + /** + * delivers "event" to "sink" + * + * @param sink destination + * @param event + * @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(TopicSink sink, Object event); + + /** + * + * @return the most recent received events + */ + public Object[] getRecentSourceEvents(); + + /** + * + * @return the most recent delivered events + */ + public String[] getRecentSinkEvents(); + + /** + * @return the underlying policy container + */ + public PolicyContainer getContainer(); + + /** + * Supports this encoder? + * + * @param encodedObject + * @return + */ + public boolean ownsCoder(Class coderClass, int modelHash); + + /** + * fetches a class from the model + * + * @param className the class to fetch + * @return the actual class object, or null if not found + */ + public Class fetchModelClass(String className); + + /** + * is this controller Smart? + */ + public boolean isBrained(); + + /** + * update the new version of the maven jar rules file + * + * @param newGroupId - new group id + * @param newArtifactId - new artifact id + * @param newVersion - new version + * @param decoderConfigurations - decoder configurations + * @param encoderConfigurations - encoder configurations + * + * @throws Exception from within drools libraries + * @throws LinkageError from within drools libraries + * @throws ArgumentException bad parameter passed in + */ + public void updateToVersion(String newGroupId, String newArtifactId, String newVersion, + List decoderConfigurations, + List encoderConfigurations) throws LinkageError; + + /** + * gets the classnames of facts as well as the current count + * + * @param sessionName the session name + * @return map of class to count + */ + public Map factClassNames(String sessionName); + + /** + * gets the count of facts for a given session + * + * @param sessionName the session name + * @return the fact count + * @throws IllegalArgumentException + */ + public long factCount(String sessionName); + + /** + * gets all the facts of a given class for a given session + * + * @param sessionName the session identifier + * @param className the class type + * @param delete retract from drools the results of the query? + * @return the list of facts returned by the query + */ + public List facts(String sessionName, String className, boolean delete); + + /** + * gets the facts associated with a query for a give session for a given queried entity + * + * @param sessionName the session + * @param queryName the query identifier + * @param queriedEntity the queried entity + * @param delete retract from drools the results of the query? + * @param queryParams query parameters + * @return list of facts returned by the query + */ + public List factQuery(String sessionName, String queryName, String queriedEntity, boolean delete, + Object... queryParams); + + /** + * halts and permanently releases all resources + * + * @throws IllegalStateException + */ + public void halt(); } diff --git a/policy-management/src/main/java/org/onap/policy/drools/controller/DroolsControllerFactory.java b/policy-management/src/main/java/org/onap/policy/drools/controller/DroolsControllerFactory.java index 65c9f334..b3aaaa7f 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/controller/DroolsControllerFactory.java +++ b/policy-management/src/main/java/org/onap/policy/drools/controller/DroolsControllerFactory.java @@ -26,498 +26,472 @@ import java.util.HashMap; import java.util.List; import java.util.Properties; +import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties; import org.onap.policy.drools.controller.internal.MavenDroolsController; import org.onap.policy.drools.controller.internal.NullDroolsController; -import org.onap.policy.drools.event.comm.Topic; -import org.onap.policy.drools.event.comm.Topic.CommInfrastructure; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.onap.policy.drools.event.comm.TopicSource; -import org.onap.policy.drools.event.comm.TopicSink; -import org.onap.policy.drools.properties.PolicyProperties; +import org.onap.policy.common.endpoints.event.comm.Topic; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.common.endpoints.event.comm.TopicSource; +import org.onap.policy.drools.properties.DroolsProperties; import org.onap.policy.drools.protocol.coders.JsonProtocolFilter; import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration; import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomGsonCoder; import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomJacksonCoder; import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration.PotentialCoderFilter; import org.onap.policy.drools.utils.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * Drools Controller Factory to manage controller creation, destruction, - * and retrieval for management interfaces + * Drools Controller Factory to manage controller creation, destruction, and retrieval for + * management interfaces */ public interface DroolsControllerFactory { - - /** - * Constructs a Drools Controller based on properties - * - * @param properties properties containing initialization parameters - * @param eventSources list of event sources - * @param eventSinks list of event sinks - * - * @return the instantiated Drools Controller - * @throws IllegalArgumentException with invalid parameters - * @throws LinkageError Failure to link rules and models in Drools Libraries - */ - public DroolsController build(Properties properties, - List eventSources, - List eventSinks) - throws LinkageError; - - /** - * Explicit construction of a Drools Controller - * - * @param groupId maven group id of drools artifact - * @param artifactId maven artifact id of drools artifact - * @param version maven version id of drools artifact - * @param decoderConfigurations list of decoder configurations - * @param encoderConfigurations list of encoder configurations - * - * @return the instantiated Drools Controller - * @throws IllegalArgumentException with invalid parameters - * @throws LinkageError Failure to link rules and models in Drools Libraries - */ - public DroolsController build(String groupId, - String artifactId, - String version, - List decoderConfigurations, - List encoderConfigurations) - throws LinkageError; - - /** - * Releases the Drools Controller from operation - * - * @param controller the Drools Controller to shut down - */ - public void shutdown(DroolsController controller); - - /** - * Disables all Drools Controllers from operation - */ - public void shutdown(); - - /** - * Destroys and releases resources for a Drools Controller - * - * @param controller the Drools Controller to destroy - */ - public void destroy(DroolsController controller); - - /** - * Destroys all Drools Controllers - */ - public void destroy(); - - /** - * Gets the Drools Controller associated with the maven group - * and artifact id - * - * @param groupId maven group id of drools artifact - * @param artifactId maven artifact id of drools artifact - * @param version maven version id of drools artifact - * - * @return the Drools Controller - * @throws IllegalArgumentException with invalid parameters - */ - public DroolsController get(String groupId, - String artifactId, - String version); - - /** - * returns the current inventory of Drools Controllers - * - * @return a list of Drools Controllers - */ - public List inventory(); + + /** + * Constructs a Drools Controller based on properties + * + * @param properties properties containing initialization parameters + * @param eventSources list of event sources + * @param eventSinks list of event sinks + * + * @return the instantiated Drools Controller + * @throws IllegalArgumentException with invalid parameters + * @throws LinkageError Failure to link rules and models in Drools Libraries + */ + public DroolsController build(Properties properties, List eventSources, + List eventSinks) throws LinkageError; + + /** + * Explicit construction of a Drools Controller + * + * @param groupId maven group id of drools artifact + * @param artifactId maven artifact id of drools artifact + * @param version maven version id of drools artifact + * @param decoderConfigurations list of decoder configurations + * @param encoderConfigurations list of encoder configurations + * + * @return the instantiated Drools Controller + * @throws IllegalArgumentException with invalid parameters + * @throws LinkageError Failure to link rules and models in Drools Libraries + */ + public DroolsController build(String groupId, String artifactId, String version, + List decoderConfigurations, + List encoderConfigurations) throws LinkageError; + + /** + * Releases the Drools Controller from operation + * + * @param controller the Drools Controller to shut down + */ + public void shutdown(DroolsController controller); + + /** + * Disables all Drools Controllers from operation + */ + public void shutdown(); + + /** + * Destroys and releases resources for a Drools Controller + * + * @param controller the Drools Controller to destroy + */ + public void destroy(DroolsController controller); + + /** + * Destroys all Drools Controllers + */ + public void destroy(); + + /** + * Gets the Drools Controller associated with the maven group and artifact id + * + * @param groupId maven group id of drools artifact + * @param artifactId maven artifact id of drools artifact + * @param version maven version id of drools artifact + * + * @return the Drools Controller + * @throws IllegalArgumentException with invalid parameters + */ + public DroolsController get(String groupId, String artifactId, String version); + + /** + * returns the current inventory of Drools Controllers + * + * @return a list of Drools Controllers + */ + public List inventory(); } -/* ---------------- implementation -----------------*/ + +/* ---------------- implementation ----------------- */ /** - * Factory of Drools Controllers indexed by the Maven coordinates + * Factory of Drools Controllers indexed by the Maven coordinates */ class IndexedDroolsControllerFactory implements DroolsControllerFactory { - /** - * logger - */ - private static Logger logger = LoggerFactory.getLogger(MavenDroolsController.class); - - /** - * Policy Controller Name Index - */ - protected HashMap droolsControllers = new HashMap<>(); - - /** - * Null Drools Controller - */ - protected NullDroolsController nullDroolsController = new NullDroolsController(); - - - public IndexedDroolsControllerFactory() { - - /* Add a NULL controller which will always be present in the hash */ - - DroolsController controller = new NullDroolsController(); - String controllerId = controller.getGroupId() + ":" + controller.getArtifactId(); - - synchronized(this) { - droolsControllers.put(controllerId, controller); - } - } - - @Override - public DroolsController build(Properties properties, - List eventSources, - List eventSinks) - throws LinkageError { - - String groupId = properties.getProperty(PolicyProperties.RULES_GROUPID); - if (groupId == null || groupId.isEmpty()) - groupId = DroolsController.NO_GROUP_ID; - - String artifactId = properties.getProperty(PolicyProperties.RULES_ARTIFACTID); - if (artifactId == null || artifactId.isEmpty()) - artifactId = DroolsController.NO_ARTIFACT_ID; - - String version = properties.getProperty(PolicyProperties.RULES_VERSION); - if (version == null || version.isEmpty()) - version = DroolsController.NO_VERSION; - - List - topics2DecodedClasses2Filters = codersAndFilters(properties, eventSources); - - List - topics2EncodedClasses2Filters = codersAndFilters(properties, eventSinks); - - return this.build(groupId, artifactId, version, - topics2DecodedClasses2Filters, - topics2EncodedClasses2Filters); - } - - /** - * find out decoder classes and filters - * - * @param properties properties with information about decoders - * @param topicEntities topic sources - * @return list of topics, each with associated decoder classes, each - * with a list of associated filters - * @throws IllegalArgumentException invalid input data - */ - protected List codersAndFilters - (Properties properties, List topicEntities) { - - String propertyTopicEntityPrefix; - - List - topics2DecodedClasses2Filters = new ArrayList<>(); - - if (topicEntities == null || topicEntities.isEmpty()) - return topics2DecodedClasses2Filters; - - for (Topic topic: topicEntities) { - - /* source or sink ? ueb or dmaap? */ - boolean isSource = topic instanceof TopicSource; - CommInfrastructure commInfra = topic.getTopicCommInfrastructure(); - if (commInfra == CommInfrastructure.UEB) { - if (isSource) { - propertyTopicEntityPrefix = PolicyProperties.PROPERTY_UEB_SOURCE_TOPICS + "."; - } else { - propertyTopicEntityPrefix = PolicyProperties.PROPERTY_UEB_SINK_TOPICS + "."; - } - } else if (commInfra == CommInfrastructure.DMAAP) { - if (isSource) { - propertyTopicEntityPrefix = PolicyProperties.PROPERTY_DMAAP_SOURCE_TOPICS + "."; - } else { - propertyTopicEntityPrefix = PolicyProperties.PROPERTY_DMAAP_SINK_TOPICS + "."; - } - } else if (commInfra == CommInfrastructure.NOOP) { - if (!isSource) - propertyTopicEntityPrefix = PolicyProperties.PROPERTY_NOOP_SINK_TOPICS + "."; - else - continue; - } else { - throw new IllegalArgumentException("Invalid Communication Infrastructure: " + commInfra); - } - - // 1. first the topic - - String aTopic = topic.getTopic(); - - // 2. check if there is a custom decoder for this topic that the user prefers to use - // instead of the ones provided in the platform - - String customGson = properties.getProperty - (propertyTopicEntityPrefix + - aTopic + - PolicyProperties.PROPERTY_TOPIC_EVENTS_CUSTOM_MODEL_CODER_GSON_SUFFIX); - - CustomGsonCoder customGsonCoder = null; - if (customGson != null && !customGson.isEmpty()) { - try { - customGsonCoder = new CustomGsonCoder(customGson); - } catch (IllegalArgumentException e) { - logger.warn("{}: cannot create custom-gson-coder {} because of {}", - this, customGson, e.getMessage(), e); - } - } - - String customJackson = properties.getProperty - (propertyTopicEntityPrefix + - aTopic + - PolicyProperties.PROPERTY_TOPIC_EVENTS_CUSTOM_MODEL_CODER_JACKSON_SUFFIX); - - CustomJacksonCoder customJacksonCoder = null; - if (customJackson != null && !customJackson.isEmpty()) { - try { - customJacksonCoder = new CustomJacksonCoder(customJackson); - } catch (IllegalArgumentException e) { - logger.warn("{}: cannot create custom-jackson-coder {} because of {}", - this, customJackson, e.getMessage(), e); - } - } - - // 3. second the list of classes associated with each topic - - String eventClasses = - properties.getProperty(propertyTopicEntityPrefix + aTopic + PolicyProperties.PROPERTY_TOPIC_EVENTS_SUFFIX); - - if (eventClasses == null || eventClasses.isEmpty()) { - // TODO warn - continue; - } - - List classes2Filters = new ArrayList<>(); - - List aTopicClasses = - new ArrayList<>(Arrays.asList(eventClasses.split("\\s*,\\s*"))); - - for (String aClass: aTopicClasses) { - - - // 4. third, for each coder class, get the list of field filters - - String filter = properties.getProperty - (propertyTopicEntityPrefix + - aTopic + - PolicyProperties.PROPERTY_TOPIC_EVENTS_SUFFIX + - "." + aClass + - PolicyProperties.PROPERTY_TOPIC_EVENTS_FILTER_SUFFIX); - - List> filters = new ArrayList<>(); - - if (filter == null || filter.isEmpty()) { - // 4. topic -> class -> with no filters - - JsonProtocolFilter protocolFilter = JsonProtocolFilter.fromRawFilters(filters); - PotentialCoderFilter class2Filters = - new PotentialCoderFilter(aClass, protocolFilter); - classes2Filters.add(class2Filters); - continue; - } - - // There are filters associated with the applicability of - // this class for decoding. - List listOfFilters = - new ArrayList<>(Arrays.asList(filter.split("\\s*,\\s*"))); - - for (String nameValue: listOfFilters) { - String fieldName; - String regexValue; - - String[] nameValueSplit = nameValue.split("\\s*=\\s*"); - if (nameValueSplit.length <= 0 || nameValueSplit.length > 2) { - // TODO warn - // skip - continue; - } - - if (nameValueSplit.length == 2) { - fieldName = nameValueSplit[0]; - regexValue = nameValueSplit[1]; - } else if (nameValueSplit.length == 1) { - fieldName = nameValueSplit[0]; - regexValue = null; - } else { - // unreachable - continue; - } - - filters.add(new Pair(fieldName, regexValue)); - } - - JsonProtocolFilter protocolFilter = JsonProtocolFilter.fromRawFilters(filters); - PotentialCoderFilter class2Filters = - new PotentialCoderFilter(aClass, protocolFilter); - classes2Filters.add(class2Filters); - } - - TopicCoderFilterConfiguration topic2Classes2Filters = - new TopicCoderFilterConfiguration(aTopic,classes2Filters, customGsonCoder, customJacksonCoder); - topics2DecodedClasses2Filters.add(topic2Classes2Filters); - } - - return topics2DecodedClasses2Filters; - } - - @Override - public DroolsController build(String newGroupId, - String newArtifactId, - String newVersion, - List decoderConfigurations, - List encoderConfigurations) - throws LinkageError { - - if (newGroupId == null || newGroupId.isEmpty()) - throw new IllegalArgumentException("Missing maven group-id coordinate"); - - if (newArtifactId == null || newArtifactId.isEmpty()) - throw new IllegalArgumentException("Missing maven artifact-id coordinate"); - - if (newVersion == null || newVersion.isEmpty()) - throw new IllegalArgumentException("Missing maven version coordinate"); - - String controllerId = newGroupId + ":" + newArtifactId; - DroolsController controllerCopy = null; - synchronized (this) { - /* - * The Null Drools Controller for no maven coordinates is always here - * so when no coordinates present, this is the return point - * - * assert (controllerCopy instanceof NullDroolsController) - */ - if (droolsControllers.containsKey(controllerId)) { - controllerCopy = droolsControllers.get(controllerId); - if (controllerCopy.getVersion().equalsIgnoreCase(newVersion)) { - return controllerCopy; - } - } - } - - if (controllerCopy != null) { - /* - * a controller keyed by group id + artifact id exists - * but with different version => version upgrade/downgrade - */ - - controllerCopy.updateToVersion(newGroupId, newArtifactId, newVersion, - decoderConfigurations, encoderConfigurations); - - return controllerCopy; - } - - /* new drools controller */ - - DroolsController controller = new MavenDroolsController - (newGroupId, newArtifactId, newVersion, - decoderConfigurations, - encoderConfigurations); - - synchronized(this) { - droolsControllers.put(controllerId, controller); - } - - return controller; - } - - @Override - public void destroy(DroolsController controller) { - unmanage(controller); - controller.halt(); - } - - @Override - public void destroy() { - List controllers = this.inventory(); - for (DroolsController controller: controllers) { - controller.halt(); - } - - synchronized(this) { - this.droolsControllers.clear(); - } - } - - /** - * unmanage the drools controller - * - * @param controller - * @return - * @throws IllegalArgumentException - */ - protected void unmanage(DroolsController controller) { - if (controller == null) { - throw new IllegalArgumentException("No controller provided"); - } - - if (!controller.isBrained()) { - logger.info("Drools Controller is NOT OPERATIONAL - nothing to destroy"); - return; - } - - String controllerId = controller.getGroupId() + ":" + controller.getArtifactId(); - synchronized(this) { - if (!this.droolsControllers.containsKey(controllerId)) { - return; - } - - droolsControllers.remove(controllerId); - } - } - - @Override - public void shutdown(DroolsController controller) { - this.unmanage(controller); - controller.shutdown(); - } - - @Override - public void shutdown() { - List controllers = this.inventory(); - for (DroolsController controller: controllers) { - controller.shutdown(); - } - - synchronized(this) { - this.droolsControllers.clear(); - } - } - - @Override - public DroolsController get(String groupId, - String artifactId, - String version) { - - if (groupId == null || artifactId == null || - groupId.isEmpty() || artifactId.isEmpty()) { - throw new IllegalArgumentException("Missing maven coordinates: " + - groupId + ":" + artifactId); - } - - String controllerId = groupId + ":" + artifactId; - - synchronized(this) { - if (this.droolsControllers.containsKey(controllerId)) { - return droolsControllers.get(controllerId); - } else { - throw new IllegalStateException("DroolController for " + - controllerId + " not found"); - } - } - } - - @Override - public List inventory() { - return new ArrayList<>(this.droolsControllers.values()); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("IndexedDroolsControllerFactory [#droolsControllers=").append(droolsControllers.size()) - .append("]"); - return builder.toString(); - } - + /** + * logger + */ + private static Logger logger = LoggerFactory.getLogger(MavenDroolsController.class); + + /** + * Policy Controller Name Index + */ + protected HashMap droolsControllers = new HashMap<>(); + + /** + * Null Drools Controller + */ + protected NullDroolsController nullDroolsController = new NullDroolsController(); + + + public IndexedDroolsControllerFactory() { + + /* Add a NULL controller which will always be present in the hash */ + + DroolsController controller = new NullDroolsController(); + String controllerId = controller.getGroupId() + ":" + controller.getArtifactId(); + + synchronized (this) { + droolsControllers.put(controllerId, controller); + } + } + + @Override + public DroolsController build(Properties properties, List eventSources, + List eventSinks) throws LinkageError { + + String groupId = properties.getProperty(DroolsProperties.RULES_GROUPID); + if (groupId == null || groupId.isEmpty()) { + groupId = DroolsController.NO_GROUP_ID; + } + + String artifactId = properties.getProperty(DroolsProperties.RULES_ARTIFACTID); + if (artifactId == null || artifactId.isEmpty()) { + artifactId = DroolsController.NO_ARTIFACT_ID; + } + + String version = properties.getProperty(DroolsProperties.RULES_VERSION); + if (version == null || version.isEmpty()) { + version = DroolsController.NO_VERSION; + } + + List topics2DecodedClasses2Filters = codersAndFilters(properties, eventSources); + + List topics2EncodedClasses2Filters = codersAndFilters(properties, eventSinks); + + return this.build(groupId, artifactId, version, topics2DecodedClasses2Filters, topics2EncodedClasses2Filters); + } + + /** + * find out decoder classes and filters + * + * @param properties properties with information about decoders + * @param topicEntities topic sources + * @return list of topics, each with associated decoder classes, each with a list of associated + * filters + * @throws IllegalArgumentException invalid input data + */ + protected List codersAndFilters(Properties properties, + List topicEntities) { + + String propertyTopicEntityPrefix; + + List topics2DecodedClasses2Filters = new ArrayList<>(); + + if (topicEntities == null || topicEntities.isEmpty()) { + return topics2DecodedClasses2Filters; + } + + for (Topic topic : topicEntities) { + + /* source or sink ? ueb or dmaap? */ + boolean isSource = topic instanceof TopicSource; + CommInfrastructure commInfra = topic.getTopicCommInfrastructure(); + if (commInfra == CommInfrastructure.UEB) { + if (isSource) { + propertyTopicEntityPrefix = PolicyEndPointProperties.PROPERTY_UEB_SOURCE_TOPICS + "."; + } else { + propertyTopicEntityPrefix = PolicyEndPointProperties.PROPERTY_UEB_SINK_TOPICS + "."; + } + } else if (commInfra == CommInfrastructure.DMAAP) { + if (isSource) { + propertyTopicEntityPrefix = PolicyEndPointProperties.PROPERTY_DMAAP_SOURCE_TOPICS + "."; + } else { + propertyTopicEntityPrefix = PolicyEndPointProperties.PROPERTY_DMAAP_SINK_TOPICS + "."; + } + } else if (commInfra == CommInfrastructure.NOOP) { + if (!isSource) { + propertyTopicEntityPrefix = PolicyEndPointProperties.PROPERTY_NOOP_SINK_TOPICS + "."; + } else { + continue; + } + } else { + throw new IllegalArgumentException("Invalid Communication Infrastructure: " + commInfra); + } + + // 1. first the topic + + String aTopic = topic.getTopic(); + + // 2. check if there is a custom decoder for this topic that the user prefers to use + // instead of the ones provided in the platform + + String customGson = properties.getProperty(propertyTopicEntityPrefix + aTopic + + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_CUSTOM_MODEL_CODER_GSON_SUFFIX); + + CustomGsonCoder customGsonCoder = null; + if (customGson != null && !customGson.isEmpty()) { + try { + customGsonCoder = new CustomGsonCoder(customGson); + } catch (IllegalArgumentException e) { + logger.warn("{}: cannot create custom-gson-coder {} because of {}", this, customGson, + e.getMessage(), e); + } + } + + String customJackson = properties.getProperty(propertyTopicEntityPrefix + aTopic + + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_CUSTOM_MODEL_CODER_JACKSON_SUFFIX); + + CustomJacksonCoder customJacksonCoder = null; + if (customJackson != null && !customJackson.isEmpty()) { + try { + customJacksonCoder = new CustomJacksonCoder(customJackson); + } catch (IllegalArgumentException e) { + logger.warn("{}: cannot create custom-jackson-coder {} because of {}", this, customJackson, + e.getMessage(), e); + } + } + + // 3. second the list of classes associated with each topic + + String eventClasses = properties + .getProperty(propertyTopicEntityPrefix + aTopic + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_SUFFIX); + + if (eventClasses == null || eventClasses.isEmpty()) { + // TODO warn + continue; + } + + List classes2Filters = new ArrayList<>(); + + List aTopicClasses = new ArrayList<>(Arrays.asList(eventClasses.split("\\s*,\\s*"))); + + for (String aClass : aTopicClasses) { + + + // 4. third, for each coder class, get the list of field filters + + String filter = properties + .getProperty(propertyTopicEntityPrefix + aTopic + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_SUFFIX + + "." + aClass + PolicyEndPointProperties.PROPERTY_TOPIC_EVENTS_FILTER_SUFFIX); + + List> filters = new ArrayList<>(); + + if (filter == null || filter.isEmpty()) { + // 4. topic -> class -> with no filters + + JsonProtocolFilter protocolFilter = JsonProtocolFilter.fromRawFilters(filters); + PotentialCoderFilter class2Filters = new PotentialCoderFilter(aClass, protocolFilter); + classes2Filters.add(class2Filters); + continue; + } + + // There are filters associated with the applicability of + // this class for decoding. + List listOfFilters = new ArrayList<>(Arrays.asList(filter.split("\\s*,\\s*"))); + + for (String nameValue : listOfFilters) { + String fieldName; + String regexValue; + + String[] nameValueSplit = nameValue.split("\\s*=\\s*"); + if (nameValueSplit.length <= 0 || nameValueSplit.length > 2) { + // TODO warn + // skip + continue; + } + + if (nameValueSplit.length == 2) { + fieldName = nameValueSplit[0]; + regexValue = nameValueSplit[1]; + } else if (nameValueSplit.length == 1) { + fieldName = nameValueSplit[0]; + regexValue = null; + } else { + // unreachable + continue; + } + + filters.add(new Pair(fieldName, regexValue)); + } + + JsonProtocolFilter protocolFilter = JsonProtocolFilter.fromRawFilters(filters); + PotentialCoderFilter class2Filters = new PotentialCoderFilter(aClass, protocolFilter); + classes2Filters.add(class2Filters); + } + + TopicCoderFilterConfiguration topic2Classes2Filters = + new TopicCoderFilterConfiguration(aTopic, classes2Filters, customGsonCoder, customJacksonCoder); + topics2DecodedClasses2Filters.add(topic2Classes2Filters); + } + + return topics2DecodedClasses2Filters; + } + + @Override + public DroolsController build(String newGroupId, String newArtifactId, String newVersion, + List decoderConfigurations, + List encoderConfigurations) throws LinkageError { + + if (newGroupId == null || newGroupId.isEmpty()) { + throw new IllegalArgumentException("Missing maven group-id coordinate"); + } + + if (newArtifactId == null || newArtifactId.isEmpty()) { + throw new IllegalArgumentException("Missing maven artifact-id coordinate"); + } + + if (newVersion == null || newVersion.isEmpty()) { + throw new IllegalArgumentException("Missing maven version coordinate"); + } + + String controllerId = newGroupId + ":" + newArtifactId; + DroolsController controllerCopy = null; + synchronized (this) { + /* + * The Null Drools Controller for no maven coordinates is always here so when no + * coordinates present, this is the return point + * + * assert (controllerCopy instanceof NullDroolsController) + */ + if (droolsControllers.containsKey(controllerId)) { + controllerCopy = droolsControllers.get(controllerId); + if (controllerCopy.getVersion().equalsIgnoreCase(newVersion)) { + return controllerCopy; + } + } + } + + if (controllerCopy != null) { + /* + * a controller keyed by group id + artifact id exists but with different version => + * version upgrade/downgrade + */ + + controllerCopy.updateToVersion(newGroupId, newArtifactId, newVersion, decoderConfigurations, + encoderConfigurations); + + return controllerCopy; + } + + /* new drools controller */ + + DroolsController controller = new MavenDroolsController(newGroupId, newArtifactId, newVersion, + decoderConfigurations, encoderConfigurations); + + synchronized (this) { + droolsControllers.put(controllerId, controller); + } + + return controller; + } + + @Override + public void destroy(DroolsController controller) { + unmanage(controller); + controller.halt(); + } + + @Override + public void destroy() { + List controllers = this.inventory(); + for (DroolsController controller : controllers) { + controller.halt(); + } + + synchronized (this) { + this.droolsControllers.clear(); + } + } + + /** + * unmanage the drools controller + * + * @param controller + * @return + * @throws IllegalArgumentException + */ + protected void unmanage(DroolsController controller) { + if (controller == null) { + throw new IllegalArgumentException("No controller provided"); + } + + if (!controller.isBrained()) { + logger.info("Drools Controller is NOT OPERATIONAL - nothing to destroy"); + return; + } + + String controllerId = controller.getGroupId() + ":" + controller.getArtifactId(); + synchronized (this) { + if (!this.droolsControllers.containsKey(controllerId)) { + return; + } + + droolsControllers.remove(controllerId); + } + } + + @Override + public void shutdown(DroolsController controller) { + this.unmanage(controller); + controller.shutdown(); + } + + @Override + public void shutdown() { + List controllers = this.inventory(); + for (DroolsController controller : controllers) { + controller.shutdown(); + } + + synchronized (this) { + this.droolsControllers.clear(); + } + } + + @Override + public DroolsController get(String groupId, String artifactId, String version) { + + if (groupId == null || artifactId == null || groupId.isEmpty() || artifactId.isEmpty()) { + throw new IllegalArgumentException("Missing maven coordinates: " + groupId + ":" + artifactId); + } + + String controllerId = groupId + ":" + artifactId; + + synchronized (this) { + if (this.droolsControllers.containsKey(controllerId)) { + return droolsControllers.get(controllerId); + } else { + throw new IllegalStateException("DroolController for " + controllerId + " not found"); + } + } + } + + @Override + public List inventory() { + return new ArrayList<>(this.droolsControllers.values()); + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("IndexedDroolsControllerFactory [#droolsControllers=").append(droolsControllers.size()) + .append("]"); + return builder.toString(); + } + } diff --git a/policy-management/src/main/java/org/onap/policy/drools/controller/internal/MavenDroolsController.java b/policy-management/src/main/java/org/onap/policy/drools/controller/internal/MavenDroolsController.java index 526b7251..7b44817a 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/controller/internal/MavenDroolsController.java +++ b/policy-management/src/main/java/org/onap/policy/drools/controller/internal/MavenDroolsController.java @@ -39,7 +39,7 @@ import org.onap.policy.drools.controller.DroolsController; import org.onap.policy.drools.core.PolicyContainer; import org.onap.policy.drools.core.PolicySession; import org.onap.policy.drools.core.jmx.PdpJmx; -import org.onap.policy.drools.event.comm.TopicSink; +import org.onap.policy.common.endpoints.event.comm.TopicSink; import org.onap.policy.drools.features.DroolsControllerFeatureAPI; import org.onap.policy.drools.protocol.coders.EventProtocolCoder; import org.onap.policy.drools.protocol.coders.JsonProtocolFilter; diff --git a/policy-management/src/main/java/org/onap/policy/drools/controller/internal/NullDroolsController.java b/policy-management/src/main/java/org/onap/policy/drools/controller/internal/NullDroolsController.java index 245b0b58..31ac1008 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/controller/internal/NullDroolsController.java +++ b/policy-management/src/main/java/org/onap/policy/drools/controller/internal/NullDroolsController.java @@ -27,7 +27,7 @@ import java.util.Map; import org.onap.policy.drools.controller.DroolsController; import org.onap.policy.drools.core.PolicyContainer; -import org.onap.policy.drools.event.comm.TopicSink; +import org.onap.policy.common.endpoints.event.comm.TopicSink; import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration; /** diff --git a/policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureAPI.java b/policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureAPI.java index d4ebc232..94d1b15e 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureAPI.java +++ b/policy-management/src/main/java/org/onap/policy/drools/features/PolicyControllerFeatureAPI.java @@ -22,7 +22,7 @@ package org.onap.policy.drools.features; import java.util.Properties; -import org.onap.policy.drools.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; import org.onap.policy.drools.system.PolicyController; import org.onap.policy.drools.utils.OrderedService; import org.onap.policy.drools.utils.OrderedServiceImpl; 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 index 45c5c428..b1e49ec2 100644 --- 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 @@ -31,7 +31,7 @@ import java.util.Arrays; import java.util.List; import java.util.Properties; -import org.onap.policy.drools.properties.PolicyProperties; +import org.onap.policy.drools.properties.DroolsProperties; import org.onap.policy.drools.utils.PropertyUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -226,9 +226,9 @@ public class FileSystemPersistence implements SystemPersistence { try { final Properties controllerProperties = this.getControllerProperties(name); final String controllerName = - controllerProperties.getProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME); + controllerProperties.getProperty(DroolsProperties.PROPERTY_CONTROLLER_NAME); if (controllerName == null) { - controllerProperties.setProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME, name); + controllerProperties.setProperty(DroolsProperties.PROPERTY_CONTROLLER_NAME, name); } else if (!controllerName.equals(name)) { logger.error("{}: mismatch controller named {} with file name {}", this, controllerName, controllerFile.getName()); 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 15c97237..26bed5e4 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 @@ -20,6 +20,8 @@ package org.onap.policy.drools.server.restful; +import ch.qos.logback.classic.LoggerContext; + import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; @@ -43,18 +45,19 @@ import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; +import org.onap.policy.common.endpoints.event.comm.TopicEndpoint; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.common.endpoints.event.comm.TopicSource; +import org.onap.policy.common.endpoints.event.comm.bus.DmaapTopicSink; +import org.onap.policy.common.endpoints.event.comm.bus.DmaapTopicSource; +import org.onap.policy.common.endpoints.event.comm.bus.NoopTopicSink; +import org.onap.policy.common.endpoints.event.comm.bus.UebTopicSink; +import org.onap.policy.common.endpoints.event.comm.bus.UebTopicSource; +import org.onap.policy.common.endpoints.event.comm.impl.ProxyTopicEndpointManager; import org.onap.policy.drools.controller.DroolsController; -import org.onap.policy.drools.event.comm.TopicEndpoint; -import org.onap.policy.drools.event.comm.TopicSink; -import org.onap.policy.drools.event.comm.TopicSource; -import org.onap.policy.drools.event.comm.bus.DmaapTopicSink; -import org.onap.policy.drools.event.comm.bus.DmaapTopicSource; -import org.onap.policy.drools.event.comm.bus.NoopTopicSink; -import org.onap.policy.drools.event.comm.bus.UebTopicSink; -import org.onap.policy.drools.event.comm.bus.UebTopicSource; import org.onap.policy.drools.features.PolicyControllerFeatureAPI; import org.onap.policy.drools.features.PolicyEngineFeatureAPI; -import org.onap.policy.drools.properties.PolicyProperties; +import org.onap.policy.drools.properties.DroolsProperties; import org.onap.policy.drools.protocol.coders.EventProtocolCoder; import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters; import org.onap.policy.drools.protocol.coders.JsonProtocolFilter; @@ -68,7 +71,6 @@ import org.onap.policy.drools.utils.logging.LoggerUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import ch.qos.logback.classic.LoggerContext; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiParam; @@ -87,2076 +89,1926 @@ import io.swagger.annotations.Tag; @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) @Api -@SwaggerDefinition( - 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")}) +@SwaggerDefinition(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")}) 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 (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(); - } - - 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); - } - - 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); - } - - 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); - } - - 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) { - logger.trace("OK ", 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(); - } - - 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 { - 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(); - } - - 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(); - } - - 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 { - 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(); - } - - return Response.status(Response.Status.OK).entity(controller).build(); - } - - @GET - @Path("engine/controllers/{controller}/switches") - @ApiOperation(value = "Policy Controller Switches", - notes = "List of the Policy Controller Switches", responseContainer = "List") - public Response controllerSwitches() { - return Response.status(Response.Status.OK).entity(Arrays.asList(Switches.values())).build(); - } - - @PUT - @Path("engine/controllers/{controller}/switches/lock") - @ApiOperation(value = "Switches on the Policy Controller Lock Control", - notes = "This action on the switch locks the Policy Controller", - response = PolicyController.class) - @ApiResponses(value = { - @ApiResponse(code = 406, message = "The system is an administrative state that prevents " - + "this request to be fulfilled")}) - public Response controllerLock(@ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName) { - final PolicyController policyController = PolicyController.factory.get(controllerName); - final boolean success = policyController.lock(); - if (success) - return Response.status(Status.OK).entity(policyController).build(); - else - return Response.status(Status.NOT_ACCEPTABLE) - .entity(new Error("Controller " + controllerName + " cannot be locked")).build(); - } - - @DELETE - @Path("engine/controllers/{controller}/switches/lock") - @ApiOperation(value = "Switches off the Policy Controller Lock Control", - notes = "This action on the switch unlocks the Policy Controller", - response = PolicyController.class) - @ApiResponses(value = { - @ApiResponse(code = 406, message = "The system is an administrative state that prevents " - + "this request to be fulfilled")}) - public Response controllerUnlock(@ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName) { - final PolicyController policyController = PolicyController.factory.get(controllerName); - final boolean success = policyController.unlock(); - if (success) - return Response.status(Status.OK).entity(policyController).build(); - else - return Response.status(Status.NOT_ACCEPTABLE) - .entity(new Error("Controller " + controllerName + " cannot be unlocked")).build(); - } - - @GET - @Path("engine/controllers/{controller}/drools") - @ApiOperation(value = "Retrieves the Drools Controller subcomponent of the Policy Controller", - notes = "The Drools Controller provides an abstraction over the Drools subsystem", - response = DroolsController.class) - @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller cannot be found"), - @ApiResponse(code = 406, message = "The system is an administrative state that prevents " - + "this request to be fulfilled")}) - public Response drools(@ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName) { - try { - final DroolsController drools = this.getDroolsController(controllerName); - return Response.status(Response.Status.OK).entity(drools).build(); - } catch (final IllegalArgumentException e) { - logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, - e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND) - .entity(new Error(controllerName + " not found")).build(); - } catch (final IllegalStateException e) { - logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, - e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(controllerName + " not acceptable")).build(); - } - } - - @GET - @Path("engine/controllers/{controller}/drools/facts") - @ApiOperation(value = "Retrieves Facts Summary information for a given controller", - notes = "Provides the session names, and a count of fact object in the drools working memory", - responseContainer = "Map") - @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller cannot be found"), - @ApiResponse(code = 406, message = "The system is an administrative state that prevents " - + "this request to be fulfilled")}) - public Response droolsFacts(@ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName) { - try { - final Map sessionCounts = new HashMap<>(); - final DroolsController drools = this.getDroolsController(controllerName); - for (final String session : drools.getSessionNames()) { - sessionCounts.put(session, drools.factCount(session)); - } - return Response.status(Response.Status.OK).entity(sessionCounts).build(); - } catch (final IllegalArgumentException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, - e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND) - .entity(new Error(controllerName + " not found")).build(); - } catch (final IllegalStateException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, - e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(controllerName + " not acceptable")).build(); - } - } - - @GET - @Path("engine/controllers/{controller}/drools/facts/{session}") - @ApiOperation(value = "Retrieves Fact Types (classnames) for a given controller and its count", - notes = "The fact types are the classnames of the objects inserted in the drools working memory", - responseContainer = "Map") - @ApiResponses( - value = {@ApiResponse(code = 404, message = "The controller or session cannot be found"), - @ApiResponse(code = 406, message = "The system is an administrative state that prevents " - + "this request to be fulfilled")}) - public Response droolsFacts( - @ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName, - @ApiParam(value = "Drools Session Name", - required = true) @PathParam("session") String sessionName) { - try { - final DroolsController drools = this.getDroolsController(controllerName); - return Response.status(Response.Status.OK).entity(drools.factClassNames(sessionName)).build(); - } catch (final IllegalArgumentException e) { - logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, - e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND).entity(new Error("entity not found")) - .build(); - } catch (final IllegalStateException e) { - logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, - e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(controllerName + ":" + sessionName + " not acceptable")).build(); - } - } - - @GET - @Path("engine/controllers/{controller}/drools/facts/{session}/{factType}") - @ApiOperation( - value = "Retrieves fact objects of a given type in the drools working memory" - + "for a given controller and session", - notes = "The fact types are the classnames of the objects inserted in the drools working memory", - responseContainer = "List") - @ApiResponses(value = { - @ApiResponse(code = 404, message = "The controller, session, or fact type cannot be found"), - @ApiResponse(code = 406, message = "The system is an administrative state that prevents " - + "this request to be fulfilled")}) - public Response droolsFacts( - @ApiParam(value = "Fact count", - required = false) @DefaultValue("false") @QueryParam("count") boolean count, - @ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName, - @ApiParam(value = "Drools Session Name", - required = true) @PathParam("session") String sessionName, - @ApiParam(value = "Drools Fact Type", - required = true) @PathParam("factType") String factType) { - try { - final DroolsController drools = this.getDroolsController(controllerName); - final List facts = drools.facts(sessionName, factType, false); - if (!count) - return Response.status(Response.Status.OK).entity(facts).build(); - else - return Response.status(Response.Status.OK).entity(facts.size()).build(); - } catch (final IllegalArgumentException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, - e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND) - .entity(new Error(controllerName + ":" + sessionName + ":" + factType + " not found")) - .build(); - } catch (final IllegalStateException e) { - logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, - e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity( - new Error(controllerName + ":" + sessionName + ":" + factType + " not acceptable")) - .build(); - } - } - - @DELETE - @Path("engine/controllers/{controller}/drools/facts/{session}/{factType}") - @ApiOperation( - value = "Deletes all the fact objects of a given type from the drools working memory" - + "for a given controller and session. The objects retracted from the working " - + "memory are provided in the response.", - notes = "The fact types are the classnames of the objects inserted in the drools working memory", - responseContainer = "List") - @ApiResponses(value = { - @ApiResponse(code = 404, message = "The controller, session, or fact type, cannot be found"), - @ApiResponse(code = 406, - message = "The system is an administrative state that prevents " - + "this request to be fulfilled"), - @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) - public Response droolsFactsDelete( - @ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName, - @ApiParam(value = "Drools Session Name", - required = true) @PathParam("session") String sessionName, - @ApiParam(value = "Drools Fact Type", - required = true) @PathParam("factType") String factType) { - try { - final DroolsController drools = this.getDroolsController(controllerName); - final List facts = drools.facts(sessionName, factType, true); - return Response.status(Response.Status.OK).entity(facts).build(); - } catch (final IllegalArgumentException e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, factType {}, because of {}", - this, controllerName, sessionName, factType, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND) - .entity(new Error(controllerName + ":" + sessionName + ":" + factType + " not found")) - .build(); - } catch (final IllegalStateException e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, factType {}, because of {}", - this, controllerName, sessionName, factType, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity( - new Error(controllerName + ":" + sessionName + ":" + factType + " not acceptable")) - .build(); - } catch (final Exception e) { - logger.debug("{}: cannot get: drools-controller {}, session {}, factType {}, because of {}", - this, controllerName, sessionName, factType, e.getMessage(), e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(new Error(e.getMessage())).build(); - } - } - - @GET - @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}") - @ApiOperation( - value = "Gets all the fact objects returned by a DRL query with no parameters from the drools working memory" - + "for a given controller and session", - notes = "The DRL query must be defined in the DRL file", responseContainer = "List") - @ApiResponses(value = { - @ApiResponse(code = 404, - message = "The controller, session, or query information, cannot be found"), - @ApiResponse(code = 406, - message = "The system is an administrative state that prevents " - + "this request to be fulfilled"), - @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) - public Response droolsFacts( - @ApiParam(value = "Fact count", - required = false) @DefaultValue("false") @QueryParam("count") boolean count, - @ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName, - @ApiParam(value = "Drools Session Name", - required = true) @PathParam("session") String sessionName, - @ApiParam(value = "Query Name Present in DRL", - required = true) @PathParam("query") String queryName, - @ApiParam(value = "Query Identifier Present in the DRL Query", - required = true) @PathParam("queriedEntity") String queriedEntity) { - try { - final DroolsController drools = this.getDroolsController(controllerName); - final List facts = drools.factQuery(sessionName, queryName, queriedEntity, false); - if (!count) - return Response.status(Response.Status.OK).entity(facts).build(); - else - return Response.status(Response.Status.OK).entity(facts.size()).build(); - } catch (final IllegalArgumentException e) { - logger.debug( - "{}: cannot get: drools-controller {}, session {}, query {}, entity {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND) - .entity(new Error( - controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not found")) - .build(); - } catch (final IllegalStateException e) { - logger.debug( - "{}: cannot get: drools-controller {}, session {}, query {}, entity {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error( - controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not acceptable")) - .build(); - } catch (final Exception e) { - logger.debug( - "{}: cannot get: drools-controller {}, session {}, query {}, entity {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(new Error(e.getMessage())).build(); - } - } - - @POST - @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}") - @ApiOperation( - value = "Gets all the fact objects returned by a DRL query with parameters from the drools working memory" - + "for a given controller and session", - notes = "The DRL query with parameters must be defined in the DRL file", - responseContainer = "List") - @ApiResponses(value = { - @ApiResponse(code = 404, - message = "The controller, session, or query information, cannot be found"), - @ApiResponse(code = 406, - message = "The system is an administrative state that prevents " - + "this request to be fulfilled"), - @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) - public Response droolsFacts( - @ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName, - @ApiParam(value = "Drools Session Name", - required = true) @PathParam("session") String sessionName, - @ApiParam(value = "Query Name Present in DRL", - required = true) @PathParam("query") String queryName, - @ApiParam(value = "Query Identifier Present in the DRL Query", - required = true) @PathParam("queriedEntity") String queriedEntity, - @ApiParam(value = "Query Parameter Values to pass in the DRL Query", - required = false) List queryParameters) { - try { - final DroolsController drools = this.getDroolsController(controllerName); - List facts; - if (queryParameters == null || queryParameters.isEmpty()) - facts = drools.factQuery(sessionName, queryName, queriedEntity, false); - else - facts = drools.factQuery(sessionName, queryName, queriedEntity, false, - queryParameters.toArray()); - return Response.status(Response.Status.OK).entity(facts).build(); - } catch (final IllegalArgumentException e) { - logger.debug( - "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, queryParameters, - e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND) - .entity(new Error( - controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not found")) - .build(); - } catch (final IllegalStateException e) { - logger.debug( - "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, queryParameters, - e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error( - controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not acceptable")) - .build(); - } catch (final Exception e) { - logger.debug( - "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, queryParameters, - e.getMessage(), e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(new Error(e.getMessage())).build(); - } - } - - @DELETE - @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}") - @ApiOperation( - value = "Deletes all the fact objects returned by a DRL query with parameters from the drools working memory" - + "for a given controller and session", - notes = "The DRL query with parameters must be defined in the DRL file", - responseContainer = "List") - @ApiResponses(value = { - @ApiResponse(code = 404, - message = "The controller, session, or query information, cannot be found"), - @ApiResponse(code = 406, - message = "The system is an administrative state that prevents " - + "this request to be fulfilled"), - @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) - public Response droolsFactsDelete( - @ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName, - @ApiParam(value = "Drools Session Name", - required = true) @PathParam("session") String sessionName, - @ApiParam(value = "Query Name Present in DRL", - required = true) @PathParam("query") String queryName, - @ApiParam(value = "Query Identifier Present in the DRL Query", - required = true) @PathParam("queriedEntity") String queriedEntity, - @ApiParam(value = "Query Parameter Values to pass in the DRL Query", - required = false) List queryParameters) { - try { - final DroolsController drools = this.getDroolsController(controllerName); - List facts; - if (queryParameters == null || queryParameters.isEmpty()) - facts = drools.factQuery(sessionName, queryName, queriedEntity, true); - else - facts = drools.factQuery(sessionName, queryName, queriedEntity, true, - queryParameters.toArray()); - return Response.status(Response.Status.OK).entity(facts).build(); - } catch (final IllegalArgumentException e) { - logger.debug( - "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, queryParameters, - e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND) - .entity(new Error( - controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not found")) - .build(); - } catch (final IllegalStateException e) { - logger.debug( - "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, queryParameters, - e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error( - controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not acceptable")) - .build(); - } catch (final Exception e) { - logger.debug( - "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", - this, controllerName, sessionName, queryName, queriedEntity, queryParameters, - e.getMessage(), e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(new Error(e.getMessage())).build(); - } - } - - @POST - @Path("engine/controllers/tools/coders/decoders/filters/rules/{ruleName}") - @ApiOperation( - value = "Produces a Decoder Rule Filter in a format that the Policy Controller can understand", - notes = "The result can be used with other APIs to attach a filter to a decoder") - public Response rules( - @ApiParam(value = "Negate regex?", - required = true) @DefaultValue("false") @QueryParam("negate") boolean negate, - @ApiParam(value = "Rule Name", required = true) @PathParam("ruleName") String name, - @ApiParam(value = "Regex expression", required = true) String regex) { - String literalRegex = Pattern.quote(regex); - if (negate) - literalRegex = "^(?!" + literalRegex + "$).*"; - - return Response.status(Status.OK).entity(new JsonProtocolFilter.FilterRule(name, literalRegex)) - .build(); - } - - @GET - @Path("engine/controllers/{controller}/decoders") - @ApiOperation(value = "Gets all the decoders used by a controller", - notes = "A Policy Controller uses decoders to deserialize incoming network messages from " - + "subscribed network topics into specific (fact) objects. " - + "The deserialized (fact) object will typically be inserted in the drools working " - + " memory of the controlled drools application.", - responseContainer = "List", response = ProtocolCoderToolset.class) - @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller cannot be found"), - @ApiResponse(code = 406, message = "The system is an administrative state that prevents " - + "this request to be fulfilled")}) - public Response decoders(@ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName) { - try { - final DroolsController drools = this.getDroolsController(controllerName); - final List decoders = - EventProtocolCoder.manager.getDecoders(drools.getGroupId(), drools.getArtifactId()); - return Response.status(Response.Status.OK).entity(decoders).build(); - } catch (final IllegalArgumentException e) { - logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, - controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND) - .entity(new Error(controllerName + " not found")).build(); - } catch (final IllegalStateException e) { - logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, - controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(controllerName + " not acceptable")).build(); - } - } - - @GET - @Path("engine/controllers/{controller}/decoders/filters") - @ApiOperation(value = "Gets all the filters used by a controller", - notes = "A Policy Controller uses decoders to deserialize incoming network messages from " - + "subscribed network topics into specific (fact) objects. " - + "The deserialized (fact) object will typically be inserted in the drools working " - + " memory of the controlled drools application." - + "Acceptance filters are used to filter out undesired network messages for the given controller", - responseContainer = "List", response = CoderFilters.class) - @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller cannot be found"), - @ApiResponse(code = 406, message = "The system is an administrative state that prevents " - + "this request to be fulfilled")}) - public Response decoderFilters(@ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName) { - try { - final DroolsController drools = this.getDroolsController(controllerName); - final List filters = - EventProtocolCoder.manager.getDecoderFilters(drools.getGroupId(), drools.getArtifactId()); - return Response.status(Response.Status.OK).entity(filters).build(); - } catch (final IllegalArgumentException e) { - logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, - controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND) - .entity(new Error(controllerName + " not found")).build(); - } catch (final IllegalStateException e) { - logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, - controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(controllerName + " not acceptable")).build(); - } - } - - @GET - @Path("engine/controllers/{controller}/decoders/{topic}") - @ApiOperation(value = "Gets all the decoders in use by a controller for a networked topic", - notes = "A Policy Controller uses decoders to deserialize incoming network messages from " - + "subscribed network topics into specific (fact) objects. " - + "The deserialized (fact) object will typically be inserted in the drools working " - + " memory of the controlled drools application.", - responseContainer = "List", response = ProtocolCoderToolset.class) - @ApiResponses( - value = {@ApiResponse(code = 404, message = "The controller or topic cannot be found"), - @ApiResponse(code = 406, message = "The system is an administrative state that prevents " - + "this request to be fulfilled")}) - public Response decoder( - @ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName, - @ApiParam(value = "Networked Topic Name", required = true) @PathParam("topic") String topic) { - try { - final DroolsController drools = this.getDroolsController(controllerName); - final ProtocolCoderToolset decoder = EventProtocolCoder.manager - .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); - return Response.status(Response.Status.OK).entity(decoder).build(); - } catch (final IllegalArgumentException e) { - logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, - controllerName, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND) - .entity(new Error(controllerName + ":" + topic + " not found")).build(); - } catch (final IllegalStateException e) { - logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, - controllerName, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(controllerName + ":" + topic + " not acceptable")).build(); - } - } - - @GET - @Path("engine/controllers/{controller}/decoders/{topic}/filters") - @ApiOperation( - value = "Gets all filters attached to decoders for a given networked topic in use by a controller", - notes = "A Policy Controller uses decoders to deserialize incoming network messages from " - + "subscribed network topics into specific (fact) objects. " - + "The deserialized (fact) object will typically be inserted in the drools working " - + " memory of the controlled drools application." - + "Acceptance filters are used to filter out undesired network messages for the given controller", - responseContainer = "List", response = CoderFilters.class) - @ApiResponses( - value = {@ApiResponse(code = 404, message = "The controller or topic cannot be found"), - @ApiResponse(code = 406, message = "The system is an administrative state that prevents " - + "this request to be fulfilled")}) - public Response decoderFilter( - @ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName, - @ApiParam(value = "Networked Topic Name", required = true) @PathParam("topic") String topic) { - try { - final DroolsController drools = this.getDroolsController(controllerName); - final ProtocolCoderToolset decoder = EventProtocolCoder.manager - .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); - if (decoder == null) - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(topic + " does not exist")).build(); - else - return Response.status(Response.Status.OK).entity(decoder.getCoders()).build(); - } catch (final IllegalArgumentException e) { - logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, - controllerName, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND) - .entity(new Error(controllerName + ":" + topic + " not found")).build(); - } catch (final IllegalStateException e) { - logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, - controllerName, topic, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(controllerName + ":" + topic + " not acceptable")).build(); - } - } - - @GET - @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}") - @ApiOperation( - value = "Gets all filters attached to decoders for a given subscribed networked topic " - + "and fact type", - notes = "Decoders are associated with networked topics. A Policy Controller manages " - + "multiple topics and therefore its attached decoders. " - + "A Policy Controller uses filters to further specify the fact mapping. " - + "Filters are applied on a per fact type (classname).", - responseContainer = "List", response = CoderFilters.class) - @ApiResponses(value = { - @ApiResponse(code = 404, message = "The controller, topic, or fact type cannot be found"), - @ApiResponse(code = 406, message = "The system is an administrative state that prevents " - + "this request to be fulfilled")}) - public Response decoderFilter( - @ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName, - @ApiParam(value = "Networked Topic Name", required = true) @PathParam("topic") String topic, - @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass) { - try { - final DroolsController drools = this.getDroolsController(controllerName); - final ProtocolCoderToolset decoder = EventProtocolCoder.manager - .getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); - final CoderFilters filters = decoder.getCoder(factClass); - if (filters == null) - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(topic + ":" + factClass + " does not exist")).build(); - else - return Response.status(Response.Status.OK).entity(filters).build(); - } catch (final IllegalArgumentException e) { - logger.debug( - "{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}", - this, controllerName, topic, factClass, e.getMessage(), e); - return Response.status(Response.Status.NOT_FOUND) - .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not found")).build(); - } catch (final IllegalStateException e) { - logger.debug( - "{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}", - this, controllerName, topic, factClass, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not acceptable")) - .build(); - } - } - - @PUT - @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}") - @ApiOperation( - value = "Attaches filters to the decoder for a given networked topic " + "and fact type", - notes = "Decoders are associated with networked topics. A Policy Controller manages " - + "multiple topics and therefore its attached decoders. " - + "A Policy Controller uses filters to further specify the fact mapping. " - + "Filters are applied on a per fact type (classname).", - responseContainer = "List", response = CoderFilters.class) - @ApiResponses(value = { - @ApiResponse(code = 404, - message = "The controller, topic, fact type, cannot be found, " - + "or a filter has not been provided"), - @ApiResponse(code = 406, message = "The system is an administrative state that prevents " - + "this request to be fulfilled")}) - public Response decoderFilter( - @ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName, - @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic, - @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass, - @ApiParam(value = "Configuration Filter", required = true) JsonProtocolFilter configFilters) { - - if (configFilters == null) { - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error("Configuration Filters not provided")).build(); - } - - 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(); - } - - final CodingResult result = new CodingResult(); - result.setDecoding(false); - result.setEncoding(false); - result.setJsonEncoding(null); - - Object event; - try { - event = EventProtocolCoder.manager.decode(policyController.getDrools().getGroupId(), - policyController.getDrools().getArtifactId(), topic, json); - result.setDecoding(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(); - } - - try { - result.setJsonEncoding(EventProtocolCoder.manager.encode(topic, event)); - result.setEncoding(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); - } - - return Response.status(Response.Status.OK).entity(result).build(); - } - - @GET - @Path("engine/controllers/{controller}/encoders") - @ApiOperation(value = "Retrieves the encoder filters of a controller", - notes = "The encoders serializes a fact object, typically for network transmission", - responseContainer = "List", response = CoderFilters.class) - @ApiResponses(value = {@ApiResponse(code = 400, message = "Bad input has been provided"), - @ApiResponse(code = 406, message = "The system is an administrative state that prevents " - + "this request to be fulfilled")}) - public Response encoderFilters(@ApiParam(value = "Policy Controller Name", - required = true) @PathParam("controller") String controllerName) { - List encoders; - try { - final PolicyController controller = PolicyController.factory.get(controllerName); - final DroolsController drools = controller.getDrools(); - encoders = - EventProtocolCoder.manager.getEncoderFilters(drools.getGroupId(), drools.getArtifactId()); - } catch (final IllegalArgumentException e) { - logger.debug("{}: cannot get encoder filters for policy-controller {} because of {}", this, - controllerName, e.getMessage(), e); - return Response.status(Response.Status.BAD_REQUEST) - .entity(new Error(controllerName + " not found: " + e.getMessage())).build(); - } catch (final IllegalStateException e) { - logger.debug("{}: cannot get encoder filters for policy-controller {} because of {}", this, - controllerName, e.getMessage(), e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(controllerName + " is not accepting the request")).build(); - } - - 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 = UebTopicSink.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/sinks/noop") - @ApiOperation(value = "Retrieves the NOOP managed topic sinks", - notes = "NOOP Topic Sinks Agregation", responseContainer = "List", - response = NoopTopicSink.class) - public Response noopSinks() { - return Response.status(Response.Status.OK).entity(TopicEndpoint.manager.getNoopTopicSinks()) - .build(); - } - - @GET - @Path("engine/topics/sinks/noop/{topic}") - @ApiOperation(value = "Retrieves a NOOP managed topic sink", - notes = "NOOP is an dev/null Network Communicaton Sink", response = NoopTopicSink.class) - public Response noopSinkTopic( - @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic) { - return Response.status(Response.Status.OK).entity(TopicEndpoint.manager.getNoopTopicSink(topic)) - .build(); - } - - @GET - @Path("engine/topics/sinks/noop/{topic}/events") - @ApiOperation(value = "Retrieves the latest events send through a NOOP topic", - notes = "NOOP is an dev/null Network Communicaton Sink", responseContainer = "List") - public Response noopSinkEvents(@PathParam("topic") String topic) { - return Response.status(Status.OK) - .entity(Arrays.asList(TopicEndpoint.manager.getNoopTopicSink(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(makeTopicOperError(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(makeTopicOperError(topic)).build(); - } - - private Error makeTopicOperError(String topic) { - return new Error("cannot perform operation on " + topic); - } - - @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(makeTopicOperError(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(makeTopicOperError(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) { - logNoUebEncoder(topic, e); - return Response.status(Response.Status.NOT_FOUND).entity(new Error(topic + " not found")) - .build(); - } catch (final IllegalStateException e) { - logNoUebEncoder(topic, e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(topic + " not acceptable due to current state")).build(); - } catch (final Exception e) { - logNoUebEncoder(topic, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(new Error(e.getMessage())).build(); - } - } - - private void logNoUebEncoder(String topic, Exception ex) { - logger.debug("{}: cannot offer for encoder ueb topic for {} because of {}", this, topic, - ex.getMessage(), ex); - } - - @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) { - logNoDmaapEncoder(topic, e); - return Response.status(Response.Status.NOT_FOUND).entity(new Error(topic + " not found")) - .build(); - } catch (final IllegalStateException e) { - logNoDmaapEncoder(topic, e); - return Response.status(Response.Status.NOT_ACCEPTABLE) - .entity(new Error(topic + " not acceptable due to current state")).build(); - } catch (final Exception e) { - logNoDmaapEncoder(topic, e); - return Response.status(Response.Status.INTERNAL_SERVER_ERROR) - .entity(new Error(e.getMessage())).build(); - } - } - - private void logNoDmaapEncoder(String topic, Exception ex) { - logger.debug("{}: cannot offer for encoder dmaap topic for {} because of {}", this, topic, - ex.getMessage(), ex); - } - - @GET - @Path("engine/tools/uuid") - @ApiOperation(value = "Produces an UUID", notes = "UUID generation utility") - @Produces(MediaType.TEXT_PLAIN) - public Response uuid() { - return Response.status(Status.OK).entity(UUID.randomUUID().toString()).build(); - } - - @GET - @Path("engine/tools/loggers") - @ApiOperation(value = "all active loggers", responseContainer = "List") - @ApiResponses(value = {@ApiResponse(code = 500, message = "logging misconfiguration")}) - public Response loggers() { - final List names = new ArrayList<>(); - if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) { - logger.warn("The SLF4J logger factory is not configured for logback"); - return Response.status(Status.INTERNAL_SERVER_ERROR).entity(names).build(); - } - - final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); - for (final Logger lgr : context.getLoggerList()) { - names.add(lgr.getName()); - } - - 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(); - } - - final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); - final ch.qos.logback.classic.Logger lgr = context.getLogger(loggerName); - if (lgr == null) { - return Response.status(Status.NOT_FOUND).build(); - } - - final String loggerLevel = (lgr.getLevel() != null) ? lgr.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 { /** - * serialized output + * 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(); + } - private String jsonEncoding; - /** - * encoding result - */ + @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(); + } + + return Response.status(Response.Status.OK).entity(PolicyEngine.manager).build(); + } - private Boolean encoding; + @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(); + } - /** - * decoding result - */ - private Boolean decoding; + @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); + } + + 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); + } + + 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); + } + + 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(DroolsProperties.PROPERTY_CONTROLLER_NAME); + if (controllerName == null || controllerName.isEmpty()) { + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error( + "Configuration must have an entry for " + DroolsProperties.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) { + logger.trace("OK ", 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(); + } + + try { + controller = PolicyEngine.manager + .createPolicyController(config.getProperty(DroolsProperties.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 { + 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(); + } + + 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(); + } + + 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 { + 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(); + } + + return Response.status(Response.Status.OK).entity(controller).build(); + } + + @GET + @Path("engine/controllers/{controller}/switches") + @ApiOperation(value = "Policy Controller Switches", notes = "List of the Policy Controller Switches", + responseContainer = "List") + public Response controllerSwitches() { + return Response.status(Response.Status.OK).entity(Arrays.asList(Switches.values())).build(); + } + + @PUT + @Path("engine/controllers/{controller}/switches/lock") + @ApiOperation(value = "Switches on the Policy Controller Lock Control", + notes = "This action on the switch locks the Policy Controller", response = PolicyController.class) + @ApiResponses(value = {@ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled")}) + public Response controllerLock(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + final PolicyController policyController = PolicyController.factory.get(controllerName); + final boolean success = policyController.lock(); + if (success) { + return Response.status(Status.OK).entity(policyController).build(); + } else { + return Response.status(Status.NOT_ACCEPTABLE) + .entity(new Error("Controller " + controllerName + " cannot be locked")).build(); + } + } + + @DELETE + @Path("engine/controllers/{controller}/switches/lock") + @ApiOperation(value = "Switches off the Policy Controller Lock Control", + notes = "This action on the switch unlocks the Policy Controller", response = PolicyController.class) + @ApiResponses(value = {@ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled")}) + public Response controllerUnlock(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + final PolicyController policyController = PolicyController.factory.get(controllerName); + final boolean success = policyController.unlock(); + if (success) { + return Response.status(Status.OK).entity(policyController).build(); + } else { + return Response.status(Status.NOT_ACCEPTABLE) + .entity(new Error("Controller " + controllerName + " cannot be unlocked")).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/drools") + @ApiOperation(value = "Retrieves the Drools Controller subcomponent of the Policy Controller", + notes = "The Drools Controller provides an abstraction over the Drools subsystem", + response = DroolsController.class) + @ApiResponses( + value = {@ApiResponse(code = 404, message = "The controller cannot be found"), @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled")}) + public Response drools(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + return Response.status(Response.Status.OK).entity(drools).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND).entity(new Error(controllerName + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error(controllerName + " not acceptable")) + .build(); + } + } + + @GET + @Path("engine/controllers/{controller}/drools/facts") + @ApiOperation(value = "Retrieves Facts Summary information for a given controller", + notes = "Provides the session names, and a count of fact object in the drools working memory", + responseContainer = "Map") + @ApiResponses( + value = {@ApiResponse(code = 404, message = "The controller cannot be found"), @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled")}) + public Response droolsFacts(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + try { + final Map sessionCounts = new HashMap<>(); + final DroolsController drools = this.getDroolsController(controllerName); + for (final String session : drools.getSessionNames()) { + sessionCounts.put(session, drools.factCount(session)); + } + return Response.status(Response.Status.OK).entity(sessionCounts).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND).entity(new Error(controllerName + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error(controllerName + " not acceptable")) + .build(); + } + } + + @GET + @Path("engine/controllers/{controller}/drools/facts/{session}") + @ApiOperation(value = "Retrieves Fact Types (classnames) for a given controller and its count", + notes = "The fact types are the classnames of the objects inserted in the drools working memory", + responseContainer = "Map") + @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller or session cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled")}) + public Response droolsFacts( + @ApiParam(value = "Policy Controller Name", required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Drools Session Name", required = true) @PathParam("session") String sessionName) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + return Response.status(Response.Status.OK).entity(drools.factClassNames(sessionName)).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND).entity(new Error("entity not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get drools-controller {} because of {}", this, controllerName, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + sessionName + " not acceptable")).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/drools/facts/{session}/{factType}") + @ApiOperation( + value = "Retrieves fact objects of a given type in the drools working memory" + + "for a given controller and session", + notes = "The fact types are the classnames of the objects inserted in the drools working memory", + responseContainer = "List") + @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller, session, or fact type cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled")}) + public Response droolsFacts( + @ApiParam(value = "Fact count", required = false) @DefaultValue("false") @QueryParam("count") boolean count, + @ApiParam(value = "Policy Controller Name", required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Drools Session Name", required = true) @PathParam("session") String sessionName, + @ApiParam(value = "Drools Fact Type", required = true) @PathParam("factType") String factType) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final List facts = drools.facts(sessionName, factType, false); + if (!count) { + return Response.status(Response.Status.OK).entity(facts).build(); + } else { + return Response.status(Response.Status.OK).entity(facts.size()).build(); + } + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + sessionName + ":" + factType + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get policy-controller {} because of {}", this, controllerName, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + sessionName + ":" + factType + " not acceptable")).build(); + } + } + + @DELETE + @Path("engine/controllers/{controller}/drools/facts/{session}/{factType}") + @ApiOperation( + value = "Deletes all the fact objects of a given type from the drools working memory" + + "for a given controller and session. The objects retracted from the working " + + "memory are provided in the response.", + notes = "The fact types are the classnames of the objects inserted in the drools working memory", + responseContainer = "List") + @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller, session, or fact type, cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled"), + @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) + public Response droolsFactsDelete( + @ApiParam(value = "Policy Controller Name", required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Drools Session Name", required = true) @PathParam("session") String sessionName, + @ApiParam(value = "Drools Fact Type", required = true) @PathParam("factType") String factType) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final List facts = drools.facts(sessionName, factType, true); + return Response.status(Response.Status.OK).entity(facts).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get: drools-controller {}, session {}, factType {}, because of {}", this, + controllerName, sessionName, factType, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + sessionName + ":" + factType + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get: drools-controller {}, session {}, factType {}, because of {}", this, + controllerName, sessionName, factType, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + sessionName + ":" + factType + " not acceptable")).build(); + } catch (final Exception e) { + logger.debug("{}: cannot get: drools-controller {}, session {}, factType {}, because of {}", this, + controllerName, sessionName, factType, e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new Error(e.getMessage())).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}") + @ApiOperation( + value = "Gets all the fact objects returned by a DRL query with no parameters from the drools working memory" + + "for a given controller and session", + notes = "The DRL query must be defined in the DRL file", responseContainer = "List") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "The controller, session, or query information, cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled"), + @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) + public Response droolsFacts( + @ApiParam(value = "Fact count", required = false) @DefaultValue("false") @QueryParam("count") boolean count, + @ApiParam(value = "Policy Controller Name", required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Drools Session Name", required = true) @PathParam("session") String sessionName, + @ApiParam(value = "Query Name Present in DRL", required = true) @PathParam("query") String queryName, + @ApiParam(value = "Query Identifier Present in the DRL Query", + required = true) @PathParam("queriedEntity") String queriedEntity) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final List facts = drools.factQuery(sessionName, queryName, queriedEntity, false); + if (!count) { + return Response.status(Response.Status.OK).entity(facts).build(); + } else { + return Response.status(Response.Status.OK).entity(facts.size()).build(); + } + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get: drools-controller {}, session {}, query {}, entity {} because of {}", this, + controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error( + controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not found")) + .build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get: drools-controller {}, session {}, query {}, entity {} because of {}", this, + controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error( + controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not acceptable")) + .build(); + } catch (final Exception e) { + logger.debug("{}: cannot get: drools-controller {}, session {}, query {}, entity {} because of {}", this, + controllerName, sessionName, queryName, queriedEntity, e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new Error(e.getMessage())).build(); + } + } + + @POST + @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}") + @ApiOperation( + value = "Gets all the fact objects returned by a DRL query with parameters from the drools working memory" + + "for a given controller and session", + notes = "The DRL query with parameters must be defined in the DRL file", responseContainer = "List") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "The controller, session, or query information, cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled"), + @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) + public Response droolsFacts( + @ApiParam(value = "Policy Controller Name", required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Drools Session Name", required = true) @PathParam("session") String sessionName, + @ApiParam(value = "Query Name Present in DRL", required = true) @PathParam("query") String queryName, + @ApiParam(value = "Query Identifier Present in the DRL Query", + required = true) @PathParam("queriedEntity") String queriedEntity, + @ApiParam(value = "Query Parameter Values to pass in the DRL Query", + required = false) List queryParameters) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + List facts; + if (queryParameters == null || queryParameters.isEmpty()) { + facts = drools.factQuery(sessionName, queryName, queriedEntity, false); + } else { + facts = drools.factQuery(sessionName, queryName, queriedEntity, false, queryParameters.toArray()); + } + return Response.status(Response.Status.OK).entity(facts).build(); + } catch (final IllegalArgumentException e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, queryParameters, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error( + controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not found")) + .build(); + } catch (final IllegalStateException e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, queryParameters, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error( + controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not acceptable")) + .build(); + } catch (final Exception e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, queryParameters, e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new Error(e.getMessage())).build(); + } + } + + @DELETE + @Path("engine/controllers/{controller}/drools/facts/{session}/{query}/{queriedEntity}") + @ApiOperation( + value = "Deletes all the fact objects returned by a DRL query with parameters from the drools working memory" + + "for a given controller and session", + notes = "The DRL query with parameters must be defined in the DRL file", responseContainer = "List") + @ApiResponses(value = { + @ApiResponse(code = 404, message = "The controller, session, or query information, cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled"), + @ApiResponse(code = 500, message = "A server error has occurred processing this request")}) + public Response droolsFactsDelete( + @ApiParam(value = "Policy Controller Name", required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Drools Session Name", required = true) @PathParam("session") String sessionName, + @ApiParam(value = "Query Name Present in DRL", required = true) @PathParam("query") String queryName, + @ApiParam(value = "Query Identifier Present in the DRL Query", + required = true) @PathParam("queriedEntity") String queriedEntity, + @ApiParam(value = "Query Parameter Values to pass in the DRL Query", + required = false) List queryParameters) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + List facts; + if (queryParameters == null || queryParameters.isEmpty()) { + facts = drools.factQuery(sessionName, queryName, queriedEntity, true); + } else { + facts = drools.factQuery(sessionName, queryName, queriedEntity, true, queryParameters.toArray()); + } + return Response.status(Response.Status.OK).entity(facts).build(); + } catch (final IllegalArgumentException e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, queryParameters, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error( + controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not found")) + .build(); + } catch (final IllegalStateException e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, queryParameters, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error( + controllerName + ":" + sessionName + ":" + queryName + queriedEntity + " not acceptable")) + .build(); + } catch (final Exception e) { + logger.debug( + "{}: cannot get: drools-controller {}, session {}, query {}, entity {}, params {} because of {}", + this, controllerName, sessionName, queryName, queriedEntity, queryParameters, e.getMessage(), e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new Error(e.getMessage())).build(); + } + } + + @POST + @Path("engine/controllers/tools/coders/decoders/filters/rules/{ruleName}") + @ApiOperation(value = "Produces a Decoder Rule Filter in a format that the Policy Controller can understand", + notes = "The result can be used with other APIs to attach a filter to a decoder") + public Response rules( + @ApiParam(value = "Negate regex?", + required = true) @DefaultValue("false") @QueryParam("negate") boolean negate, + @ApiParam(value = "Rule Name", required = true) @PathParam("ruleName") String name, + @ApiParam(value = "Regex expression", required = true) String regex) { + String literalRegex = Pattern.quote(regex); + if (negate) { + literalRegex = "^(?!" + literalRegex + "$).*"; + } + + return Response.status(Status.OK).entity(new JsonProtocolFilter.FilterRule(name, literalRegex)).build(); + } + + @GET + @Path("engine/controllers/{controller}/decoders") + @ApiOperation(value = "Gets all the decoders used by a controller", + notes = "A Policy Controller uses decoders to deserialize incoming network messages from " + + "subscribed network topics into specific (fact) objects. " + + "The deserialized (fact) object will typically be inserted in the drools working " + + " memory of the controlled drools application.", + responseContainer = "List", response = ProtocolCoderToolset.class) + @ApiResponses( + value = {@ApiResponse(code = 404, message = "The controller cannot be found"), @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled")}) + public Response decoders(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final List decoders = + EventProtocolCoder.manager.getDecoders(drools.getGroupId(), drools.getArtifactId()); + return Response.status(Response.Status.OK).entity(decoders).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND).entity(new Error(controllerName + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error(controllerName + " not acceptable")) + .build(); + } + } + + @GET + @Path("engine/controllers/{controller}/decoders/filters") + @ApiOperation(value = "Gets all the filters used by a controller", + notes = "A Policy Controller uses decoders to deserialize incoming network messages from " + + "subscribed network topics into specific (fact) objects. " + + "The deserialized (fact) object will typically be inserted in the drools working " + + " memory of the controlled drools application." + + "Acceptance filters are used to filter out undesired network messages for the given controller", + responseContainer = "List", response = CoderFilters.class) + @ApiResponses( + value = {@ApiResponse(code = 404, message = "The controller cannot be found"), @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled")}) + public Response decoderFilters(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final List filters = + EventProtocolCoder.manager.getDecoderFilters(drools.getGroupId(), drools.getArtifactId()); + return Response.status(Response.Status.OK).entity(filters).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND).entity(new Error(controllerName + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get decoders for policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE).entity(new Error(controllerName + " not acceptable")) + .build(); + } + } + + @GET + @Path("engine/controllers/{controller}/decoders/{topic}") + @ApiOperation(value = "Gets all the decoders in use by a controller for a networked topic", + notes = "A Policy Controller uses decoders to deserialize incoming network messages from " + + "subscribed network topics into specific (fact) objects. " + + "The deserialized (fact) object will typically be inserted in the drools working " + + " memory of the controlled drools application.", + responseContainer = "List", response = ProtocolCoderToolset.class) + @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller or topic cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled")}) + public Response decoder( + @ApiParam(value = "Policy Controller Name", required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Networked Topic Name", required = true) @PathParam("topic") String topic) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final ProtocolCoderToolset decoder = + EventProtocolCoder.manager.getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); + return Response.status(Response.Status.OK).entity(decoder).build(); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, + controllerName, topic, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + topic + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, + controllerName, topic, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + topic + " not acceptable")).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/decoders/{topic}/filters") + @ApiOperation(value = "Gets all filters attached to decoders for a given networked topic in use by a controller", + notes = "A Policy Controller uses decoders to deserialize incoming network messages from " + + "subscribed network topics into specific (fact) objects. " + + "The deserialized (fact) object will typically be inserted in the drools working " + + " memory of the controlled drools application." + + "Acceptance filters are used to filter out undesired network messages for the given controller", + responseContainer = "List", response = CoderFilters.class) + @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller or topic cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled")}) + public Response decoderFilter( + @ApiParam(value = "Policy Controller Name", required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Networked Topic Name", required = true) @PathParam("topic") String topic) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final ProtocolCoderToolset decoder = + EventProtocolCoder.manager.getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); + if (decoder == null) { + return Response.status(Response.Status.BAD_REQUEST).entity(new Error(topic + " does not exist")) + .build(); + } else { + return Response.status(Response.Status.OK).entity(decoder.getCoders()).build(); + } + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, + controllerName, topic, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + topic + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get decoders for policy-controller {} topic {} because of {}", this, + controllerName, topic, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + topic + " not acceptable")).build(); + } + } + + @GET + @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}") + @ApiOperation( + value = "Gets all filters attached to decoders for a given subscribed networked topic " + "and fact type", + notes = "Decoders are associated with networked topics. A Policy Controller manages " + + "multiple topics and therefore its attached decoders. " + + "A Policy Controller uses filters to further specify the fact mapping. " + + "Filters are applied on a per fact type (classname).", + responseContainer = "List", response = CoderFilters.class) + @ApiResponses(value = {@ApiResponse(code = 404, message = "The controller, topic, or fact type cannot be found"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled")}) + public Response decoderFilter( + @ApiParam(value = "Policy Controller Name", required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Networked Topic Name", required = true) @PathParam("topic") String topic, + @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass) { + try { + final DroolsController drools = this.getDroolsController(controllerName); + final ProtocolCoderToolset decoder = + EventProtocolCoder.manager.getDecoders(drools.getGroupId(), drools.getArtifactId(), topic); + final CoderFilters filters = decoder.getCoder(factClass); + if (filters == null) { + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(topic + ":" + factClass + " does not exist")).build(); + } else { + return Response.status(Response.Status.OK).entity(filters).build(); + } + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}", this, + controllerName, topic, factClass, e.getMessage(), e); + return Response.status(Response.Status.NOT_FOUND) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not found")).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get decoder filters for policy-controller {} topic {} type {} because of {}", this, + controllerName, topic, factClass, e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + ":" + topic + ":" + factClass + " not acceptable")).build(); + } + } + + @PUT + @Path("engine/controllers/{controller}/decoders/{topic}/filters/{factType}") + @ApiOperation(value = "Attaches filters to the decoder for a given networked topic " + "and fact type", + notes = "Decoders are associated with networked topics. A Policy Controller manages " + + "multiple topics and therefore its attached decoders. " + + "A Policy Controller uses filters to further specify the fact mapping. " + + "Filters are applied on a per fact type (classname).", + responseContainer = "List", response = CoderFilters.class) + @ApiResponses(value = { + @ApiResponse(code = 404, + message = "The controller, topic, fact type, cannot be found, " + + "or a filter has not been provided"), + @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled")}) + public Response decoderFilter( + @ApiParam(value = "Policy Controller Name", required = true) @PathParam("controller") String controllerName, + @ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic, + @ApiParam(value = "Fact Type", required = true) @PathParam("factType") String factClass, + @ApiParam(value = "Configuration Filter", required = true) JsonProtocolFilter configFilters) { + + if (configFilters == null) { + return Response.status(Response.Status.BAD_REQUEST).entity(new Error("Configuration Filters not provided")) + .build(); + } + + 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(); + } + } - public String getJsonEncoding() { - return jsonEncoding; + @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(); + } } - public void setJsonEncoding(String jsonEncoding) { - this.jsonEncoding = jsonEncoding; + @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(); + } } - public Boolean getEncoding() { - return encoding; + @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(); + } } - public void setEncoding(Boolean encoding) { - this.encoding = encoding; + @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(); + } } - public Boolean getDecoding() { - return decoding; + @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(); + } + + final CodingResult result = new CodingResult(); + result.setDecoding(false); + result.setEncoding(false); + result.setJsonEncoding(null); + + Object event; + try { + event = EventProtocolCoder.manager.decode(policyController.getDrools().getGroupId(), + policyController.getDrools().getArtifactId(), topic, json); + result.setDecoding(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(); + } + + try { + result.setJsonEncoding(EventProtocolCoder.manager.encode(topic, event)); + result.setEncoding(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); + } + + return Response.status(Response.Status.OK).entity(result).build(); } - public void setDecoding(Boolean decoding) { - this.decoding = decoding; + @GET + @Path("engine/controllers/{controller}/encoders") + @ApiOperation(value = "Retrieves the encoder filters of a controller", + notes = "The encoders serializes a fact object, typically for network transmission", + responseContainer = "List", response = CoderFilters.class) + @ApiResponses(value = {@ApiResponse(code = 400, message = "Bad input has been provided"), @ApiResponse(code = 406, + message = "The system is an administrative state that prevents " + "this request to be fulfilled")}) + public Response encoderFilters(@ApiParam(value = "Policy Controller Name", + required = true) @PathParam("controller") String controllerName) { + List encoders; + try { + final PolicyController controller = PolicyController.factory.get(controllerName); + final DroolsController drools = controller.getDrools(); + encoders = EventProtocolCoder.manager.getEncoderFilters(drools.getGroupId(), drools.getArtifactId()); + } catch (final IllegalArgumentException e) { + logger.debug("{}: cannot get encoder filters for policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.BAD_REQUEST) + .entity(new Error(controllerName + " not found: " + e.getMessage())).build(); + } catch (final IllegalStateException e) { + logger.debug("{}: cannot get encoder filters for policy-controller {} because of {}", this, controllerName, + e.getMessage(), e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(controllerName + " is not accepting the request")).build(); + } + + return Response.status(Response.Status.OK).entity(encoders).build(); } - } - /** - * Generic Error Reporting class - */ - public static class Error { - private String msg; + @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(ProxyTopicEndpointManager.getInstance()).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 = ProxyTopicEndpointManager.getInstance().lock(); + if (success) { + return Response.status(Status.OK).entity(ProxyTopicEndpointManager.getInstance()).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 = ProxyTopicEndpointManager.getInstance().unlock(); + if (success) { + return Response.status(Status.OK).entity(ProxyTopicEndpointManager.getInstance()).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(ProxyTopicEndpointManager.getInstance().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(ProxyTopicEndpointManager.getInstance().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(ProxyTopicEndpointManager.getInstance().getUebTopicSources()) + .build(); + } + + @GET + @Path("engine/topics/sinks/ueb") + @ApiOperation(value = "Retrieves the UEB managed topic sinks", notes = "UEB Topic Sinks Agregation", + responseContainer = "List", response = UebTopicSink.class) + public Response uebSinks() { + return Response.status(Response.Status.OK).entity(ProxyTopicEndpointManager.getInstance().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(ProxyTopicEndpointManager.getInstance().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(ProxyTopicEndpointManager.getInstance().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(ProxyTopicEndpointManager.getInstance().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(ProxyTopicEndpointManager.getInstance().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(ProxyTopicEndpointManager.getInstance().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(ProxyTopicEndpointManager.getInstance().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(ProxyTopicEndpointManager.getInstance().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(ProxyTopicEndpointManager.getInstance().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(ProxyTopicEndpointManager.getInstance().getDmaapTopicSource(topic).getRecentEvents())) + .build(); + } - public Error(String msg) { - this.setError(msg); + @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(ProxyTopicEndpointManager.getInstance().getDmaapTopicSink(topic).getRecentEvents())) + .build(); + } + + @GET + @Path("engine/topics/sinks/noop") + @ApiOperation(value = "Retrieves the NOOP managed topic sinks", notes = "NOOP Topic Sinks Agregation", + responseContainer = "List", response = NoopTopicSink.class) + public Response noopSinks() { + return Response.status(Response.Status.OK).entity(ProxyTopicEndpointManager.getInstance().getNoopTopicSinks()) + .build(); + } + + @GET + @Path("engine/topics/sinks/noop/{topic}") + @ApiOperation(value = "Retrieves a NOOP managed topic sink", + notes = "NOOP is an dev/null Network Communicaton Sink", response = NoopTopicSink.class) + public Response noopSinkTopic(@ApiParam(value = "Topic Name", required = true) @PathParam("topic") String topic) { + return Response.status(Response.Status.OK) + .entity(ProxyTopicEndpointManager.getInstance().getNoopTopicSink(topic)).build(); + } + + @GET + @Path("engine/topics/sinks/noop/{topic}/events") + @ApiOperation(value = "Retrieves the latest events send through a NOOP topic", + notes = "NOOP is an dev/null Network Communicaton Sink", responseContainer = "List") + public Response noopSinkEvents(@PathParam("topic") String topic) { + return Response.status(Status.OK) + .entity(Arrays + .asList(ProxyTopicEndpointManager.getInstance().getNoopTopicSink(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(); } - public String getError() { - return msg; + @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 = ProxyTopicEndpointManager.getInstance().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(makeTopicOperError(topic)).build(); + } } - public void setError(String msg) { - this.msg = msg; + @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 = ProxyTopicEndpointManager.getInstance().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(makeTopicOperError(topic)).build(); + } } - } - /** - * Feed Ports into Resources - */ - public enum Inputs { - configuration, - } + private Error makeTopicOperError(String topic) { + return new Error("cannot perform operation on " + topic); + } - /** - * Resource Toggles - */ - public enum Switches { - activation, lock, - } + @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 = ProxyTopicEndpointManager.getInstance().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(makeTopicOperError(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 = ProxyTopicEndpointManager.getInstance().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(makeTopicOperError(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 = ProxyTopicEndpointManager.getInstance().getUebTopicSource(topic); + final boolean success = uebReader.offer(json); + if (success) { + return Response.status(Status.OK) + .entity(Arrays.asList( + ProxyTopicEndpointManager.getInstance().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) { + logNoUebEncoder(topic, e); + return Response.status(Response.Status.NOT_FOUND).entity(new Error(topic + " not found")).build(); + } catch (final IllegalStateException e) { + logNoUebEncoder(topic, e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(topic + " not acceptable due to current state")).build(); + } catch (final Exception e) { + logNoUebEncoder(topic, e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new Error(e.getMessage())).build(); + } + } + + private void logNoUebEncoder(String topic, Exception ex) { + logger.debug("{}: cannot offer for encoder ueb topic for {} because of {}", this, topic, ex.getMessage(), ex); + } + + @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 = ProxyTopicEndpointManager.getInstance().getDmaapTopicSource(topic); + final boolean success = dmaapReader.offer(json); + if (success) { + return Response.status(Status.OK) + .entity(Arrays.asList( + ProxyTopicEndpointManager.getInstance().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) { + logNoDmaapEncoder(topic, e); + return Response.status(Response.Status.NOT_FOUND).entity(new Error(topic + " not found")).build(); + } catch (final IllegalStateException e) { + logNoDmaapEncoder(topic, e); + return Response.status(Response.Status.NOT_ACCEPTABLE) + .entity(new Error(topic + " not acceptable due to current state")).build(); + } catch (final Exception e) { + logNoDmaapEncoder(topic, e); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(new Error(e.getMessage())).build(); + } + } + + private void logNoDmaapEncoder(String topic, Exception ex) { + logger.debug("{}: cannot offer for encoder dmaap topic for {} because of {}", this, topic, ex.getMessage(), ex); + } + + @GET + @Path("engine/tools/uuid") + @ApiOperation(value = "Produces an UUID", notes = "UUID generation utility") + @Produces(MediaType.TEXT_PLAIN) + public Response uuid() { + return Response.status(Status.OK).entity(UUID.randomUUID().toString()).build(); + } + + @GET + @Path("engine/tools/loggers") + @ApiOperation(value = "all active loggers", responseContainer = "List") + @ApiResponses(value = {@ApiResponse(code = 500, message = "logging misconfiguration")}) + public Response loggers() { + final List names = new ArrayList<>(); + if (!(LoggerFactory.getILoggerFactory() instanceof LoggerContext)) { + logger.warn("The SLF4J logger factory is not configured for logback"); + return Response.status(Status.INTERNAL_SERVER_ERROR).entity(names).build(); + } + + final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + for (final Logger lgr : context.getLoggerList()) { + names.add(lgr.getName()); + } + + 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(); + } + + final LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory(); + final ch.qos.logback.classic.Logger lgr = context.getLogger(loggerName); + if (lgr == null) { + return Response.status(Status.NOT_FOUND).build(); + } + + final String loggerLevel = (lgr.getLevel() != null) ? lgr.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 { + /** + * serialized output + */ + + private String jsonEncoding; + /** + * encoding result + */ + + private Boolean encoding; + + /** + * decoding result + */ + private Boolean decoding; + + public String getJsonEncoding() { + return jsonEncoding; + } + + public void setJsonEncoding(String jsonEncoding) { + this.jsonEncoding = jsonEncoding; + } + + public Boolean getEncoding() { + return encoding; + } + + public void setEncoding(Boolean encoding) { + this.encoding = encoding; + } + + public Boolean getDecoding() { + return decoding; + } + + public void setDecoding(Boolean decoding) { + this.decoding = decoding; + } + } + + /** + * Generic Error Reporting class + */ + public static class Error { + private String msg; + + public Error(String msg) { + this.setError(msg); + } + + public String getError() { + return msg; + } + + public void setError(String msg) { + this.msg = msg; + } + } + + /** + * 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 43216000..c8956839 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 @@ -25,7 +25,7 @@ import java.nio.file.Paths; import java.util.Properties; import org.onap.policy.drools.persistence.SystemPersistence; -import org.onap.policy.drools.properties.PolicyProperties; +import org.onap.policy.drools.properties.DroolsProperties; import org.onap.policy.drools.utils.logging.LoggerUtil; import org.onap.policy.drools.utils.logging.MDCTransaction; import org.slf4j.Logger; @@ -134,7 +134,7 @@ public class Main { for (final Properties controllerProperties : SystemPersistence.manager .getControllerProperties()) { final String controllerName = - controllerProperties.getProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME); + controllerProperties.getProperty(DroolsProperties.PROPERTY_CONTROLLER_NAME); try { trans = MDCTransaction.newTransaction(null, null).setServiceName(Main.class.getSimpleName()). diff --git a/policy-management/src/main/java/org/onap/policy/drools/system/PolicyController.java b/policy-management/src/main/java/org/onap/policy/drools/system/PolicyController.java index 5324937e..9e01634b 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/system/PolicyController.java +++ b/policy-management/src/main/java/org/onap/policy/drools/system/PolicyController.java @@ -23,86 +23,82 @@ package org.onap.policy.drools.system; import java.util.List; import java.util.Properties; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.capabilities.Lockable; +import org.onap.policy.common.capabilities.Startable; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.common.endpoints.event.comm.TopicSource; import org.onap.policy.drools.controller.DroolsController; -import org.onap.policy.drools.event.comm.TopicSource; -import org.onap.policy.drools.event.comm.Topic.CommInfrastructure; -import org.onap.policy.drools.event.comm.TopicSink; -import org.onap.policy.drools.properties.Lockable; -import org.onap.policy.drools.properties.Startable; import org.onap.policy.drools.protocol.configuration.DroolsConfiguration; /** - * A Policy Controller is the higher level unit of control. It corresponds to - * the ncomp equivalent of a controller. It provides management of underlying - * resources associated with the policy controller, which is a) communication - * infrastructure, and b) policy-core (drools) session infrastructure + * A Policy Controller is the higher level unit of control. It corresponds to the ncomp equivalent + * of a controller. It provides management of underlying resources associated with the policy + * controller, which is a) communication infrastructure, and b) policy-core (drools) session + * infrastructure * */ public interface PolicyController extends Startable, Lockable { - - /** - * Factory that tracks and manages Policy Controllers - */ - public static PolicyControllerFactory factory = - new IndexedPolicyControllerFactory(); - - /** - * name of this Policy Controller - */ - public String getName(); - - /** - * Get the topic readers of interest for this controller - */ - public List getTopicSources(); - - /** - * Get the topic readers of interest for this controller - */ - public List getTopicSinks(); - - /** - * Get the Drools Controller - */ - public DroolsController getDrools(); - - /** - * update maven configuration - * - * @param newDroolsConfiguration new drools configuration - * @return true if the update was successful, false otherwise - */ - public boolean updateDrools(DroolsConfiguration newDroolsConfiguration); - - /** - * Get the Properties - */ - public Properties getProperties(); - - /** - * 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, - Object event); - - /** - * halts and permanently releases all resources - * @throws IllegalStateException - */ - public void halt(); - + + /** + * Factory that tracks and manages Policy Controllers + */ + public static PolicyControllerFactory factory = new IndexedPolicyControllerFactory(); + + /** + * name of this Policy Controller + */ + public String getName(); + + /** + * Get the topic readers of interest for this controller + */ + public List getTopicSources(); + + /** + * Get the topic readers of interest for this controller + */ + public List getTopicSinks(); + + /** + * Get the Drools Controller + */ + public DroolsController getDrools(); + + /** + * update maven configuration + * + * @param newDroolsConfiguration new drools configuration + * @return true if the update was successful, false otherwise + */ + public boolean updateDrools(DroolsConfiguration newDroolsConfiguration); + + /** + * Get the Properties + */ + public Properties getProperties(); + + /** + * 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, Object event); + + /** + * halts and permanently releases all resources + * + * @throws IllegalStateException + */ + public void halt(); + } 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 d7275578..71c509c2 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 @@ -20,26 +20,33 @@ package org.onap.policy.drools.system; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + import java.util.ArrayList; import java.util.List; import java.util.Properties; +import org.onap.policy.common.capabilities.Lockable; +import org.onap.policy.common.capabilities.Startable; +import org.onap.policy.common.endpoints.event.comm.Topic; +import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure; +import org.onap.policy.common.endpoints.event.comm.TopicListener; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.common.endpoints.event.comm.TopicSource; +import org.onap.policy.common.endpoints.event.comm.impl.ProxyTopicEndpointManager; +import org.onap.policy.common.endpoints.http.server.HttpServletServer; +import org.onap.policy.common.endpoints.http.server.impl.IndexedHttpServletServerFactory; +import org.onap.policy.common.endpoints.properties.PolicyEndPointProperties; import org.onap.policy.drools.controller.DroolsController; import org.onap.policy.drools.core.PolicyContainer; import org.onap.policy.drools.core.jmx.PdpJmxListener; -import org.onap.policy.drools.event.comm.Topic; -import org.onap.policy.drools.event.comm.Topic.CommInfrastructure; -import org.onap.policy.drools.event.comm.TopicEndpoint; -import org.onap.policy.drools.event.comm.TopicListener; -import org.onap.policy.drools.event.comm.TopicSink; -import org.onap.policy.drools.event.comm.TopicSource; import org.onap.policy.drools.features.PolicyControllerFeatureAPI; import org.onap.policy.drools.features.PolicyEngineFeatureAPI; -import org.onap.policy.drools.http.server.HttpServletServer; import org.onap.policy.drools.persistence.SystemPersistence; -import org.onap.policy.drools.properties.Lockable; -import org.onap.policy.drools.properties.PolicyProperties; -import org.onap.policy.drools.properties.Startable; +import org.onap.policy.drools.properties.DroolsProperties; import org.onap.policy.drools.protocol.coders.EventProtocolCoder; import org.onap.policy.drools.protocol.configuration.ControllerConfiguration; import org.onap.policy.drools.protocol.configuration.PdpdConfiguration; @@ -49,292 +56,285 @@ import org.onap.policy.drools.utils.logging.MDCTransaction; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; - /** * Policy Engine, the top abstraction for the Drools PDP Policy Engine. It abstracts away a Drools * PDP Engine from management purposes. This is the best place to looking at the code from a top * down approach. Other managed entities can be obtained from the PolicyEngine, hierarchically.
* PolicyEngine 1 --- * PolicyController 1 --- 1 DroolsController 1 --- 1 PolicyContainer 1 --- * - * PolicySession
- * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 UebTopicReader
- * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 DmaapTopicReader
- * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 DmaapTopicWriter
- * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 RestTopicReader
- * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 RestTopicWriter
- * PolicyEngine 1 --- 1 ManagementServer + * PolicySession
PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 + * UebTopicReader
PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 + * DmaapTopicReader
PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 + * DmaapTopicWriter
PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 + * RestTopicReader
PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 + * RestTopicWriter
PolicyEngine 1 --- 1 ManagementServer */ public interface PolicyEngine extends Startable, Lockable, TopicListener { - /** - * Policy Engine Manager - */ - public static final PolicyEngine manager = new PolicyEngineManager(); - - /** - * 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 properties properties to initialize the Policy Controller - * @throws IllegalArgumentException when invalid or insufficient properties are provided - * @throws IllegalStateException when the engine is in a state where this operation is not - * permitted. - * @return the newly instantiated Policy Controller - */ - public PolicyController createPolicyController(String name, Properties properties); - - /** - * updates the Policy Engine with the given configuration - * - * @param configuration the configuration - * @return success or failure - * @throws IllegalArgumentException if invalid argument provided - * @throws IllegalStateException if the system is in an invalid state - */ - public boolean configure(PdpdConfiguration configuration); - - /** - * updates a set of Policy Controllers with configuration information - * - * @param configuration - * @return - * @throws IllegalArgumentException - * @throws IllegalStateException - */ - public List updatePolicyControllers( - List configuration); - - /** - * updates an already existing Policy Controller with configuration information - * - * @param configuration configuration - * - * @return the updated Policy Controller - * @throws IllegalArgumentException in the configuration is invalid - * @throws IllegalStateException if the controller is in a bad state - * @throws Exception any other reason - */ - public PolicyController updatePolicyController(ControllerConfiguration configuration); - - /** - * removes the Policy Controller identified by its name from the Policy Engine - * - * @param name name of the Policy Controller - * @return the removed Policy Controller - */ - public void removePolicyController(String name); - - /** - * removes a Policy Controller from the Policy Engine - * - * @param controller the Policy Controller to remove from the Policy Engine - */ - public void removePolicyController(PolicyController controller); - - /** - * returns a list of the available Policy Controllers - * - * @return list of Policy Controllers - */ - public List getPolicyControllers(); - - - /** - * get policy controller names - * - * @return list of controller names - */ - public List getPolicyControllerIds(); - - /** - * get unmanaged sources - * - * @return unmanaged sources - */ - public List getSources(); - - /** - * get unmanaged sinks - * - * @return unmanaged sinks - */ - public List getSinks(); - - /** - * get unmmanaged http servers list - * - * @return http servers - */ - public List getHttpServers(); - - /** - * get properties configuration - * - * @return properties objects - */ - public Properties getProperties(); - - /** - * get features attached to the Policy Engine - * - * @return list of features - */ - public List getFeatureProviders(); - - /** - * get named feature attached to the Policy Engine - * - * @return the feature - */ - public PolicyEngineFeatureAPI getFeatureProvider(String featureName); - - /** - * get features attached to the Policy Engine - * - * @return list of features - */ - public List getFeatures(); - - /** - * Attempts the dispatching of an "event" object - * - * @param topic topic - * @param event the event object to send - * - * @return true if successful, false if a failure has occurred. - * @throws IllegalArgumentException when invalid or insufficient properties are provided - * @throws IllegalStateException when the engine is in a state where this operation is not - * permitted (ie. locked or stopped). - */ - public boolean deliver(String topic, Object event); - - /** - * Attempts the dispatching of an "event" object over communication infrastructure "busType" - * - * @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); - - /** - * Attempts the dispatching of an "event" object over communication infrastructure "busType" - * - * @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); - - /** - * Attempts delivering of an String over communication infrastructure "busType" - * - * @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); - - /** - * 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 static final PolicyEngine manager = new PolicyEngineManager(); + + /** + * 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 properties properties to initialize the Policy Controller + * @throws IllegalArgumentException when invalid or insufficient properties are provided + * @throws IllegalStateException when the engine is in a state where this operation is not + * permitted. + * @return the newly instantiated Policy Controller + */ + public PolicyController createPolicyController(String name, Properties properties); + + /** + * updates the Policy Engine with the given configuration + * + * @param configuration the configuration + * @return success or failure + * @throws IllegalArgumentException if invalid argument provided + * @throws IllegalStateException if the system is in an invalid state + */ + public boolean configure(PdpdConfiguration configuration); + + /** + * updates a set of Policy Controllers with configuration information + * + * @param configuration + * @return + * @throws IllegalArgumentException + * @throws IllegalStateException + */ + public List updatePolicyControllers(List configuration); + + /** + * updates an already existing Policy Controller with configuration information + * + * @param configuration configuration + * + * @return the updated Policy Controller + * @throws IllegalArgumentException in the configuration is invalid + * @throws IllegalStateException if the controller is in a bad state + * @throws Exception any other reason + */ + public PolicyController updatePolicyController(ControllerConfiguration configuration); + + /** + * removes the Policy Controller identified by its name from the Policy Engine + * + * @param name name of the Policy Controller + * @return the removed Policy Controller + */ + public void removePolicyController(String name); + + /** + * removes a Policy Controller from the Policy Engine + * + * @param controller the Policy Controller to remove from the Policy Engine + */ + public void removePolicyController(PolicyController controller); + + /** + * returns a list of the available Policy Controllers + * + * @return list of Policy Controllers + */ + public List getPolicyControllers(); + + + /** + * get policy controller names + * + * @return list of controller names + */ + public List getPolicyControllerIds(); + + /** + * get unmanaged sources + * + * @return unmanaged sources + */ + public List getSources(); + + /** + * get unmanaged sinks + * + * @return unmanaged sinks + */ + public List getSinks(); + + /** + * get unmmanaged http servers list + * + * @return http servers + */ + public List getHttpServers(); + + /** + * get properties configuration + * + * @return properties objects + */ + public Properties getProperties(); + + /** + * get features attached to the Policy Engine + * + * @return list of features + */ + public List getFeatureProviders(); + + /** + * get named feature attached to the Policy Engine + * + * @return the feature + */ + public PolicyEngineFeatureAPI getFeatureProvider(String featureName); + + /** + * get features attached to the Policy Engine + * + * @return list of features + */ + public List getFeatures(); + + /** + * Attempts the dispatching of an "event" object + * + * @param topic topic + * @param event the event object to send + * + * @return true if successful, false if a failure has occurred. + * @throws IllegalArgumentException when invalid or insufficient properties are provided + * @throws IllegalStateException when the engine is in a state where this operation is not + * permitted (ie. locked or stopped). + */ + public boolean deliver(String topic, Object event); + + /** + * Attempts the dispatching of an "event" object over communication infrastructure "busType" + * + * @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); + + /** + * Attempts the dispatching of an "event" object over communication infrastructure "busType" + * + * @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); + + /** + * Attempts delivering of an String over communication infrastructure "busType" + * + * @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); + + /** + * 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(); } @@ -342,1128 +342,1168 @@ public interface PolicyEngine extends Startable, Lockable, TopicListener { * Policy Engine Manager Implementation */ class PolicyEngineManager implements PolicyEngine { - private static final String INVALID_TOPIC_MSG = "Invalid Topic"; + private static final String INVALID_TOPIC_MSG = "Invalid Topic"; -private static final String INVALID_EVENT_MSG = "Invalid Event"; + private static final String INVALID_EVENT_MSG = "Invalid Event"; -private static final String ENGINE_STOPPED_MSG = "Policy Engine is stopped"; + private static final String ENGINE_STOPPED_MSG = "Policy Engine is stopped"; -private static final String ENGINE_LOCKED_MSG = "Policy Engine is locked"; + private static final String ENGINE_LOCKED_MSG = "Policy Engine is locked"; -/** - * logger - */ - private static final Logger logger = LoggerFactory.getLogger(PolicyEngineManager.class); - - /** - * Is the Policy Engine running? - */ - protected volatile boolean alive = false; - - /** - * Is the engine locked? - */ - protected volatile boolean locked = false; - - /** - * Properties used to initialize the engine - */ - protected Properties properties; - - /** - * Environment Properties - */ - protected final Properties environment = new Properties(); - - /** - * Policy Engine Sources - */ - protected List sources = new ArrayList<>(); - - /** - * Policy Engine Sinks - */ - protected List sinks = new ArrayList<>(); - - /** - * Policy Engine HTTP Servers - */ - protected List httpServers = new ArrayList<>(); - - /** - * gson parser to decode configuration requests - */ - protected final Gson decoder = new GsonBuilder().disableHtmlEscaping().create(); - - - @Override - public synchronized void boot(String[] cliArgs) { - - for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - try { - if (feature.beforeBoot(this, cliArgs)) - return; - } catch (final Exception e) { - logger.error("{}: feature {} before-boot failure because of {}", this, - feature.getClass().getName(), e.getMessage(), e); - } - } + /** + * logger + */ + private static final Logger logger = LoggerFactory.getLogger(PolicyEngineManager.class); - try { - PolicyContainer.globalInit(cliArgs); - } catch (final Exception e) { - logger.error("{}: cannot init policy-container because of {}", this, e.getMessage(), e); - } + /** + * Is the Policy Engine running? + */ + protected volatile boolean alive = false; - 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, - "" + Integer.toString(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"); - } + /** + * Is the engine locked? + */ + protected volatile boolean locked = false; + + /** + * Properties used to initialize the engine + */ + protected Properties properties; + + /** + * Environment Properties + */ + protected final Properties environment = new Properties(); + + /** + * Policy Engine Sources + */ + protected List sources = new ArrayList<>(); - /* policy-engine 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); - } + /** + * Policy Engine Sinks + */ + protected List sinks = new ArrayList<>(); + + /** + * Policy Engine HTTP Servers + */ + protected List httpServers = new ArrayList<>(); + + /** + * gson parser to decode configuration requests + */ + protected final Gson decoder = new GsonBuilder().disableHtmlEscaping().create(); + + + @Override + public synchronized void boot(String[] cliArgs) { + + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.beforeBoot(this, cliArgs)) { + return; + } + } catch (final Exception e) { + logger.error("{}: feature {} before-boot failure because of {}", this, feature.getClass().getName(), + e.getMessage(), e); + } + } + + try { + PolicyContainer.globalInit(cliArgs); + } catch (final Exception e) { + logger.error("{}: cannot init policy-container because of {}", this, e.getMessage(), e); + } + + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + try { + if (feature.afterBoot(this)) { + return; + } + } catch (final Exception e) { + logger.error("{}: feature {} after-boot failure because of {}", this, feature.getClass().getName(), + e.getMessage(), e); + } + } } - this.properties = properties; + @Override + public synchronized void setEnvironment(Properties properties) { + this.environment.putAll(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); + @JsonIgnore + @Override + public synchronized Properties getEnvironment() { + return this.environment; } - try { - this.sinks = TopicEndpoint.manager.addTopicSinks(properties); - } catch (final IllegalArgumentException e) { - logger.error("{}: add-sinks failed", this, e); + @Override + public synchronized String getEnvironmentProperty(String envKey) { + String value = this.environment.getProperty(envKey); + if (value == null) { + value = System.getenv(envKey); + } + return value; } - try { - this.httpServers = HttpServletServer.factory.build(properties); - } catch (final IllegalArgumentException e) { - logger.error("{}: add-http-servers failed", this, e); + @Override + public synchronized String setEnvironmentProperty(String envKey, String envValue) { + return (String) this.environment.setProperty(envKey, envValue); } - /* 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); - } + @Override + public final Properties defaultTelemetryConfig() { + final Properties defaultConfig = new Properties(); + + defaultConfig.put(PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES, "TELEMETRY"); + defaultConfig.put(PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + TELEMETRY_SERVER_DEFAULT_NAME + + PolicyEndPointProperties.PROPERTY_HTTP_HOST_SUFFIX, TELEMETRY_SERVER_DEFAULT_HOST); + defaultConfig.put( + PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + TELEMETRY_SERVER_DEFAULT_NAME + + PolicyEndPointProperties.PROPERTY_HTTP_PORT_SUFFIX, + "" + Integer.toString(TELEMETRY_SERVER_DEFAULT_PORT)); + defaultConfig.put( + PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + TELEMETRY_SERVER_DEFAULT_NAME + + PolicyEndPointProperties.PROPERTY_HTTP_REST_PACKAGES_SUFFIX, + RestManager.class.getPackage().getName()); + defaultConfig.put(PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + TELEMETRY_SERVER_DEFAULT_NAME + + PolicyEndPointProperties.PROPERTY_HTTP_SWAGGER_SUFFIX, "" + Boolean.TRUE); + defaultConfig.put(PolicyEndPointProperties.PROPERTY_HTTP_SERVER_SERVICES + "." + TELEMETRY_SERVER_DEFAULT_NAME + + PolicyEndPointProperties.PROPERTY_MANAGED_SUFFIX, "" + Boolean.FALSE); + + return defaultConfig; } - return; - } + @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); + } + } - @Override - public synchronized PolicyController createPolicyController(String name, Properties properties) { + this.properties = properties; - String tempName = name; - // check if a PROPERTY_CONTROLLER_NAME property is present - // if so, override the given name + try { + this.sources = ProxyTopicEndpointManager.getInstance().addTopicSources(properties); + for (final TopicSource source : this.sources) { + source.register(this); + } + } catch (final Exception e) { + logger.error("{}: add-sources failed", this, e); + } - final String propertyControllerName = - properties.getProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME); - if (propertyControllerName != null && !propertyControllerName.isEmpty()) { - if (!propertyControllerName.equals(tempName)) { - throw new IllegalStateException("Proposed name (" + tempName + ") and properties name (" - + propertyControllerName + ") don't match"); - } - tempName = propertyControllerName; - } + try { + this.sinks = ProxyTopicEndpointManager.getInstance().addTopicSinks(properties); + } catch (final IllegalArgumentException e) { + logger.error("{}: add-sinks failed", this, e); + } - PolicyController controller; - for (final PolicyControllerFeatureAPI controllerFeature : PolicyControllerFeatureAPI.providers - .getList()) { - try { - controller = controllerFeature.beforeCreate(tempName, 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); - } - } + try { + this.httpServers = IndexedHttpServletServerFactory.getInstance().build(properties); + } catch (final IllegalArgumentException e) { + logger.error("{}: add-http-servers failed", this, e); + } - controller = PolicyController.factory.build(tempName, 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); - } + /* 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; } - return controller; - } + @Override + public synchronized PolicyController createPolicyController(String name, Properties properties) { + String tempName = name; + // check if a PROPERTY_CONTROLLER_NAME property is present + // if so, override the given name - @Override - public boolean configure(PdpdConfiguration config) { + final String propertyControllerName = properties.getProperty(DroolsProperties.PROPERTY_CONTROLLER_NAME); + if (propertyControllerName != null && !propertyControllerName.isEmpty()) { + if (!propertyControllerName.equals(tempName)) { + throw new IllegalStateException("Proposed name (" + tempName + ") and properties name (" + + propertyControllerName + ") don't match"); + } + tempName = propertyControllerName; + } - if (config == null) - throw new IllegalArgumentException("No configuration provided"); + PolicyController controller; + for (final PolicyControllerFeatureAPI controllerFeature : PolicyControllerFeatureAPI.providers.getList()) { + try { + controller = controllerFeature.beforeCreate(tempName, 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); + } + } - final String entity = config.getEntity(); + controller = PolicyController.factory.build(tempName, properties); + if (this.isLocked()) { + controller.lock(); + } - MDCTransaction mdcTrans = MDCTransaction.newTransaction(config.getRequestID(), "brmsgw"); - if (this.getSources().size() == 1) { - Topic topic = this.getSources().get(0); - mdcTrans.setServiceName(topic.getTopic()).setRemoteHost(topic.getServers().toString()). - setTargetEntity(config.getEntity()); - } + // 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); + } + } - switch (entity) { - case PdpdConfiguration.CONFIG_ENTITY_CONTROLLER: - boolean success = controllerConfig(config); - mdcTrans.resetSubTransaction().setStatusCode(success).transaction(); - return success; - default: - final String msg = "Configuration Entity is not supported: " + entity; - mdcTrans.resetSubTransaction().setStatusCode(false).setResponseDescription(msg).flush(); - logger.warn(LoggerUtil.TRANSACTION_LOG_MARKER_NAME, msg); - throw new IllegalArgumentException(msg); + return controller; } - } - @Override - public List updatePolicyControllers( - List configControllers) { - final List policyControllers = new ArrayList<>(); - if (configControllers == null || configControllers.isEmpty()) { - if (logger.isInfoEnabled()) - logger.info("No controller configuration provided: " + configControllers); - return policyControllers; + @Override + public boolean configure(PdpdConfiguration config) { + + if (config == null) { + throw new IllegalArgumentException("No configuration provided"); + } + + final String entity = config.getEntity(); + + MDCTransaction mdcTrans = MDCTransaction.newTransaction(config.getRequestID(), "brmsgw"); + if (this.getSources().size() == 1) { + Topic topic = this.getSources().get(0); + mdcTrans.setServiceName(topic.getTopic()).setRemoteHost(topic.getServers().toString()) + .setTargetEntity(config.getEntity()); + } + + switch (entity) { + case PdpdConfiguration.CONFIG_ENTITY_CONTROLLER: + boolean success = controllerConfig(config); + mdcTrans.resetSubTransaction().setStatusCode(success).transaction(); + return success; + default: + final String msg = "Configuration Entity is not supported: " + entity; + mdcTrans.resetSubTransaction().setStatusCode(false).setResponseDescription(msg).flush(); + logger.warn(LoggerUtil.TRANSACTION_LOG_MARKER_NAME, msg); + throw new IllegalArgumentException(msg); + } } - for (final ControllerConfiguration configController : configControllers) { - MDCTransaction mdcTrans = - MDCTransaction.newSubTransaction(null).setTargetEntity(configController.getName()). - setTargetServiceName(configController.getOperation()). - setTargetVirtualEntity(configController.getDrools().toString()); - try { - final PolicyController policyController = this.updatePolicyController(configController); - policyControllers.add(policyController); - mdcTrans.setStatusCode(true).transaction(); - } catch (final Exception e) { - mdcTrans.setStatusCode(false).setResponseCode(e.getClass().getName()). - setResponseDescription(e.getMessage()).flush(); - logger.error(LoggerUtil.TRANSACTION_LOG_MARKER_NAME, "{}: cannot update-policy-controllers because of {}", this, e.getMessage(), e); - } + @Override + public List updatePolicyControllers(List configControllers) { + + final List policyControllers = new ArrayList<>(); + if (configControllers == null || configControllers.isEmpty()) { + if (logger.isInfoEnabled()) { + logger.info("No controller configuration provided: " + configControllers); + } + return policyControllers; + } + + for (final ControllerConfiguration configController : configControllers) { + MDCTransaction mdcTrans = MDCTransaction.newSubTransaction(null).setTargetEntity(configController.getName()) + .setTargetServiceName(configController.getOperation()) + .setTargetVirtualEntity(configController.getDrools().toString()); + try { + final PolicyController policyController = this.updatePolicyController(configController); + policyControllers.add(policyController); + mdcTrans.setStatusCode(true).transaction(); + } catch (final Exception e) { + mdcTrans.setStatusCode(false).setResponseCode(e.getClass().getName()) + .setResponseDescription(e.getMessage()).flush(); + logger.error(LoggerUtil.TRANSACTION_LOG_MARKER_NAME, + "{}: cannot update-policy-controllers because of {}", this, e.getMessage(), e); + } + } + + return policyControllers; } - return policyControllers; - } + @Override + public synchronized 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 controllerProperties = + SystemPersistence.manager.getControllerProperties(controllerName); + + /* + * returned properties cannot be null (per implementation) assert (properties != + * null) + */ + + if (controllerProperties == null) { + throw new IllegalArgumentException(controllerName + " is invalid"); + } - @Override - public synchronized PolicyController updatePolicyController(ControllerConfiguration configController) { + logger.warn("controller " + controllerName + " being recovered. " + + "Reset controller's bad maven coordinates to brainless"); - if (configController == null) - throw new IllegalArgumentException("No controller configuration has been provided"); + /* + * try to bring up bad controller in brainless mode, after having it working, apply + * the new create/update operation. + */ + controllerProperties.setProperty(DroolsProperties.RULES_GROUPID, DroolsController.NO_GROUP_ID); + controllerProperties.setProperty(DroolsProperties.RULES_ARTIFACTID, DroolsController.NO_ARTIFACT_ID); + controllerProperties.setProperty(DroolsProperties.RULES_VERSION, DroolsController.NO_VERSION); - 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 = PolicyEngine.manager.createPolicyController(controllerName, controllerProperties); + + /* 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); + } } - 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"); - } + @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_LOCKED_MSG); + } - try { - policyController = PolicyController.factory.get(controllerName); - } catch (final IllegalArgumentException e) { - // not found - logger.warn("Policy Controller " + controllerName + " not found", e); - } + this.alive = true; - if (policyController == null) { + /* Start Policy Engine exclusively-owned (unmanaged) http servers */ - 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); + for (final HttpServletServer httpServer : this.httpServers) { + try { + if (!httpServer.waitedStart(10 * 1000L)) { + success = false; + } + } catch (final Exception e) { + logger.error("{}: cannot start http-server {} because of {}", this, httpServer, e.getMessage(), e); + } } - /* Recovery case */ + /* Start Policy Engine exclusively-owned (unmanaged) sources */ - logger.warn("controller " + controllerName + " does not exist. " - + "Attempting recovery from disk"); + 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); + } + } - final Properties controllerProperties = - SystemPersistence.manager.getControllerProperties(controllerName); + /* Start Policy Engine owned (unmanaged) sinks */ - /* - * returned properties cannot be null (per implementation) assert (properties != null) - */ + 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); + } + } - if (controllerProperties == null) { - throw new IllegalArgumentException(controllerName + " is invalid"); + /* Start Policy Controllers */ + + final List controllers = PolicyController.factory.inventory(); + for (final PolicyController controller : controllers) { + try { + if (!controller.start()) { + success = false; + } + } catch (final Exception e) { + logger.error("{}: cannot start policy-controller {} because of {}", this, controller, e.getMessage(), + e); + success = false; + } } - logger.warn("controller " + controllerName + " being recovered. " - + "Reset controller's bad maven coordinates to brainless"); + /* Start managed Topic Endpoints */ - /* - * try to bring up bad controller in brainless mode, after having it working, apply the new - * create/update operation. - */ - controllerProperties.setProperty(PolicyProperties.RULES_GROUPID, DroolsController.NO_GROUP_ID); - controllerProperties.setProperty(PolicyProperties.RULES_ARTIFACTID, DroolsController.NO_ARTIFACT_ID); - controllerProperties.setProperty(PolicyProperties.RULES_VERSION, DroolsController.NO_VERSION); - - policyController = PolicyEngine.manager.createPolicyController(controllerName, controllerProperties); - - /* 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); - } - } + try { + if (!ProxyTopicEndpointManager.getInstance().start()) { + success = false; + } + } catch (final IllegalStateException e) { + logger.warn("{}: Topic Endpoint Manager is in an invalid state because of {}", this, e.getMessage(), e); + } - boolean success = true; - if (this.locked) - throw new IllegalStateException(ENGINE_LOCKED_MSG); - this.alive = true; + // Start the JMX listener - /* Start Policy Engine exclusively-owned (unmanaged) http servers */ + PdpJmxListener.start(); - for (final HttpServletServer httpServer : this.httpServers) { - try { - if (!httpServer.waitedStart(10 * 1000L)) - success = false; - } catch (final Exception e) { - logger.error("{}: cannot start http-server {} because of {}", this, httpServer, - e.getMessage(), e); - } + /* 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; } - /* Start Policy Engine exclusively-owned (unmanaged) sources */ + @Override + public synchronized boolean stop() { - 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); - } - } + /* 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); + } + } - /* Start Policy Engine owned (unmanaged) sinks */ + /* stop regardless of the lock state */ - 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); - } - } + boolean success = true; + if (!this.alive) { + return true; + } - /* Start Policy Controllers */ - - final List controllers = PolicyController.factory.inventory(); - for (final PolicyController controller : controllers) { - try { - if (!controller.start()) - success = false; - } catch (final Exception e) { - logger.error("{}: cannot start policy-controller {} because of {}", this, controller, - e.getMessage(), e); - success = false; - } - } + this.alive = false; - /* Start managed Topic Endpoints */ + final List controllers = PolicyController.factory.inventory(); + for (final PolicyController controller : controllers) { + try { + if (!controller.stop()) { + success = false; + } + } catch (final Exception e) { + logger.error("{}: cannot stop policy-controller {} because of {}", this, controller, e.getMessage(), e); + success = false; + } + } - 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); - } + /* 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); + } + } - // Start the JMX listener + /* stop all managed topics sources and sinks */ + if (!ProxyTopicEndpointManager.getInstance().stop()) { + success = false; + } - PdpJmxListener.start(); + /* 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 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); - } - } + /* 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 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); - } + return success; } - /* stop regardless of the lock state */ + @Override + public synchronized void shutdown() { - boolean success = true; - if (!this.alive) - return true; + /* + * shutdown activity even when underlying subcomponents (features, controllers, topics, etc + * ..) are stuck + */ - this.alive = false; + Thread exitThread = new Thread(new Runnable() { + private static final long SHUTDOWN_MAX_GRACE_TIME = 30000L; + + @Override + public void run() { + try { + Thread.sleep(SHUTDOWN_MAX_GRACE_TIME); + logger.warn("{}: abnormal termination - shutdown graceful time period expiration", + PolicyEngineManager.this); + } catch (final InterruptedException e) { + /* courtesy to shutdown() to allow it to return */ + synchronized (PolicyEngineManager.this) { + } + logger.info("{}: finishing a graceful shutdown ", PolicyEngineManager.this, e); + } finally { + /* + * shut down the Policy Engine owned http servers as the very last thing + */ + for (final HttpServletServer httpServer : PolicyEngineManager.this.getHttpServers()) { + try { + httpServer.shutdown(); + } catch (final Exception e) { + logger.error("{}: cannot shutdown http-server {} because of {}", PolicyEngineManager.this, + httpServer, e.getMessage(), e); + } + } + + logger.info("{}: exit", PolicyEngineManager.this); + System.exit(0); + } + } + }); + exitThread.start(); - final List controllers = PolicyController.factory.inventory(); - for (final PolicyController controller : controllers) { - try { - if (!controller.stop()) - success = false; - } catch (final Exception e) { - logger.error("{}: cannot stop policy-controller {} because of {}", this, controller, - e.getMessage(), e); - success = false; - } - } + /* 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); + } + } - /* 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); - } - } + this.alive = false; - /* 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); - } - } + /* 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); + } + } - /* 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); - } + /* 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(); + ProxyTopicEndpointManager.getInstance().shutdown(); + IndexedHttpServletServerFactory.getInstance().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); + } + } + + exitThread.interrupt(); + logger.info("{}: normal termination", this); } - /* 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); - } + @Override + public boolean isAlive() { + return this.alive; } - return success; - } + @Override + public synchronized boolean lock() { - @Override - public synchronized void shutdown() { - - /* - * shutdown activity even when underlying subcomponents - * (features, controllers, topics, etc ..) are stuck - */ - - Thread exitThread = new Thread(new Runnable() { - private static final long SHUTDOWN_MAX_GRACE_TIME = 30000L; - - @Override - public void run() { - try { - Thread.sleep(SHUTDOWN_MAX_GRACE_TIME); - logger.warn("{}: abnormal termination - shutdown graceful time period expiration", - PolicyEngineManager.this); - } catch (final InterruptedException e) { - /* courtesy to shutdown() to allow it to return */ - synchronized(PolicyEngineManager.this) {} - logger.info("{}: finishing a graceful shutdown ", - PolicyEngineManager.this, e); - } finally { - /* - * shut down the Policy Engine owned http servers as the very last thing - */ - for (final HttpServletServer httpServer : PolicyEngineManager.this.getHttpServers()) { + /* policy-engine dispatch pre lock hook */ + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { try { - httpServer.shutdown(); + if (feature.beforeLock(this)) { + return true; + } } catch (final Exception e) { - logger.error("{}: cannot shutdown http-server {} because of {}", - PolicyEngineManager.this, httpServer, e.getMessage(), e); + logger.error("{}: feature {} before-lock failure because of {}", this, feature.getClass().getName(), + e.getMessage(), e); } - } - - logger.info("{}: exit" , PolicyEngineManager.this); - System.exit(0); - } - } - }); - exitThread.start(); - - /* 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; + if (this.locked) { + return true; + } - /* 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); - } - } + this.locked = true; - /* 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); - } + boolean success = true; + final List controllers = PolicyController.factory.inventory(); + for (final PolicyController controller : controllers) { + try { + success = controller.lock() && success; + } catch (final Exception e) { + logger.error("{}: cannot lock policy-controller {} because of {}", this, controller, e.getMessage(), e); + success = false; + } + } + + success = ProxyTopicEndpointManager.getInstance().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; } - /* Shutdown managed resources */ - PolicyController.factory.shutdown(); - TopicEndpoint.manager.shutdown(); - HttpServletServer.factory.destroy(); + @Override + public synchronized boolean unlock() { - // Stop the JMX listener + /* 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; + } - PdpJmxListener.stop(); + this.locked = false; - /* 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); - } - } - - exitThread.interrupt(); - logger.info("{}: normal termination" , this); - } - - @Override - public 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); - } + boolean success = true; + final List controllers = PolicyController.factory.inventory(); + for (final PolicyController controller : controllers) { + try { + success = controller.unlock() && success; + } catch (final Exception e) { + logger.error("{}: cannot unlock policy-controller {} because of {}", this, controller, e.getMessage(), + e); + success = false; + } + } + + success = ProxyTopicEndpointManager.getInstance().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; } - if (this.locked) - return true; - - this.locked = true; - - boolean success = true; - final List controllers = PolicyController.factory.inventory(); - for (final PolicyController controller : controllers) { - try { - success = controller.lock() && success; - } catch (final Exception e) { - logger.error("{}: cannot lock policy-controller {} because of {}", this, controller, - e.getMessage(), e); - success = false; - } + @Override + public boolean isLocked() { + return this.locked; } - 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); - } + @Override + public void removePolicyController(String name) { + PolicyController.factory.destroy(name); } - 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); - } + @Override + public void removePolicyController(PolicyController controller) { + PolicyController.factory.destroy(controller); } - if (!this.locked) - return true; - - this.locked = false; - - boolean success = true; - final List controllers = PolicyController.factory.inventory(); - for (final PolicyController controller : controllers) { - try { - success = controller.unlock() && success; - } catch (final Exception e) { - logger.error("{}: cannot unlock policy-controller {} because of {}", this, controller, - e.getMessage(), e); - success = false; - } + @JsonIgnore + @Override + public List getPolicyControllers() { + return PolicyController.factory.inventory(); } - 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); - } + @JsonProperty("controllers") + @Override + public List getPolicyControllerIds() { + final List controllerNames = new ArrayList<>(); + for (final PolicyController controller : PolicyController.factory.inventory()) { + controllerNames.add(controller.getName()); + } + return controllerNames; } - return success; - } - - @Override - public boolean isLocked() { - return this.locked; - } - - @Override - public void removePolicyController(String name) { - PolicyController.factory.destroy(name); - } - - @Override - public void removePolicyController(PolicyController controller) { - PolicyController.factory.destroy(controller); - } - - @JsonIgnore - @Override - public List getPolicyControllers() { - return PolicyController.factory.inventory(); - } - - @JsonProperty("controllers") - @Override - public List getPolicyControllerIds() { - final List controllerNames = new ArrayList<>(); - for (final PolicyController controller : PolicyController.factory.inventory()) { - controllerNames.add(controller.getName()); + @Override + @JsonIgnore + public Properties getProperties() { + return this.properties; } - return controllerNames; - } - - @Override - @JsonIgnore - public Properties getProperties() { - return this.properties; - } - - - @SuppressWarnings("unchecked") - @Override - public List getSources() { - return (List) this.sources; - } - - @SuppressWarnings("unchecked") - @Override - public List getSinks() { - return (List) this.sinks; - } - - @Override - public List getHttpServers() { - return this.httpServers; - } - - @Override - public List getFeatures() { - final List features = new ArrayList<>(); - for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - features.add(feature.getName()); + + + @SuppressWarnings("unchecked") + @Override + public List getSources() { + return (List) this.sources; } - return features; - } - - @JsonIgnore - @Override - public List getFeatureProviders() { - return PolicyEngineFeatureAPI.providers.getList(); - } - - @Override - public PolicyEngineFeatureAPI getFeatureProvider(String featureName) { - if (featureName == null || featureName.isEmpty()) - throw new IllegalArgumentException("A feature name must be provided"); - - for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { - if (feature.getName().equals(featureName)) - return feature; + + @SuppressWarnings("unchecked") + @Override + public List getSinks() { + return (List) this.sinks; } - 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 List getHttpServers() { + return this.httpServers; } - } - @Override - public boolean deliver(String topic, Object event) { + @Override + public List getFeatures() { + final List features = new ArrayList<>(); + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + features.add(feature.getName()); + } + return features; + } - /* - * Note this entry point is usually from the DRL - */ + @JsonIgnore + @Override + public List getFeatureProviders() { + return PolicyEngineFeatureAPI.providers.getList(); + } - if (topic == null || topic.isEmpty()) - throw new IllegalArgumentException(INVALID_TOPIC_MSG); + @Override + public PolicyEngineFeatureAPI getFeatureProvider(String featureName) { + if (featureName == null || featureName.isEmpty()) { + throw new IllegalArgumentException("A feature name must be provided"); + } - if (event == null) - throw new IllegalArgumentException(INVALID_EVENT_MSG); + for (final PolicyEngineFeatureAPI feature : PolicyEngineFeatureAPI.providers.getList()) { + if (feature.getName().equals(featureName)) { + return feature; + } + } - if (!this.isAlive()) - throw new IllegalStateException(ENGINE_STOPPED_MSG); + throw new IllegalArgumentException("Invalid Feature Name: " + featureName); + } - if (this.isLocked()) - throw new IllegalStateException(ENGINE_LOCKED_MSG); + @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); + } + } - final List topicSinks = TopicEndpoint.manager.getTopicSinks(topic); - if (topicSinks == null || topicSinks.isEmpty() || topicSinks.size() > 1) - throw new IllegalStateException( - "Cannot ensure correct delivery on topic " + topic + ": " + topicSinks); + @Override + public boolean deliver(String topic, Object event) { - return this.deliver(topicSinks.get(0).getTopicCommInfrastructure(), topic, event); - } + /* + * Note this entry point is usually from the DRL + */ - @Override - public boolean deliver(String busType, String topic, Object event) { + if (topic == null || topic.isEmpty()) { + throw new IllegalArgumentException(INVALID_TOPIC_MSG); + } - /* - * Note this entry point is usually from the DRL (one of the reasons busType is String. - */ + if (event == null) { + throw new IllegalArgumentException(INVALID_EVENT_MSG); + } - if (busType == null || busType.isEmpty()) - throw new IllegalArgumentException("Invalid Communication Infrastructure"); + if (!this.isAlive()) { + throw new IllegalStateException(ENGINE_STOPPED_MSG); + } - if (topic == null || topic.isEmpty()) - throw new IllegalArgumentException(INVALID_TOPIC_MSG); + if (this.isLocked()) { + throw new IllegalStateException(ENGINE_LOCKED_MSG); + } - if (event == null) - throw new IllegalArgumentException(INVALID_EVENT_MSG); + final List topicSinks = ProxyTopicEndpointManager.getInstance().getTopicSinks(topic); + if (topicSinks == null || topicSinks.isEmpty() || topicSinks.size() > 1) { + throw new IllegalStateException("Cannot ensure correct delivery on topic " + topic + ": " + topicSinks); + } - boolean valid = false; - for (final Topic.CommInfrastructure comm : Topic.CommInfrastructure.values()) { - if (comm.name().equals(busType)) { - valid = true; - } + return this.deliver(topicSinks.get(0).getTopicCommInfrastructure(), topic, event); } - if (!valid) - throw new IllegalArgumentException("Invalid Communication Infrastructure: " + busType); + @Override + public boolean deliver(String busType, String topic, Object event) { + /* + * Note this entry point is usually from the DRL (one of the reasons busType is String. + */ - if (!this.isAlive()) - throw new IllegalStateException(ENGINE_STOPPED_MSG); + if (busType == null || busType.isEmpty()) { + throw new IllegalArgumentException("Invalid Communication Infrastructure"); + } - if (this.isLocked()) - throw new IllegalStateException(ENGINE_LOCKED_MSG); + if (topic == null || topic.isEmpty()) { + throw new IllegalArgumentException(INVALID_TOPIC_MSG); + } + if (event == null) { + throw new IllegalArgumentException(INVALID_EVENT_MSG); + } - return this.deliver(Topic.CommInfrastructure.valueOf(busType), topic, event); - } + boolean valid = false; + for (final Topic.CommInfrastructure comm : Topic.CommInfrastructure.values()) { + if (comm.name().equals(busType)) { + valid = true; + } + } - @Override - public boolean deliver(Topic.CommInfrastructure busType, String topic, Object event) { + if (!valid) { + throw new IllegalArgumentException("Invalid Communication Infrastructure: " + busType); + } - if (topic == null || topic.isEmpty()) - throw new IllegalArgumentException(INVALID_TOPIC_MSG); - if (event == null) - throw new IllegalArgumentException(INVALID_EVENT_MSG); + if (!this.isAlive()) { + throw new IllegalStateException(ENGINE_STOPPED_MSG); + } - if (!this.isAlive()) - throw new IllegalStateException(ENGINE_STOPPED_MSG); + if (this.isLocked()) { + throw new IllegalStateException(ENGINE_LOCKED_MSG); + } - if (this.isLocked()) - throw new IllegalStateException(ENGINE_LOCKED_MSG); - /* - * 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) */ + return this.deliver(Topic.CommInfrastructure.valueOf(busType), topic, event); } - /* - * 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, Object event) { + + if (topic == null || topic.isEmpty()) { + throw new IllegalArgumentException(INVALID_TOPIC_MSG); + } + + if (event == null) { + throw new IllegalArgumentException(INVALID_EVENT_MSG); + } + + if (!this.isAlive()) { + throw new IllegalStateException(ENGINE_STOPPED_MSG); + } + + if (this.isLocked()) { + throw new IllegalStateException(ENGINE_LOCKED_MSG); + } + + /* + * 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) { + @Override + public boolean deliver(Topic.CommInfrastructure busType, String topic, String event) { - if (topic == null || topic.isEmpty()) - throw new IllegalArgumentException(INVALID_TOPIC_MSG); + if (topic == null || topic.isEmpty()) { + throw new IllegalArgumentException(INVALID_TOPIC_MSG); + } - if (event == null || event.isEmpty()) - throw new IllegalArgumentException(INVALID_EVENT_MSG); + if (event == null || event.isEmpty()) { + throw new IllegalArgumentException(INVALID_EVENT_MSG); + } - if (!this.isAlive()) - throw new IllegalStateException(ENGINE_STOPPED_MSG); + if (!this.isAlive()) { + throw new IllegalStateException(ENGINE_STOPPED_MSG); + } - if (this.isLocked()) - throw new IllegalStateException(ENGINE_LOCKED_MSG); + if (this.isLocked()) { + throw new IllegalStateException(ENGINE_LOCKED_MSG); + } - try { - final TopicSink sink = TopicEndpoint.manager.getTopicSink(busType, topic); + try { + final TopicSink sink = ProxyTopicEndpointManager.getInstance().getTopicSink(busType, topic); - if (sink == null) - throw new IllegalStateException("Inconsistent State: " + this); + if (sink == null) { + throw new IllegalStateException("Inconsistent State: " + this); + } - return sink.send(event); + 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); - } + } catch (final Exception e) { + logger.warn("{}: cannot deliver {} over {}:{} because of {}", this, event, busType, topic, e.getMessage(), + e); + throw 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); - } - } + @Override + public synchronized void activate() { - 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); - } + /* 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); - } + + @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 | 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); + } + } } - this.lock(); + public boolean controllerConfig(PdpdConfiguration config) { + /* only this one supported for now */ + final List configControllers = config.getControllers(); + if (configControllers == null || configControllers.isEmpty()) { + logger.info("No controller configuration provided: {}" + config); + return false; + } + + final List policyControllers = this.updatePolicyControllers(config.getControllers()); + + boolean success; - for (final PolicyController policyController : this.getPolicyControllers()) { - try { - policyController.stop(); - } catch (final Exception | LinkageError e) { - logger.error("{}: cannot deactivate (stop) policy-controller {} because of {}", this, - policyController, e.getMessage(), e); - } + if (policyControllers == null || policyControllers.isEmpty()) { + success = false; + } else if (policyControllers.size() == configControllers.size()) { + success = true; + } else { + success = false; + } + + return success; } - /* 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(); } - } - - public boolean controllerConfig(PdpdConfiguration config) { - /* only this one supported for now */ - final List configControllers = config.getControllers(); - if (configControllers == null || configControllers.isEmpty()) { - logger.info("No controller configuration provided: {}" + config); - return false; - } - - final List policyControllers = this.updatePolicyControllers(config.getControllers()); - - boolean success; - - if (policyControllers == null || policyControllers.isEmpty()) { - success = false; - } else if (policyControllers.size() == configControllers.size()) { - success = true; - } else { - success = false; - } - - return success; - } - - @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/java/org/onap/policy/drools/system/internal/AggregatedPolicyController.java b/policy-management/src/main/java/org/onap/policy/drools/system/internal/AggregatedPolicyController.java index ea631fae..41408258 100644 --- a/policy-management/src/main/java/org/onap/policy/drools/system/internal/AggregatedPolicyController.java +++ b/policy-management/src/main/java/org/onap/policy/drools/system/internal/AggregatedPolicyController.java @@ -20,604 +20,624 @@ package org.onap.policy.drools.system.internal; +import com.fasterxml.jackson.annotation.JsonIgnore; + import java.util.HashMap; import java.util.List; import java.util.Properties; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.onap.policy.common.endpoints.event.comm.Topic; +import org.onap.policy.common.endpoints.event.comm.TopicListener; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.common.endpoints.event.comm.TopicSource; +import org.onap.policy.common.endpoints.event.comm.impl.ProxyTopicEndpointManager; import org.onap.policy.drools.controller.DroolsController; -import org.onap.policy.drools.event.comm.Topic; -import org.onap.policy.drools.event.comm.TopicEndpoint; -import org.onap.policy.drools.event.comm.TopicListener; -import org.onap.policy.drools.event.comm.TopicSink; -import org.onap.policy.drools.event.comm.TopicSource; import org.onap.policy.drools.features.PolicyControllerFeatureAPI; import org.onap.policy.drools.persistence.SystemPersistence; -import org.onap.policy.drools.properties.PolicyProperties; +import org.onap.policy.drools.properties.DroolsProperties; import org.onap.policy.drools.protocol.configuration.DroolsConfiguration; import org.onap.policy.drools.system.PolicyController; - -import com.fasterxml.jackson.annotation.JsonIgnore; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * This implementation of the Policy Controller merely aggregates and tracks for - * management purposes all underlying resources that this controller depends upon. + * This implementation of the Policy Controller merely aggregates and tracks for management purposes + * all underlying resources that this controller depends upon. */ -public class AggregatedPolicyController implements PolicyController, - TopicListener { - - /** - * Logger - */ - private static Logger logger = LoggerFactory.getLogger(AggregatedPolicyController.class); - - /** - * identifier for this policy controller - */ - protected final String name; - - /** - * Abstracted Event Sources List regardless communication - * technology - */ - protected final List sources; - - /** - * Abstracted Event Sinks List regardless communication - * technology - */ - protected final List sinks; - - /** - * Mapping topics to sinks - */ - @JsonIgnore - protected final HashMap topic2Sinks = - new HashMap<>(); - - /** - * Is this Policy Controller running (alive) ? - * reflects invocation of start()/stop() only - */ - protected volatile boolean alive; - - /** - * Is this Policy Controller locked ? - * reflects if i/o controller related operations and start - * are permitted, - * more specifically: start(), deliver() and onTopicEvent(). - * It does not affect the ability to stop the - * underlying drools infrastructure - */ - protected volatile boolean locked; - - /** - * Policy Drools Controller - */ - protected volatile DroolsController droolsController; - - /** - * Properties used to initialize controller - */ - protected final Properties properties; - - /** - * Constructor version mainly used for bootstrapping at initialization time - * a policy engine controller - * - * @param name controller name - * @param properties - * - * @throws IllegalArgumentException when invalid arguments are provided - */ - public AggregatedPolicyController(String name, Properties properties) { - - this.name = name; - - /* - * 1. Register read topics with network infrastructure (ueb, dmaap, rest) - * 2. Register write topics with network infrastructure (ueb, dmaap, rest) - * 3. Register with drools infrastructure - */ - - // Create/Reuse Readers/Writers for all event sources endpoints - - this.sources = TopicEndpoint.manager.addTopicSources(properties); - this.sinks = TopicEndpoint.manager.addTopicSinks(properties); - - initDrools(properties); - initSinks(); - - /* persist new properties */ - SystemPersistence.manager.storeController(name, properties); - this.properties = properties; - } - - /** - * initialize drools layer - * @throws IllegalArgumentException if invalid parameters are passed in - */ - protected void initDrools(Properties properties) { - try { - // Register with drools infrastructure - this.droolsController = DroolsController.factory.build(properties, sources, sinks); - } catch (Exception | LinkageError e) { - logger.error("{}: cannot init-drools because of {}", this, e.getMessage(), e); - throw new IllegalArgumentException(e); - } - } - - /** - * initialize sinks - * @throws IllegalArgumentException if invalid parameters are passed in - */ - protected void initSinks() { - this.topic2Sinks.clear(); - for (TopicSink sink: sinks) { - this.topic2Sinks.put(sink.getTopic(), sink); - } - } - - /** - * {@inheritDoc} - */ - @Override - public boolean updateDrools(DroolsConfiguration newDroolsConfiguration) { - - DroolsConfiguration oldDroolsConfiguration = - new DroolsConfiguration(this.droolsController.getArtifactId(), - this.droolsController.getGroupId(), - this.droolsController.getVersion()); - - if (oldDroolsConfiguration.getGroupId().equalsIgnoreCase(newDroolsConfiguration.getGroupId()) && - oldDroolsConfiguration.getArtifactId().equalsIgnoreCase(newDroolsConfiguration.getArtifactId()) && - oldDroolsConfiguration.getVersion().equalsIgnoreCase(newDroolsConfiguration.getVersion())) { - logger.warn("{}: cannot update-drools: identical configuration {} vs {}", - this, oldDroolsConfiguration, newDroolsConfiguration); - return true; - } - - try { - /* Drools Controller created, update initialization properties for restarts */ - - this.properties.setProperty(PolicyProperties.RULES_GROUPID, newDroolsConfiguration.getGroupId()); - this.properties.setProperty(PolicyProperties.RULES_ARTIFACTID, newDroolsConfiguration.getArtifactId()); - this.properties.setProperty(PolicyProperties.RULES_VERSION, newDroolsConfiguration.getVersion()); - - SystemPersistence.manager.storeController(name, this.properties); - - this.initDrools(this.properties); - - /* set drools controller to current locked status */ - - if (this.isLocked()) - this.droolsController.lock(); - else - this.droolsController.unlock(); - - /* set drools controller to current alive status */ - - if (this.isAlive()) - this.droolsController.start(); - else - this.droolsController.stop(); - - } catch (IllegalArgumentException e) { - logger.error("{}: cannot update-drools because of {}", this, e.getMessage(), e); - return false; - } - - return true; - } - - /** - * {@inheritDoc} - */ - @Override - public String getName() { - return this.name; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean start() { - logger.info("{}: start", this); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.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); - } - } - - if (this.isLocked()) - throw new IllegalStateException("Policy Controller " + name + " is locked"); - - synchronized(this) { - if (this.alive) - return true; - - this.alive = true; - } - - boolean success = this.droolsController.start(); - - // register for events - - for (TopicSource source: sources) { - source.register(this); - } - - for (TopicSink sink: sinks) { - try { - sink.start(); - } catch (Exception e) { - logger.error("{}: cannot start {} because of {}", - this, sink, e.getMessage(), e); - } - } - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { - try { - if (feature.afterStart(this)) - return true; - } catch (Exception e) { - logger.error("{}: feature {} after-start failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - return success; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean stop() { - logger.info("{}: stop", this); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.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 locked state */ - - synchronized(this) { - if (!this.alive) - return true; - - this.alive = false; - } - - // 1. Stop registration - - for (TopicSource source: sources) { - source.unregister(this); - } - - boolean success = this.droolsController.stop(); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { - try { - if (feature.afterStop(this)) - return true; - } catch (Exception e) { - logger.error("{}: feature {} after-stop failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - return success; - } - - /** - * {@inheritDoc} - */ - @Override - public void shutdown() { - logger.info("{}: shutdown", this); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.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.stop(); - - DroolsController.factory.shutdown(this.droolsController); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.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); - } - } - } - - /** - * {@inheritDoc} - */ - @Override - public void halt() { - logger.info("{}: halt", this); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { - try { - if (feature.beforeHalt(this)) - return; - } catch (Exception e) { - logger.error("{}: feature {} before-halt failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - this.stop(); - DroolsController.factory.destroy(this.droolsController); - SystemPersistence.manager.deleteController(this.name); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { - try { - if (feature.afterHalt(this)) - return; - } catch (Exception e) { - logger.error("{}: feature {} after-halt failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - } - - /** - * {@inheritDoc} - */ - @Override - public void onTopicEvent(Topic.CommInfrastructure commType, - String topic, String event) { - - if (logger.isDebugEnabled()) - logger.debug("{}: event offered from {}:{}: {}", this, commType, topic, event); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { - try { - if (feature.beforeOffer(this, commType, topic, event)) - return; - } catch (Exception e) { - logger.error("{}: feature {} before-offer failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - if (this.locked) - return; - - if (!this.alive) - return; - - boolean success = this.droolsController.offer(topic, event); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { - try { - if (feature.afterOffer(this, commType, topic, event, success)) - return; - } catch (Exception e) { - logger.error("{}: feature {} after-offer failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - } - - /** - * {@inheritDoc} - */ - @Override - public boolean deliver(Topic.CommInfrastructure commType, - String topic, Object event) { - - if (logger.isDebugEnabled()) - logger.debug("{}: deliver event to {}:{}: {}", this, commType, topic, event); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { - try { - if (feature.beforeDeliver(this, commType, topic, event)) - return true; - } catch (Exception e) { - logger.error("{}: feature {} before-deliver failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - 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"); - - if (!this.topic2Sinks.containsKey(topic)) { - logger.warn("{}: cannot deliver event because the sink {}:{} is not registered: {}", - this, commType, topic, event); - throw new IllegalArgumentException("Unsuported topic " + topic + " for delivery"); - } - - boolean success = this.droolsController.deliver(this.topic2Sinks.get(topic), event); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { - try { - if (feature.afterDeliver(this, commType, topic, event, success)) - return success; - } catch (Exception e) { - logger.error("{}: feature {} after-deliver failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - return success; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isAlive() { - return this.alive; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean lock() { - logger.info("{}: lock", this); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.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); - } - } - - synchronized(this) { - if (this.locked) - return true; - - this.locked = true; - } - - // it does not affect associated sources/sinks, they are - // autonomous entities - - boolean success = this.droolsController.lock(); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { - try { - if (feature.afterLock(this)) - return true; - } catch (Exception e) { - logger.error("{}: feature {} after-lock failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - return success; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean unlock() { - - logger.info("{}: unlock", this); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.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); - } - } - - synchronized(this) { - if (!this.locked) - return true; - - this.locked = false; - } - - boolean success = this.droolsController.unlock(); - - for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { - try { - if (feature.afterUnlock(this)) - return true; - } catch (Exception e) { - logger.error("{}: feature {} after-unlock failure because of {}", - this, feature.getClass().getName(), e.getMessage(), e); - } - } - - return success; - } - - /** - * {@inheritDoc} - */ - @Override - public boolean isLocked() { - return this.locked; - } - - /** - * {@inheritDoc} - */ - @Override - public List getTopicSources() { - return this.sources; - } - - /** - * {@inheritDoc} - */ - @Override - public List getTopicSinks() { - return this.sinks; - } - - /** - * {@inheritDoc} - */ - @Override - public DroolsController getDrools() { - return this.droolsController; - } - - - /** - * {@inheritDoc} - */ - @Override - @JsonIgnore - public Properties getProperties() { - return this.properties; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append("AggregatedPolicyController [name=").append(name).append(", alive=").append(alive).append(", locked=").append(locked) - .append(", droolsController=").append(droolsController).append("]"); - return builder.toString(); - } +public class AggregatedPolicyController implements PolicyController, TopicListener { + + /** + * Logger + */ + private static Logger logger = LoggerFactory.getLogger(AggregatedPolicyController.class); + + /** + * identifier for this policy controller + */ + protected final String name; + + /** + * Abstracted Event Sources List regardless communication technology + */ + protected final List sources; + + /** + * Abstracted Event Sinks List regardless communication technology + */ + protected final List sinks; + + /** + * Mapping topics to sinks + */ + @JsonIgnore + protected final HashMap topic2Sinks = new HashMap<>(); + + /** + * Is this Policy Controller running (alive) ? reflects invocation of start()/stop() only + */ + protected volatile boolean alive; + + /** + * Is this Policy Controller locked ? reflects if i/o controller related operations and start + * are permitted, more specifically: start(), deliver() and onTopicEvent(). It does not affect + * the ability to stop the underlying drools infrastructure + */ + protected volatile boolean locked; + + /** + * Policy Drools Controller + */ + protected volatile DroolsController droolsController; + + /** + * Properties used to initialize controller + */ + protected final Properties properties; + + /** + * Constructor version mainly used for bootstrapping at initialization time a policy engine + * controller + * + * @param name controller name + * @param properties + * + * @throws IllegalArgumentException when invalid arguments are provided + */ + public AggregatedPolicyController(String name, Properties properties) { + + this.name = name; + + /* + * 1. Register read topics with network infrastructure (ueb, dmaap, rest) 2. Register write + * topics with network infrastructure (ueb, dmaap, rest) 3. Register with drools + * infrastructure + */ + + // Create/Reuse Readers/Writers for all event sources endpoints + + this.sources = ProxyTopicEndpointManager.getInstance().addTopicSources(properties); + this.sinks = ProxyTopicEndpointManager.getInstance().addTopicSinks(properties); + + initDrools(properties); + initSinks(); + + /* persist new properties */ + SystemPersistence.manager.storeController(name, properties); + this.properties = properties; + } + + /** + * initialize drools layer + * + * @throws IllegalArgumentException if invalid parameters are passed in + */ + protected void initDrools(Properties properties) { + try { + // Register with drools infrastructure + this.droolsController = DroolsController.factory.build(properties, sources, sinks); + } catch (Exception | LinkageError e) { + logger.error("{}: cannot init-drools because of {}", this, e.getMessage(), e); + throw new IllegalArgumentException(e); + } + } + + /** + * initialize sinks + * + * @throws IllegalArgumentException if invalid parameters are passed in + */ + protected void initSinks() { + this.topic2Sinks.clear(); + for (TopicSink sink : sinks) { + this.topic2Sinks.put(sink.getTopic(), sink); + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean updateDrools(DroolsConfiguration newDroolsConfiguration) { + + DroolsConfiguration oldDroolsConfiguration = new DroolsConfiguration(this.droolsController.getArtifactId(), + this.droolsController.getGroupId(), this.droolsController.getVersion()); + + if (oldDroolsConfiguration.getGroupId().equalsIgnoreCase(newDroolsConfiguration.getGroupId()) + && oldDroolsConfiguration.getArtifactId().equalsIgnoreCase(newDroolsConfiguration.getArtifactId()) + && oldDroolsConfiguration.getVersion().equalsIgnoreCase(newDroolsConfiguration.getVersion())) { + logger.warn("{}: cannot update-drools: identical configuration {} vs {}", this, oldDroolsConfiguration, + newDroolsConfiguration); + return true; + } + + try { + /* Drools Controller created, update initialization properties for restarts */ + + this.properties.setProperty(DroolsProperties.RULES_GROUPID, newDroolsConfiguration.getGroupId()); + this.properties.setProperty(DroolsProperties.RULES_ARTIFACTID, newDroolsConfiguration.getArtifactId()); + this.properties.setProperty(DroolsProperties.RULES_VERSION, newDroolsConfiguration.getVersion()); + + SystemPersistence.manager.storeController(name, this.properties); + + this.initDrools(this.properties); + + /* set drools controller to current locked status */ + + if (this.isLocked()) { + this.droolsController.lock(); + } else { + this.droolsController.unlock(); + } + + /* set drools controller to current alive status */ + + if (this.isAlive()) { + this.droolsController.start(); + } else { + this.droolsController.stop(); + } + + } catch (IllegalArgumentException e) { + logger.error("{}: cannot update-drools because of {}", this, e.getMessage(), e); + return false; + } + + return true; + } + + /** + * {@inheritDoc} + */ + @Override + public String getName() { + return this.name; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean start() { + logger.info("{}: start", this); + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.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); + } + } + + if (this.isLocked()) { + throw new IllegalStateException("Policy Controller " + name + " is locked"); + } + + synchronized (this) { + if (this.alive) { + return true; + } + + this.alive = true; + } + + boolean success = this.droolsController.start(); + + // register for events + + for (TopicSource source : sources) { + source.register(this); + } + + for (TopicSink sink : sinks) { + try { + sink.start(); + } catch (Exception e) { + logger.error("{}: cannot start {} because of {}", this, sink, e.getMessage(), e); + } + } + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { + try { + if (feature.afterStart(this)) { + return true; + } + } catch (Exception e) { + logger.error("{}: feature {} after-start failure because of {}", this, feature.getClass().getName(), + e.getMessage(), e); + } + } + + return success; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean stop() { + logger.info("{}: stop", this); + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.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 locked state */ + + synchronized (this) { + if (!this.alive) { + return true; + } + + this.alive = false; + } + + // 1. Stop registration + + for (TopicSource source : sources) { + source.unregister(this); + } + + boolean success = this.droolsController.stop(); + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { + try { + if (feature.afterStop(this)) { + return true; + } + } catch (Exception e) { + logger.error("{}: feature {} after-stop failure because of {}", this, feature.getClass().getName(), + e.getMessage(), e); + } + } + + return success; + } + + /** + * {@inheritDoc} + */ + @Override + public void shutdown() { + logger.info("{}: shutdown", this); + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.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.stop(); + + DroolsController.factory.shutdown(this.droolsController); + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.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); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void halt() { + logger.info("{}: halt", this); + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { + try { + if (feature.beforeHalt(this)) { + return; + } + } catch (Exception e) { + logger.error("{}: feature {} before-halt failure because of {}", this, feature.getClass().getName(), + e.getMessage(), e); + } + } + + this.stop(); + DroolsController.factory.destroy(this.droolsController); + SystemPersistence.manager.deleteController(this.name); + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { + try { + if (feature.afterHalt(this)) { + return; + } + } catch (Exception e) { + logger.error("{}: feature {} after-halt failure because of {}", this, feature.getClass().getName(), + e.getMessage(), e); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public void onTopicEvent(Topic.CommInfrastructure commType, String topic, String event) { + + if (logger.isDebugEnabled()) { + logger.debug("{}: event offered from {}:{}: {}", this, commType, topic, event); + } + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { + try { + if (feature.beforeOffer(this, commType, topic, event)) { + return; + } + } catch (Exception e) { + logger.error("{}: feature {} before-offer failure because of {}", this, feature.getClass().getName(), + e.getMessage(), e); + } + } + + if (this.locked) { + return; + } + + if (!this.alive) { + return; + } + + boolean success = this.droolsController.offer(topic, event); + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { + try { + if (feature.afterOffer(this, commType, topic, event, success)) { + return; + } + } catch (Exception e) { + logger.error("{}: feature {} after-offer failure because of {}", this, feature.getClass().getName(), + e.getMessage(), e); + } + } + } + + /** + * {@inheritDoc} + */ + @Override + public boolean deliver(Topic.CommInfrastructure commType, String topic, Object event) { + + if (logger.isDebugEnabled()) { + logger.debug("{}: deliver event to {}:{}: {}", this, commType, topic, event); + } + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { + try { + if (feature.beforeDeliver(this, commType, topic, event)) { + return true; + } + } catch (Exception e) { + logger.error("{}: feature {} before-deliver failure because of {}", this, feature.getClass().getName(), + e.getMessage(), e); + } + } + + 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"); + } + + if (!this.topic2Sinks.containsKey(topic)) { + logger.warn("{}: cannot deliver event because the sink {}:{} is not registered: {}", this, commType, topic, + event); + throw new IllegalArgumentException("Unsuported topic " + topic + " for delivery"); + } + + boolean success = this.droolsController.deliver(this.topic2Sinks.get(topic), event); + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { + try { + if (feature.afterDeliver(this, commType, topic, event, success)) { + return success; + } + } catch (Exception e) { + logger.error("{}: feature {} after-deliver failure because of {}", this, feature.getClass().getName(), + e.getMessage(), e); + } + } + + return success; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isAlive() { + return this.alive; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean lock() { + logger.info("{}: lock", this); + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.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); + } + } + + synchronized (this) { + if (this.locked) { + return true; + } + + this.locked = true; + } + + // it does not affect associated sources/sinks, they are + // autonomous entities + + boolean success = this.droolsController.lock(); + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { + try { + if (feature.afterLock(this)) { + return true; + } + } catch (Exception e) { + logger.error("{}: feature {} after-lock failure because of {}", this, feature.getClass().getName(), + e.getMessage(), e); + } + } + + return success; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean unlock() { + + logger.info("{}: unlock", this); + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.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); + } + } + + synchronized (this) { + if (!this.locked) { + return true; + } + + this.locked = false; + } + + boolean success = this.droolsController.unlock(); + + for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) { + try { + if (feature.afterUnlock(this)) { + return true; + } + } catch (Exception e) { + logger.error("{}: feature {} after-unlock failure because of {}", this, feature.getClass().getName(), + e.getMessage(), e); + } + } + + return success; + } + + /** + * {@inheritDoc} + */ + @Override + public boolean isLocked() { + return this.locked; + } + + /** + * {@inheritDoc} + */ + @Override + public List getTopicSources() { + return this.sources; + } + + /** + * {@inheritDoc} + */ + @Override + public List getTopicSinks() { + return this.sinks; + } + + /** + * {@inheritDoc} + */ + @Override + public DroolsController getDrools() { + return this.droolsController; + } + + + /** + * {@inheritDoc} + */ + @Override + @JsonIgnore + public Properties getProperties() { + return this.properties; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + builder.append("AggregatedPolicyController [name=").append(name).append(", alive=").append(alive) + .append(", locked=").append(locked).append(", droolsController=").append(droolsController).append("]"); + return builder.toString(); + } } -- cgit 1.2.3-korg