summaryrefslogtreecommitdiffstats
path: root/policy-management/src/main/java/org/openecomp/policy/drools/controller/DroolsControllerFactory.java
diff options
context:
space:
mode:
Diffstat (limited to 'policy-management/src/main/java/org/openecomp/policy/drools/controller/DroolsControllerFactory.java')
-rw-r--r--policy-management/src/main/java/org/openecomp/policy/drools/controller/DroolsControllerFactory.java540
1 files changed, 540 insertions, 0 deletions
diff --git a/policy-management/src/main/java/org/openecomp/policy/drools/controller/DroolsControllerFactory.java b/policy-management/src/main/java/org/openecomp/policy/drools/controller/DroolsControllerFactory.java
new file mode 100644
index 00000000..d94e773c
--- /dev/null
+++ b/policy-management/src/main/java/org/openecomp/policy/drools/controller/DroolsControllerFactory.java
@@ -0,0 +1,540 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * policy-management
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.openecomp.policy.drools.controller;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Properties;
+
+import org.openecomp.policy.drools.controller.internal.MavenDroolsController;
+import org.openecomp.policy.drools.controller.internal.NullDroolsController;
+import org.openecomp.policy.drools.event.comm.Topic;
+import org.openecomp.policy.drools.event.comm.Topic.CommInfrastructure;
+import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
+import org.openecomp.policy.common.logging.flexlogger.Logger;
+import org.openecomp.policy.drools.event.comm.TopicSource;
+import org.openecomp.policy.drools.event.comm.TopicSink;
+import org.openecomp.policy.drools.properties.PolicyProperties;
+import org.openecomp.policy.drools.protocol.coders.JsonProtocolFilter;
+import org.openecomp.policy.drools.protocol.coders.TopicCoderFilterConfiguration;
+import org.openecomp.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomGsonCoder;
+import org.openecomp.policy.drools.protocol.coders.TopicCoderFilterConfiguration.CustomJacksonCoder;
+import org.openecomp.policy.drools.protocol.coders.TopicCoderFilterConfiguration.PotentialCoderFilter;
+import org.openecomp.policy.drools.utils.Pair;
+
+/**
+ * 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
+ * @throws Exception Exception from Drools Libraries
+ */
+ public DroolsController build(Properties properties,
+ List<? extends TopicSource> eventSources,
+ List<? extends TopicSink> eventSinks)
+ throws IllegalArgumentException, LinkageError, Exception;
+
+ /**
+ * 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
+ * @throws Exception Exception from Drools Libraries
+ */
+ public DroolsController build(String groupId,
+ String artifactId,
+ String version,
+ List<TopicCoderFilterConfiguration> decoderConfigurations,
+ List<TopicCoderFilterConfiguration> encoderConfigurations)
+ throws IllegalArgumentException, LinkageError, Exception;
+
+ /**
+ * 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)
+ throws IllegalArgumentException;
+
+ /**
+ * returns the current inventory of Drools Controllers
+ *
+ * @return a list of Drools Controllers
+ */
+ public List<DroolsController> inventory();
+}
+
+/* ---------------- implementation -----------------*/
+
+/**
+ * Factory of Drools Controllers indexed by the Maven coordinates
+ */
+class IndexedDroolsControllerFactory implements DroolsControllerFactory {
+
+ /**
+ * logger
+ */
+ private static Logger logger = FlexLogger.getLogger(MavenDroolsController.class);
+
+ /**
+ * Policy Controller Name Index
+ */
+ protected HashMap<String, DroolsController> droolsControllers =
+ new HashMap<String, DroolsController>();
+
+ /**
+ * 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);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DroolsController build(Properties properties,
+ List<? extends TopicSource> eventSources,
+ List<? extends TopicSink> eventSinks)
+ throws IllegalArgumentException, LinkageError, Exception {
+
+ 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<TopicCoderFilterConfiguration>
+ topics2DecodedClasses2Filters = codersAndFilters(properties, eventSources);
+
+ List<TopicCoderFilterConfiguration>
+ 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<TopicCoderFilterConfiguration> codersAndFilters
+ (Properties properties, List<? extends Topic> topicEntities)
+ throws IllegalArgumentException {
+
+ String PROPERTY_TOPIC_ENTITY_PREFIX;
+
+ List<TopicCoderFilterConfiguration>
+ topics2DecodedClasses2Filters =
+ new ArrayList<TopicCoderFilterConfiguration>();
+
+ if (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) {
+ PROPERTY_TOPIC_ENTITY_PREFIX = PolicyProperties.PROPERTY_UEB_SOURCE_TOPICS + ".";
+ } else {
+ PROPERTY_TOPIC_ENTITY_PREFIX = PolicyProperties.PROPERTY_UEB_SINK_TOPICS + ".";
+ }
+ } else if (commInfra == CommInfrastructure.DMAAP) {
+ if (isSource) {
+ PROPERTY_TOPIC_ENTITY_PREFIX = PolicyProperties.PROPERTY_DMAAP_SOURCE_TOPICS + ".";
+ } else {
+ PROPERTY_TOPIC_ENTITY_PREFIX = PolicyProperties.PROPERTY_DMAAP_SINK_TOPICS + ".";
+ }
+ } 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
+ (PROPERTY_TOPIC_ENTITY_PREFIX +
+ 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) {
+ e.printStackTrace();
+ }
+ }
+
+ String customJackson = properties.getProperty
+ (PROPERTY_TOPIC_ENTITY_PREFIX +
+ 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) {
+ e.printStackTrace();
+ }
+ }
+
+ // 3. second the list of classes associated with each topic
+
+ String eventClasses =
+ properties.getProperty(PROPERTY_TOPIC_ENTITY_PREFIX + aTopic + PolicyProperties.PROPERTY_TOPIC_EVENTS_SUFFIX);
+
+ if (eventClasses == null || eventClasses.isEmpty()) {
+ // TODO warn
+ continue;
+ }
+
+ List<PotentialCoderFilter> classes2Filters = new ArrayList<PotentialCoderFilter>();
+
+ List<String> aTopicClasses =
+ new ArrayList<String>(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
+ (PROPERTY_TOPIC_ENTITY_PREFIX +
+ aTopic +
+ PolicyProperties.PROPERTY_TOPIC_EVENTS_SUFFIX +
+ "." + aClass +
+ PolicyProperties.PROPERTY_TOPIC_EVENTS_FILTER_SUFFIX);
+
+ List<Pair<String,String>> filters = new ArrayList<Pair<String,String>>();
+
+ 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<String> listOfFilters =
+ new ArrayList<String>(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<String,String>(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;
+ }
+
+ /**
+ * {@inheritDoc}
+ * @param decoderConfiguration
+ */
+ @Override
+ public DroolsController build(String newGroupId,
+ String newArtifactId,
+ String newVersion,
+ List<TopicCoderFilterConfiguration> decoderConfigurations,
+ List<TopicCoderFilterConfiguration> encoderConfigurations)
+ throws IllegalArgumentException, LinkageError, Exception {
+
+ if (newGroupId == null || newArtifactId == null || newVersion == null ||
+ newGroupId.isEmpty() || newArtifactId.isEmpty() || newVersion.isEmpty()) {
+ throw new IllegalArgumentException("Missing maven coordinates: " +
+ newGroupId + ":" + newArtifactId + ":" +
+ newVersion);
+ }
+
+ 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;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void destroy(DroolsController controller) throws IllegalArgumentException {
+ unmanage(controller);
+ controller.halt();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void destroy() {
+ List<DroolsController> 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) throws IllegalArgumentException {
+ 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);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void shutdown(DroolsController controller) throws IllegalArgumentException {
+ this.unmanage(controller);
+ controller.shutdown();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void shutdown() {
+ List<DroolsController> controllers = this.inventory();
+ for (DroolsController controller: controllers) {
+ controller.shutdown();
+ }
+
+ synchronized(this) {
+ this.droolsControllers.clear();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DroolsController get(String groupId,
+ String artifactId,
+ String version)
+ throws IllegalArgumentException, IllegalStateException {
+
+ 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");
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<DroolsController> inventory() {
+ List<DroolsController> controllers =
+ new ArrayList<DroolsController>(this.droolsControllers.values());
+ return controllers;
+ }
+
+}