aboutsummaryrefslogtreecommitdiffstats
path: root/policy-management/src/main/java/org/openecomp/policy/drools/system
diff options
context:
space:
mode:
Diffstat (limited to 'policy-management/src/main/java/org/openecomp/policy/drools/system')
-rw-r--r--policy-management/src/main/java/org/openecomp/policy/drools/system/Main.java131
-rw-r--r--policy-management/src/main/java/org/openecomp/policy/drools/system/PolicyController.java110
-rw-r--r--policy-management/src/main/java/org/openecomp/policy/drools/system/PolicyControllerFactory.java464
-rw-r--r--policy-management/src/main/java/org/openecomp/policy/drools/system/PolicyEngine.java1182
-rw-r--r--policy-management/src/main/java/org/openecomp/policy/drools/system/internal/AggregatedPolicyController.java462
5 files changed, 2349 insertions, 0 deletions
diff --git a/policy-management/src/main/java/org/openecomp/policy/drools/system/Main.java b/policy-management/src/main/java/org/openecomp/policy/drools/system/Main.java
new file mode 100644
index 00000000..108600b2
--- /dev/null
+++ b/policy-management/src/main/java/org/openecomp/policy/drools/system/Main.java
@@ -0,0 +1,131 @@
+/*-
+ * ============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.system;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Properties;
+
+import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
+import org.openecomp.policy.common.logging.flexlogger.Logger;
+import org.openecomp.policy.drools.core.PolicyContainer;
+import org.openecomp.policy.drools.persistence.SystemPersistence;
+import org.openecomp.policy.drools.utils.PropertyUtil;
+
+/**
+ * Programmatic entry point to the management layer
+ */
+public class Main {
+
+ /**
+ * logger
+ */
+ private static Logger logger = FlexLogger.getLogger(Main.class, true);
+
+ public static void main(String args[]) {
+
+ File configDir = new File(SystemPersistence.CONFIG_DIR_NAME);
+
+ if (!configDir.isDirectory()) {
+ throw new IllegalArgumentException
+ ("config directory: " + configDir.getAbsolutePath() +
+ " not found");
+ }
+
+
+ /* 0. Start the CORE layer first */
+
+ try {
+ PolicyContainer.globalInit(args);
+ } catch (Exception e) {
+ System.out.println("policy-core startup failed");
+ logger.warn("policy-core startup failed");
+ e.printStackTrace();
+ }
+
+ /* 1. Configure the Engine */
+
+ try {
+ Path policyEnginePath = Paths.get(configDir.toPath().toString(), SystemPersistence.PROPERTIES_FILE_ENGINE);
+ Properties properties = PropertyUtil.getProperties(policyEnginePath.toFile());
+ PolicyEngine.manager.configure(properties);
+ } catch (Exception e) {
+ String msg = "Policy Engine cannot be configured with properties: " + e.getMessage() + " : " + PolicyEngine.manager;
+ System.out.println(msg);
+ logger.warn(msg);
+ }
+
+ /* 2. Start the Engine with the basic services only (no Policy Controllers) */
+
+ try {
+ boolean success = PolicyEngine.manager.start();
+ if (!success) {
+ System.out.println("Policy Engine found some problems starting some components: " + PolicyEngine.manager);
+ logger.warn("Policy Engine is in an invalid state: " + PolicyEngine.manager);
+ }
+ } catch (IllegalStateException e) {
+ String msg = "Policy Engine is starting in an unexpected state: " + e.getMessage() + " : " + PolicyEngine.manager;
+ System.out.println(msg);
+ logger.warn(msg);
+ } catch (Exception e) {
+ String msg = "Unexpected Situation. Policy Engine cannot be started: " + e.getMessage() + " : " + PolicyEngine.manager;
+ System.out.println(msg);
+ e.printStackTrace();
+ System.exit(1);
+ }
+
+ /* 3. Create and start the controllers */
+
+ File[] controllerFiles = configDir.listFiles();
+ for (File config : controllerFiles) {
+
+ if (config.getName().endsWith(SystemPersistence.PROPERTIES_FILE_CONTROLLER_SUFFIX)) {
+ int idxSuffix =
+ config.getName().indexOf(SystemPersistence.PROPERTIES_FILE_CONTROLLER_SUFFIX);
+ int lastIdxSuffix =
+ config.getName().lastIndexOf(SystemPersistence.PROPERTIES_FILE_CONTROLLER_SUFFIX);
+ if (idxSuffix != lastIdxSuffix) {
+ throw new IllegalArgumentException
+ ("Improper naming of controller properties file: " +
+ "Expected <controller-name>" +
+ SystemPersistence.PROPERTIES_FILE_CONTROLLER_SUFFIX);
+ }
+
+ String name =
+ config.getName().substring(0, lastIdxSuffix);
+ try {
+ Properties properties = PropertyUtil.getProperties(config);
+ PolicyController controller = PolicyEngine.manager.createPolicyController(name, properties);
+ controller.start();
+ } catch (Exception e) {
+ System.out.println("can't instantiate Policy Controller based on properties file: " +
+ config + " with message " + e.getMessage());
+ e.printStackTrace();
+ } catch (LinkageError le) {
+ System.out.println("can't instantiate Policy Controller based on properties file: " +
+ config + ". A Linkage Error has been encountered: " + le.getMessage());
+ le.printStackTrace();
+ }
+ }
+ }
+ }
+}
diff --git a/policy-management/src/main/java/org/openecomp/policy/drools/system/PolicyController.java b/policy-management/src/main/java/org/openecomp/policy/drools/system/PolicyController.java
new file mode 100644
index 00000000..543fd0e3
--- /dev/null
+++ b/policy-management/src/main/java/org/openecomp/policy/drools/system/PolicyController.java
@@ -0,0 +1,110 @@
+/*-
+ * ============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.system;
+
+import java.util.List;
+import java.util.Properties;
+
+import org.openecomp.policy.drools.controller.DroolsController;
+import org.openecomp.policy.drools.event.comm.TopicSource;
+import org.openecomp.policy.drools.event.comm.Topic.CommInfrastructure;
+import org.openecomp.policy.drools.event.comm.TopicSink;
+import org.openecomp.policy.drools.properties.Lockable;
+import org.openecomp.policy.drools.properties.Startable;
+import org.openecomp.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
+ *
+ */
+public interface PolicyController extends Startable, Lockable {
+
+ /**
+ * name of this Policy Controller
+ */
+ public String getName();
+
+ /**
+ * Get the topic readers of interest for this controller
+ */
+ public List<? extends TopicSource> getTopicSources();
+
+ /**
+ * Get the topic readers of interest for this controller
+ */
+ public List<? extends TopicSink> 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 Initialization Properties
+ */
+ public Properties getInitializationProperties();
+
+ /**
+ * 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)
+ throws IllegalArgumentException, IllegalStateException,
+ UnsupportedOperationException;
+
+ /**
+ * halts and permanently releases all resources
+ * @throws IllegalStateException
+ */
+ public void halt() throws IllegalStateException;
+
+ /**
+ * Factory that tracks and manages Policy Controllers
+ */
+ public static PolicyControllerFactory factory =
+ new IndexedPolicyControllerFactory();
+
+}
diff --git a/policy-management/src/main/java/org/openecomp/policy/drools/system/PolicyControllerFactory.java b/policy-management/src/main/java/org/openecomp/policy/drools/system/PolicyControllerFactory.java
new file mode 100644
index 00000000..e105bbb9
--- /dev/null
+++ b/policy-management/src/main/java/org/openecomp/policy/drools/system/PolicyControllerFactory.java
@@ -0,0 +1,464 @@
+/*-
+ * ============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.system;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Properties;
+
+import org.openecomp.policy.drools.controller.DroolsController;
+import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
+import org.openecomp.policy.common.logging.flexlogger.Logger;
+import org.openecomp.policy.drools.protocol.configuration.DroolsConfiguration;
+import org.openecomp.policy.drools.system.internal.AggregatedPolicyController;
+
+/**
+ * Policy Controller Factory to manage controller creation, destruction,
+ * and retrieval for management interfaces
+ */
+public interface PolicyControllerFactory {
+ /**
+ * Build a controller from a properties file
+ *
+ * @param name the global name of this controller
+ * @param properties input parameters in form of properties for controller
+ * initialization.
+ *
+ * @return a Policy Controller
+ *
+ * @throws IllegalArgumentException invalid values provided in properties
+ */
+ public PolicyController build(String name, Properties properties)
+ throws IllegalArgumentException;
+
+ /**
+ * patches (updates) a controller from a critical configuration update.
+ *
+ * @param name
+ * @param configController
+ *
+ * @return a Policy Controller
+ */
+ public PolicyController patch(String name, DroolsConfiguration configController);
+
+ /**
+ * rebuilds (updates) a controller from a configuration update.
+ *
+ * @param controller
+ * @param configController
+ *
+ * @return a Policy Controller
+ */
+ public PolicyController patch(PolicyController controller,
+ DroolsConfiguration configController);
+
+ /**
+ * get PolicyController from DroolsController
+ *
+ * @param droolsController
+ * @return
+ * @throws IllegalArgumentException
+ * @throws IllegalStateException
+ */
+ public PolicyController get(DroolsController droolsController)
+ throws IllegalArgumentException, IllegalStateException;
+
+ /**
+ * Makes the Policy Controller identified by controllerName not operational, but
+ * does not delete its associated data
+ *
+ * @param controllerName name of the policy controller
+ * @throws IllegalArgumentException invalid arguments
+ */
+ public void shutdown(String controllerName) throws IllegalArgumentException;;
+
+ /**
+ * Makes the Policy Controller identified by controller not operational, but
+ * does not delete its associated data
+ *
+ * @param controller a Policy Controller
+ * @throws IllegalArgumentException invalid arguments
+ */
+ public void shutdown(PolicyController controller) throws IllegalArgumentException;
+
+ /**
+ * Releases all Policy Controllers from operation
+ */
+ public void shutdown();
+
+ /**
+ * Destroys this Policy Controller
+ *
+ * @param controllerName name of the policy controller
+ * @throws IllegalArgumentException invalid arguments
+ */
+ public void destroy(String controllerName) throws IllegalArgumentException;;
+
+ /**
+ * Destroys this Policy Controller
+ *
+ * @param controller a Policy Controller
+ * @throws IllegalArgumentException invalid arguments
+ */
+ public void destroy(PolicyController controller) throws IllegalArgumentException;
+
+ /**
+ * Releases all Policy Controller resources
+ */
+ public void destroy();
+
+ /**
+ * gets the Policy Controller identified by its name
+ *
+ * @param policyControllerName
+ * @return
+ * @throws IllegalArgumentException
+ * @throws IllegalStateException
+ */
+ public PolicyController get(String policyControllerName)
+ throws IllegalArgumentException, IllegalStateException;
+
+ /**
+ * gets the Policy Controller identified by group and artifact ids
+ *
+ * @param groupId group id
+ * @param artifactId artifact id
+ * @return
+ * @throws IllegalArgumentException
+ * @throws IllegalStateException
+ */
+ public PolicyController get(String groupId, String artifactId)
+ throws IllegalArgumentException, IllegalStateException;
+
+ /**
+ * returns the current inventory of Policy Controllers
+ *
+ * @return a list of Policy Controllers
+ */
+ public List<PolicyController> inventory();
+}
+
+/**
+ * Factory of Policy Controllers indexed by the name of the Policy Controller
+ */
+class IndexedPolicyControllerFactory implements PolicyControllerFactory {
+ // get an instance of logger
+ private static Logger logger = FlexLogger.getLogger(PolicyControllerFactory.class);
+
+ /**
+ * Policy Controller Name Index
+ */
+ protected HashMap<String,PolicyController> policyControllers =
+ new HashMap<String,PolicyController>();
+
+ /**
+ * Group/Artifact Ids Index
+ */
+ protected HashMap<String,PolicyController> coordinates2Controller =
+ new HashMap<String,PolicyController>();
+
+ /**
+ * produces key for indexing controller names
+ *
+ * @param group group id
+ * @param artifactId artifact id
+ * @return index key
+ */
+ protected String toKey(String groupId, String artifactId) {
+ return groupId + ":" + artifactId;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public synchronized PolicyController build(String name, Properties properties)
+ throws IllegalArgumentException {
+
+ if (this.policyControllers.containsKey(name)) {
+ return this.policyControllers.get(name);
+ }
+
+ /* A PolicyController does not exist */
+
+ PolicyController controller =
+ new AggregatedPolicyController(name, properties);
+
+ String coordinates = toKey(controller.getDrools().getGroupId(),
+ controller.getDrools().getArtifactId());
+
+ this.policyControllers.put(name, controller);
+
+
+ if (controller.getDrools().isBrained())
+ this.coordinates2Controller.put(coordinates, controller);
+
+ return controller;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public synchronized PolicyController patch(String name, DroolsConfiguration droolsConfig)
+ throws IllegalArgumentException {
+
+ if (name == null || name.isEmpty() || !this.policyControllers.containsKey(name)) {
+ throw new IllegalArgumentException("Invalid " + name);
+ }
+
+ if (droolsConfig == null)
+ throw new IllegalArgumentException("Invalid Drools Configuration");
+
+ PolicyController controller = this.get(name);
+
+ if (controller == null) {
+ logger.warn("A POLICY CONTROLLER of name " + name +
+ "does not exist for patch operation: " + droolsConfig);
+
+ throw new IllegalArgumentException("Not a valid controller of name " + name);
+ }
+
+ this.patch(controller, droolsConfig);
+
+ if (logger.isInfoEnabled())
+ logger.info("UPDATED drools configuration: " + droolsConfig + " on " + this);
+
+ return controller;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PolicyController patch(PolicyController controller, DroolsConfiguration droolsConfig)
+ throws IllegalArgumentException {
+
+ if (controller == null)
+ throw new IllegalArgumentException("Not a valid controller: null");
+
+ if (!controller.updateDrools(droolsConfig)) {
+ logger.warn("Cannot update drools configuration: " + droolsConfig + " on " + this);
+ throw new IllegalArgumentException("Cannot update drools configuration Drools Configuration");
+ }
+
+ if (logger.isInfoEnabled())
+ logger.info("UPDATED drools configuration: " + droolsConfig + " on " + this);
+
+ String coordinates = toKey(controller.getDrools().getGroupId(),
+ controller.getDrools().getArtifactId());
+
+ if (controller.getDrools().isBrained())
+ this.coordinates2Controller.put(coordinates, controller);
+
+ return controller;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void shutdown(String controllerName) throws IllegalArgumentException {
+
+ if (controllerName == null || controllerName.isEmpty()) {
+ throw new IllegalArgumentException("Invalid " + controllerName);
+ }
+
+ synchronized(this) {
+ if (!this.policyControllers.containsKey(controllerName)) {
+ return;
+ }
+
+ PolicyController controller = this.policyControllers.get(controllerName);
+ this.shutdown(controller);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void shutdown(PolicyController controller) throws IllegalArgumentException {
+ this.unmanage(controller);
+ controller.shutdown();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void shutdown() {
+ List<PolicyController> controllers = this.inventory();
+ for (PolicyController controller: controllers) {
+ controller.shutdown();
+ }
+
+ synchronized(this) {
+ this.policyControllers.clear();
+ this.coordinates2Controller.clear();
+ }
+ }
+
+ /**
+ * unmanage the controller
+ *
+ * @param controller
+ * @return
+ * @throws IllegalArgumentException
+ */
+ protected void unmanage(PolicyController controller) throws IllegalArgumentException {
+ if (controller == null) {
+ throw new IllegalArgumentException("Invalid Controller");
+ }
+
+ synchronized(this) {
+ if (!this.policyControllers.containsKey(controller.getName())) {
+ return;
+ }
+ controller = this.policyControllers.remove(controller.getName());
+
+ String coordinates = toKey(controller.getDrools().getGroupId(),
+ controller.getDrools().getArtifactId());
+ this.coordinates2Controller.remove(coordinates);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void destroy(String controllerName) throws IllegalArgumentException {
+
+ if (controllerName == null || controllerName.isEmpty()) {
+ throw new IllegalArgumentException("Invalid " + controllerName);
+ }
+
+ synchronized(this) {
+ if (!this.policyControllers.containsKey(controllerName)) {
+ return;
+ }
+
+ PolicyController controller = this.policyControllers.get(controllerName);
+ this.destroy(controller);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void destroy(PolicyController controller) throws IllegalArgumentException {
+ this.unmanage(controller);
+ controller.halt();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void destroy() {
+ List<PolicyController> controllers = this.inventory();
+ for (PolicyController controller: controllers) {
+ controller.halt();
+ }
+
+ synchronized(this) {
+ this.policyControllers.clear();
+ this.coordinates2Controller.clear();
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PolicyController get(String name) throws IllegalArgumentException, IllegalStateException {
+
+ if (name == null || name.isEmpty()) {
+ throw new IllegalArgumentException("Invalid " + name);
+ }
+
+ synchronized(this) {
+ if (this.policyControllers.containsKey(name)) {
+ return this.policyControllers.get(name);
+ } else {
+ throw new IllegalArgumentException("Invalid " + name);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PolicyController get(String groupId, String artifactId)
+ throws IllegalArgumentException, IllegalStateException {
+
+ if (groupId == null || groupId.isEmpty() ||
+ artifactId == null || artifactId.isEmpty()) {
+ throw new IllegalArgumentException("Invalid group/artifact ids");
+ }
+
+ synchronized(this) {
+ String key = toKey(groupId,artifactId);
+ if (this.coordinates2Controller.containsKey(key)) {
+ return this.coordinates2Controller.get(key);
+ } else {
+ throw new IllegalArgumentException("Invalid " + key);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PolicyController get(DroolsController droolsController)
+ throws IllegalArgumentException, IllegalStateException {
+
+ if (droolsController == null) {
+ throw new IllegalArgumentException("No Drools Controller provided");
+ }
+
+ synchronized(this) {
+ String key = toKey(droolsController.getGroupId(), droolsController.getArtifactId());
+ if (this.coordinates2Controller.containsKey(key)) {
+ return this.coordinates2Controller.get(key);
+ } else {
+ logger.error("Drools Controller not associated with Policy Controller " + droolsController + ":" + this);
+ throw new IllegalStateException("Drools Controller not associated with Policy Controller " + droolsController + ":" + this);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<PolicyController> inventory() {
+ List<PolicyController> controllers =
+ new ArrayList<PolicyController>(this.policyControllers.values());
+ return controllers;
+ }
+
+}
diff --git a/policy-management/src/main/java/org/openecomp/policy/drools/system/PolicyEngine.java b/policy-management/src/main/java/org/openecomp/policy/drools/system/PolicyEngine.java
new file mode 100644
index 00000000..33f2a098
--- /dev/null
+++ b/policy-management/src/main/java/org/openecomp/policy/drools/system/PolicyEngine.java
@@ -0,0 +1,1182 @@
+/*-
+ * ============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.system;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.openecomp.policy.common.logging.eelf.MessageCodes;
+import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
+import org.openecomp.policy.common.logging.flexlogger.Logger;
+import org.openecomp.policy.drools.controller.DroolsController;
+import org.openecomp.policy.drools.core.FeatureAPI;
+import org.openecomp.policy.drools.core.jmx.PdpJmxListener;
+import org.openecomp.policy.drools.event.comm.Topic;
+import org.openecomp.policy.drools.event.comm.Topic.CommInfrastructure;
+import org.openecomp.policy.drools.event.comm.TopicEndpoint;
+import org.openecomp.policy.drools.event.comm.TopicListener;
+import org.openecomp.policy.drools.event.comm.TopicSink;
+import org.openecomp.policy.drools.event.comm.TopicSource;
+import org.openecomp.policy.drools.http.server.HttpServletServer;
+import org.openecomp.policy.drools.persistence.SystemPersistence;
+import org.openecomp.policy.drools.properties.Lockable;
+import org.openecomp.policy.drools.properties.PolicyProperties;
+import org.openecomp.policy.drools.properties.Startable;
+import org.openecomp.policy.drools.protocol.coders.EventProtocolCoder;
+import org.openecomp.policy.drools.protocol.configuration.ControllerConfiguration;
+import org.openecomp.policy.drools.protocol.configuration.PdpdConfiguration;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.google.gson.Gson;
+import com.google.gson.GsonBuilder;
+
+/**
+ * Policy Engine, the top abstraction for the Drools PDP Policy Engine.
+ * It abstracts away a Drools PDP Engine from management purposes.
+ * This is the best place to looking at the code from a top down approach.
+ * Other managed entities can be obtained from the PolicyEngine, hierarchically.
+ * <br>
+ * PolicyEngine 1 --- * PolicyController 1 --- 1 DroolsController 1 --- 1 PolicyContainer 1 --- * PolicySession
+ * <br>
+ * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 UebTopicReader
+ * <br>
+ * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 DmaapTopicReader
+ * <br>
+ * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 DmaapTopicWriter
+ * <br>
+ * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicReader 1 --- 1 RestTopicReader
+ * <br>
+ * PolicyEngine 1 --- 1 TopicEndpointManager 1 -- * TopicWriter 1 --- 1 RestTopicWriter
+ * <br>
+ * PolicyEngine 1 --- 1 ManagementServer
+ */
+public interface PolicyEngine extends Startable, Lockable, TopicListener {
+
+ /**
+ * Default Config Server Port
+ */
+ public static final int CONFIG_SERVER_DEFAULT_PORT = 9696;
+
+ /**
+ * Default Config Server Hostname
+ */
+ public static final String CONFIG_SERVER_DEFAULT_HOST = "localhost";
+
+ /**
+ * 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) throws IllegalArgumentException;
+
+ /**
+ * registers a new Policy Controller with the Policy Engine
+ * initialized per properties.
+ *
+ * @param controller name
+ * @param properties properties to initialize the Policy Controller
+ * @throws IllegalArgumentException when invalid or insufficient
+ * properties are provided
+ * @throws IllegalStateException when the engine is in a state where
+ * this operation is not permitted.
+ * @return the newly instantiated Policy Controller
+ */
+ public PolicyController createPolicyController(String name, Properties properties)
+ throws IllegalArgumentException, IllegalStateException;
+
+ /**
+ * 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)
+ throws IllegalArgumentException, IllegalStateException;
+
+ /**
+ * updates a set of Policy Controllers with configuration information
+ *
+ * @param configuration
+ * @return
+ * @throws IllegalArgumentException
+ * @throws IllegalStateException
+ */
+ public List<PolicyController> updatePolicyControllers(List<ControllerConfiguration> configuration)
+ throws IllegalArgumentException, IllegalStateException;
+
+ /**
+ * 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)
+ throws Exception;
+
+ /**
+ * removes the Policy Controller identified by its name from the Policy Engine
+ *
+ * @param name name of the Policy Controller
+ * @return the removed Policy Controller
+ */
+ public void removePolicyController(String name);
+
+ /**
+ * removes a Policy Controller from the Policy Engine
+ * @param controller the Policy Controller to remove from the Policy Engine
+ */
+ public void removePolicyController(PolicyController controller);
+
+ /**
+ * returns a list of the available Policy Controllers
+ *
+ * @return list of Policy Controllers
+ */
+ public List<PolicyController> getPolicyControllers();
+
+ /**
+ * get unmanaged sources
+ *
+ * @return unmanaged sources
+ */
+ public List<TopicSource> getSources();
+
+ /**
+ * get unmanaged sinks
+ *
+ * @return unmanaged sinks
+ */
+ public List<TopicSink> getSinks();
+
+ /**
+ * get unmmanaged http servers list
+ * @return http servers
+ */
+ public List<HttpServletServer> getHttpServers();
+
+ /**
+ * get properties configuration
+ *
+ * @return properties objects
+ */
+ public Properties getProperties();
+
+ /**
+ * Attempts the dispatching of an "event" object
+ *
+ * @param topic topic
+ * @param event the event object to send
+ *
+ * @return true if successful, false if a failure has occurred.
+ * @throws IllegalArgumentException when invalid or insufficient
+ * properties are provided
+ * @throws IllegalStateException when the engine is in a state where
+ * this operation is not permitted (ie. locked or stopped).
+ */
+ public boolean deliver(String topic, Object event)
+ throws IllegalArgumentException, IllegalStateException;
+
+ /**
+ * Attempts the dispatching of an "event" object over communication
+ * infrastructure "busType"
+ *
+ * @param eventBus Communication infrastructure identifier
+ * @param topic topic
+ * @param event the event object to send
+ *
+ * @return true if successful, false if a failure has occurred.
+ * @throws IllegalArgumentException when invalid or insufficient
+ * properties are provided
+ * @throws IllegalStateException when the engine is in a state where
+ * this operation is not permitted (ie. locked or stopped).
+ * @throws UnsupportedOperationException when the engine cannot deliver due
+ * to the functionality missing (ie. communication infrastructure
+ * not supported.
+ */
+ public boolean deliver(String busType, String topic, Object event)
+ throws IllegalArgumentException, IllegalStateException,
+ UnsupportedOperationException;
+
+ /**
+ * Attempts the dispatching of an "event" object over communication
+ * infrastructure "busType"
+ *
+ * @param eventBus Communication infrastructure enum
+ * @param topic topic
+ * @param event the event object to send
+ *
+ * @return true if successful, false if a failure has occurred.
+ * @throws IllegalArgumentException when invalid or insufficient
+ * properties are provided
+ * @throws IllegalStateException when the engine is in a state where
+ * this operation is not permitted (ie. locked or stopped).
+ * @throws UnsupportedOperationException when the engine cannot deliver due
+ * to the functionality missing (ie. communication infrastructure
+ * not supported.
+ */
+ public boolean deliver(CommInfrastructure busType, String topic, Object event)
+ throws IllegalArgumentException, IllegalStateException,
+ UnsupportedOperationException;
+
+ /**
+ * Attempts delivering of an String over communication
+ * infrastructure "busType"
+ *
+ * @param eventBus Communication infrastructure identifier
+ * @param topic topic
+ * @param event the event object to send
+ *
+ * @return true if successful, false if a failure has occurred.
+ * @throws IllegalArgumentException when invalid or insufficient
+ * properties are provided
+ * @throws IllegalStateException when the engine is in a state where
+ * this operation is not permitted (ie. locked or stopped).
+ * @throws UnsupportedOperationException when the engine cannot deliver due
+ * to the functionality missing (ie. communication infrastructure
+ * not supported.
+ */
+ public boolean deliver(CommInfrastructure busType, String topic,
+ String event)
+ throws IllegalArgumentException, IllegalStateException,
+ UnsupportedOperationException;
+
+ /**
+ * Invoked when the host goes into the active state.
+ */
+ public void activate();
+
+ /**
+ * Invoked when the host goes into the standby state.
+ */
+ public void deactivate();
+
+ /**
+ * get policy controller names
+ *
+ * @return list of controller names
+ */
+ public List<String> getControllers();
+
+ /**
+ * Policy Engine Manager
+ */
+ public final static PolicyEngine manager = new PolicyEngineManager();
+}
+
+/**
+ * Policy Engine Manager Implementation
+ */
+class PolicyEngineManager implements PolicyEngine {
+ /**
+ * logger
+ */
+ private static Logger logger = FlexLogger.getLogger(PolicyEngineManager.class);
+
+ /**
+ * Is the Policy Engine running?
+ */
+ protected boolean alive = false;
+
+ /**
+ * Is the engine locked?
+ */
+ protected boolean locked = false;
+
+ /**
+ * Properties used to initialize the engine
+ */
+ protected Properties properties;
+
+ /**
+ * Policy Engine Sources
+ */
+ protected List<? extends TopicSource> sources = new ArrayList<>();
+
+ /**
+ * Policy Engine Sinks
+ */
+ protected List<? extends TopicSink> sinks = new ArrayList<>();
+
+ /**
+ * Policy Engine HTTP Servers
+ */
+ protected List<HttpServletServer> httpServers = new ArrayList<HttpServletServer>();
+
+ protected Gson decoder = new GsonBuilder().disableHtmlEscaping().create();
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void configure(Properties properties) throws IllegalArgumentException {
+
+ if (properties == null) {
+ logger.warn("No properties provided");
+ throw new IllegalArgumentException("No properties provided");
+ }
+
+ this.properties = properties;
+
+ try {
+ this.sources = TopicEndpoint.manager.addTopicSources(properties);
+ for (TopicSource source: this.sources) {
+ source.register(this);
+ }
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, "PolicyEngine", "configure");
+ }
+
+ try {
+ this.sinks = TopicEndpoint.manager.addTopicSinks(properties);
+ } catch (IllegalArgumentException e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, "PolicyEngine", "configure");
+ }
+
+ try {
+ this.httpServers = HttpServletServer.factory.build(properties);
+ } catch (IllegalArgumentException e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, "PolicyEngine", "configure");
+ }
+
+ return;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PolicyController createPolicyController(String name, Properties properties)
+ throws IllegalArgumentException, IllegalStateException {
+
+ // check if a PROPERTY_CONTROLLER_NAME property is present
+ // if so, override the given name
+
+ String propertyControllerName = properties.getProperty(PolicyProperties.PROPERTY_CONTROLLER_NAME);
+ if (propertyControllerName != null && !propertyControllerName.isEmpty()) {
+ if (!propertyControllerName.equals(name)) {
+ throw new IllegalStateException("Proposed name (" + name +
+ ") and properties name (" + propertyControllerName +
+ ") don't match");
+ }
+ name = propertyControllerName;
+ }
+
+ // feature hook
+ for (FeatureAPI feature : FeatureAPI.impl.getList()) {
+ feature.beforeCreateController(name, properties);
+ }
+
+ PolicyController controller = PolicyController.factory.build(name, properties);
+ if (this.isLocked())
+ controller.lock();
+
+ // feature hook
+ for (FeatureAPI feature : FeatureAPI.impl.getList()) {
+ // NOTE: this should change to the actual controller object
+ feature.afterCreateController(name);
+ }
+
+ return controller;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean configure(PdpdConfiguration config) throws IllegalArgumentException, IllegalStateException {
+
+ if (config == null)
+ throw new IllegalArgumentException("No configuration provided");
+
+ String entity = config.getEntity();
+
+ switch (entity) {
+ case PdpdConfiguration.CONFIG_ENTITY_CONTROLLER:
+ /* only this one supported for now */
+ List<ControllerConfiguration> configControllers = config.getControllers();
+ if (configControllers == null || configControllers.isEmpty()) {
+ if (logger.isInfoEnabled())
+ logger.info("No controller configuration provided: " + config);
+ return false;
+ }
+ List<PolicyController> policyControllers = this.updatePolicyControllers(config.getControllers());
+ if (policyControllers == null || policyControllers.isEmpty())
+ return false;
+ else if (policyControllers.size() == configControllers.size())
+ return true;
+
+ return false;
+ default:
+ String msg = "Configuration Entity is not supported: " + entity;
+ logger.warn(msg);
+ throw new IllegalArgumentException(msg);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<PolicyController> updatePolicyControllers(List<ControllerConfiguration> configControllers)
+ throws IllegalArgumentException, IllegalStateException {
+
+ List<PolicyController> policyControllers = new ArrayList<PolicyController>();
+ if (configControllers == null || configControllers.isEmpty()) {
+ if (logger.isInfoEnabled())
+ logger.info("No controller configuration provided: " + configControllers);
+ return policyControllers;
+ }
+
+ for (ControllerConfiguration configController: configControllers) {
+ try {
+ PolicyController policyController = this.updatePolicyController(configController);
+ policyControllers.add(policyController);
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, "PolicyEngine", "updatePolicyControllers");
+ }
+ }
+
+ return policyControllers;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public PolicyController updatePolicyController(ControllerConfiguration configController)
+ throws Exception {
+
+ if (configController == null)
+ throw new IllegalArgumentException("No controller configuration has been provided");
+
+ String controllerName = configController.getName();
+ if (controllerName == null || controllerName.isEmpty()) {
+ logger.warn("controller-name must be provided");
+ throw new IllegalArgumentException("No controller configuration has been provided");
+ }
+
+ PolicyController policyController = null;
+ try {
+ String operation = configController.getOperation();
+ if (operation == null || operation.isEmpty()) {
+ logger.warn("operation must be provided");
+ throw new IllegalArgumentException("operation must be provided");
+ }
+
+ try {
+ policyController = PolicyController.factory.get(controllerName);
+ } catch (IllegalArgumentException e) {
+ // not found
+ logger.warn("Policy Controller " + controllerName + " not found");
+ }
+
+ if (policyController == null) {
+
+ if (operation.equalsIgnoreCase(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_LOCK) ||
+ operation.equalsIgnoreCase(ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UNLOCK)) {
+ throw new IllegalArgumentException(controllerName + " is not available for operation " + operation);
+ }
+
+ /* Recovery case */
+
+ logger.warn("controller " + controllerName + " does not exist. " +
+ "Attempting recovery from disk");
+
+ Properties properties =
+ SystemPersistence.manager.getControllerProperties(controllerName);
+
+ /*
+ * returned properties cannot be null (per implementation)
+ * assert (properties != null)
+ */
+
+ if (properties == null) {
+ throw new IllegalArgumentException(controllerName + " is invalid");
+ }
+
+ logger.warn("controller " + controllerName + " being recovered. " +
+ "Reset controller's bad maven coordinates to brainless");
+
+ /*
+ * try to bring up bad controller in brainless mode,
+ * after having it working, apply the new create/update operation.
+ */
+ properties.setProperty(PolicyProperties.RULES_GROUPID, DroolsController.NO_GROUP_ID);
+ properties.setProperty(PolicyProperties.RULES_ARTIFACTID, DroolsController.NO_ARTIFACT_ID);
+ properties.setProperty(PolicyProperties.RULES_VERSION, DroolsController.NO_VERSION);
+
+ policyController = PolicyEngine.manager.createPolicyController(controllerName, properties);
+
+ /* fall through to do brain update operation*/
+ }
+
+ switch (operation) {
+ case ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_CREATE:
+ PolicyController.factory.patch(policyController, configController.getDrools());
+ break;
+ case ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UPDATE:
+ policyController.unlock();
+ PolicyController.factory.patch(policyController, configController.getDrools());
+ break;
+ case ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_LOCK:
+ policyController.lock();
+ break;
+ case ControllerConfiguration.CONFIG_CONTROLLER_OPERATION_UNLOCK:
+ policyController.unlock();
+ break;
+ default:
+ String msg = "Controller Operation Configuration is not supported: " +
+ operation + " for " + controllerName;
+ logger.warn(msg);
+ throw new IllegalArgumentException(msg);
+ }
+
+ return policyController;
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, "PolicyEngine", "updatePolicyController " + e.getMessage());
+ throw e;
+ } catch (LinkageError e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, "PolicyEngine", "updatePolicyController " + e.getMessage());
+ throw new IllegalStateException(e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean start() throws IllegalStateException {
+
+ if (this.locked) {
+ throw new IllegalStateException("Engine is locked");
+ }
+
+ // Features hook
+ for (FeatureAPI feature : FeatureAPI.impl.getList()) {
+ feature.beforeStartEngine();
+ }
+
+ synchronized(this) {
+ this.alive = true;
+ }
+
+ boolean success = true;
+
+ /* Start Policy Engine exclusively-owned (unmanaged) http servers */
+
+ for (HttpServletServer httpServer: this.httpServers) {
+ try {
+ if (!httpServer.start())
+ success = false;
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, httpServer.toString(), this.toString());
+ }
+ }
+ /* Start Policy Engine exclusively-owned (unmanaged) sources */
+
+ for (TopicSource source: this.sources) {
+ try {
+ if (!source.start())
+ success = false;
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, source.toString(), this.toString());
+ }
+ }
+
+ /* Start Policy Engine owned (unmanaged) sinks */
+
+ for (TopicSink sink: this.sinks) {
+ try {
+ if (!sink.start())
+ success = false;
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, sink.toString(), this.toString());
+ }
+ }
+
+ /* Start Policy Controllers */
+
+ List<PolicyController> controllers = PolicyController.factory.inventory();
+ for (PolicyController controller : controllers) {
+ try {
+ if (!controller.start())
+ success = false;
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, controller.toString(), this.toString());
+ success = false;
+ }
+ }
+
+ /* Start managed Topic Endpoints */
+
+ try {
+ if (!TopicEndpoint.manager.start())
+ success = false;
+ } catch (IllegalStateException e) {
+ String msg = "Topic Endpoint Manager is in an invalid state: " + e.getMessage() + " : " + this;
+ logger.warn(msg);
+ }
+
+
+ // Start the JMX listener
+
+ PdpJmxListener.start();
+
+ // Features hook
+ for (FeatureAPI feature : FeatureAPI.impl.getList()) {
+ feature.afterStartEngine();
+ }
+
+ return success;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean stop() {
+
+ /* stop regardless of the lock state */
+
+ synchronized(this) {
+ if (!this.alive)
+ return true;
+
+ this.alive = false;
+ }
+
+ boolean success = true;
+ List<PolicyController> controllers = PolicyController.factory.inventory();
+ for (PolicyController controller : controllers) {
+ try {
+ if (!controller.stop())
+ success = false;
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, controller.toString(), this.toString());
+ success = false;
+ }
+ }
+
+ /* Stop Policy Engine owned (unmanaged) sources */
+ for (TopicSource source: this.sources) {
+ try {
+ if (!source.stop())
+ success = false;
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, source.toString(), this.toString());
+ }
+ }
+
+ /* Stop Policy Engine owned (unmanaged) sinks */
+ for (TopicSink sink: this.sinks) {
+ try {
+ if (!sink.stop())
+ success = false;
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, sink.toString(), this.toString());
+ }
+ }
+
+ /* stop all managed topics sources and sinks */
+ if (!TopicEndpoint.manager.stop())
+ success = false;
+
+ /* stop all unmanaged http servers */
+ for (HttpServletServer httpServer: this.httpServers) {
+ try {
+ if (!httpServer.stop())
+ success = false;
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, httpServer.toString(), this.toString());
+ }
+ }
+
+ return success;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void shutdown() throws IllegalStateException {
+
+ synchronized(this) {
+ this.alive = false;
+ }
+
+ // feature hook reporting that the Policy Engine is being shut down
+ for (FeatureAPI feature : FeatureAPI.impl.getList()) {
+ feature.beforeShutdownEngine();
+ }
+
+ /* Shutdown Policy Engine owned (unmanaged) sources */
+ for (TopicSource source: this.sources) {
+ try {
+ source.shutdown();
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, source.toString(), this.toString());
+ }
+ }
+
+ /* Shutdown Policy Engine owned (unmanaged) sinks */
+ for (TopicSink sink: this.sinks) {
+ try {
+ sink.shutdown();
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, sink.toString(), this.toString());
+ }
+ }
+
+ /* Shutdown managed resources */
+ PolicyController.factory.shutdown();
+ TopicEndpoint.manager.shutdown();
+ HttpServletServer.factory.destroy();
+
+ // Stop the JMX listener
+
+ PdpJmxListener.stop();
+
+ // feature hook reporting that the Policy Engine has being shut down
+ for (FeatureAPI feature : FeatureAPI.impl.getList()) {
+ feature.afterShutdownEngine();
+ }
+
+ new Thread(new Runnable() {
+ @Override
+ public void run() {
+ try {
+ Thread.sleep(5000L);
+ } catch (InterruptedException e) {
+ logger.warn("InterruptedException while shutting down management server: " + this.toString());
+ }
+
+ /* shutdown all unmanaged http servers */
+ for (HttpServletServer httpServer: getHttpServers()) {
+ try {
+ httpServer.shutdown();
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, httpServer.toString(), this.toString());
+ }
+ }
+
+ try {
+ Thread.sleep(5000L);
+ } catch (InterruptedException e) {
+ logger.warn("InterruptedException while shutting down management server: " + this.toString());
+ }
+
+ System.exit(0);
+ }
+ }).start();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isAlive() {
+ return this.alive;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean lock() {
+
+ synchronized(this) {
+ if (this.locked)
+ return true;
+
+ this.locked = true;
+ }
+
+ boolean success = true;
+ List<PolicyController> controllers = PolicyController.factory.inventory();
+ for (PolicyController controller : controllers) {
+ try {
+ success = controller.lock() && success;
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, controller.toString(), this.toString());
+ success = false;
+ }
+ }
+
+ success = TopicEndpoint.manager.lock();
+ return success;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean unlock() {
+ synchronized(this) {
+ if (!this.locked)
+ return true;
+
+ this.locked = false;
+ }
+
+ boolean success = true;
+ List<PolicyController> controllers = PolicyController.factory.inventory();
+ for (PolicyController controller : controllers) {
+ try {
+ success = controller.unlock() && success;
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, controller.toString(), this.toString());
+ success = false;
+ }
+ }
+
+ success = TopicEndpoint.manager.unlock();
+ return success;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isLocked() {
+ return this.locked;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removePolicyController(String name) {
+ PolicyController.factory.destroy(name);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void removePolicyController(PolicyController controller) {
+ PolicyController.factory.destroy(controller);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @JsonIgnore
+ @Override
+ public List<PolicyController> getPolicyControllers() {
+ return PolicyController.factory.inventory();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<String> getControllers() {
+ List<String> controllerNames = new ArrayList<String>();
+ for (PolicyController controller: PolicyController.factory.inventory()) {
+ controllerNames.add(controller.getName());
+ }
+ return controllerNames;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Properties getProperties() {
+ return this.properties;
+ }
+
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public List<TopicSource> getSources() {
+ return (List<TopicSource>) this.sources;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public List<TopicSink> getSinks() {
+ return (List<TopicSink>) this.sinks;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<HttpServletServer> getHttpServers() {
+ return this.httpServers;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean onTopicEvent(CommInfrastructure commType, String topic, String event) {
+ /* configuration request */
+ try {
+ PdpdConfiguration configuration = this.decoder.fromJson(event, PdpdConfiguration.class);
+ this.configure(configuration);
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, "CONFIGURATION ERROR IN PDP-D POLICY ENGINE: "+ event + ":" + e.getMessage() + ":" + this);
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean deliver(String topic, Object event)
+ throws IllegalArgumentException, IllegalStateException {
+
+ /*
+ * Note this entry point is usually from the DRL
+ */
+
+ if (topic == null || topic.isEmpty())
+ throw new IllegalArgumentException("Invalid Topic");
+
+ if (event == null)
+ throw new IllegalArgumentException("Invalid Event");
+
+ if (!this.isAlive())
+ throw new IllegalStateException("Policy Engine is stopped");
+
+ if (this.isLocked())
+ throw new IllegalStateException("Policy Engine is locked");
+
+ List<? extends TopicSink> sinks =
+ TopicEndpoint.manager.getTopicSinks(topic);
+ if (sinks == null || sinks.isEmpty() || sinks.size() > 1)
+ throw new IllegalStateException
+ ("Cannot ensure correct delivery on topic " + topic + ": " + sinks);
+
+ return this.deliver(sinks.get(0).getTopicCommInfrastructure(),
+ topic, event);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean deliver(String busType, String topic, Object event)
+ throws IllegalArgumentException, IllegalStateException,
+ UnsupportedOperationException {
+
+ /*
+ * Note this entry point is usually from the DRL (one of the reasons
+ * busType is String.
+ */
+
+ if (busType == null || busType.isEmpty())
+ throw new IllegalArgumentException
+ ("Invalid Communication Infrastructure");
+
+ if (topic == null || topic.isEmpty())
+ throw new IllegalArgumentException("Invalid Topic");
+
+ if (event == null)
+ throw new IllegalArgumentException("Invalid Event");
+
+ boolean valid = false;
+ for (Topic.CommInfrastructure comm: Topic.CommInfrastructure.values()) {
+ if (comm.name().equals(busType)) {
+ valid = true;
+ }
+ }
+
+ if (!valid)
+ throw new IllegalArgumentException
+ ("Invalid Communication Infrastructure: " + busType);
+
+
+ if (!this.isAlive())
+ throw new IllegalStateException("Policy Engine is stopped");
+
+ if (this.isLocked())
+ throw new IllegalStateException("Policy Engine is locked");
+
+
+ return this.deliver(Topic.CommInfrastructure.valueOf(busType),
+ topic, event);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean deliver(Topic.CommInfrastructure busType,
+ String topic, Object event)
+ throws IllegalArgumentException, IllegalStateException,
+ UnsupportedOperationException {
+
+ if (topic == null || topic.isEmpty())
+ throw new IllegalArgumentException("Invalid Topic");
+
+ if (event == null)
+ throw new IllegalArgumentException("Invalid Event");
+
+ if (!this.isAlive())
+ throw new IllegalStateException("Policy Engine is stopped");
+
+ if (this.isLocked())
+ throw new IllegalStateException("Policy Engine is locked");
+
+ /* Try to send through the controller, this is the
+ * preferred way, since it may want to apply additional
+ * processing
+ */
+ try {
+ DroolsController droolsController =
+ EventProtocolCoder.manager.getDroolsController(topic, event);
+ PolicyController controller = PolicyController.factory.get(droolsController);
+ if (controller != null)
+ return controller.deliver(busType, topic, event);
+ } catch (Exception e) {
+ logger.warn(MessageCodes.EXCEPTION_ERROR, e,
+ busType + ":" + topic + " :" + event, this.toString());
+ /* continue (try without routing through the controller) */
+ }
+
+ /*
+ * cannot route through the controller, send directly through
+ * the topic sink
+ */
+ try {
+ String json = EventProtocolCoder.manager.encode(topic, event);
+ return this.deliver(busType, topic, json);
+
+ } catch (Exception e) {
+ logger.warn(MessageCodes.EXCEPTION_ERROR, e,
+ busType + ":" + topic + " :" + event, this.toString());
+ throw e;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean deliver(Topic.CommInfrastructure busType,
+ String topic, String event)
+ throws IllegalArgumentException, IllegalStateException,
+ UnsupportedOperationException {
+
+ if (topic == null || topic.isEmpty())
+ throw new IllegalArgumentException("Invalid Topic");
+
+ if (event == null || event.isEmpty())
+ throw new IllegalArgumentException("Invalid Event");
+
+ if (!this.isAlive())
+ throw new IllegalStateException("Policy Engine is stopped");
+
+ if (this.isLocked())
+ throw new IllegalStateException("Policy Engine is locked");
+
+ try {
+ TopicSink sink =
+ TopicEndpoint.manager.getTopicSink
+ (busType, topic);
+
+ if (sink == null)
+ throw new IllegalStateException("Inconsistent State: " + this);
+
+ return sink.send(event);
+
+ } catch (Exception e) {
+ logger.warn(MessageCodes.EXCEPTION_ERROR, e,
+ busType + ":" + topic + " :" + event, this.toString());
+ throw e;
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public synchronized void activate() {
+
+ // activate 'policy-management'
+ for (PolicyController policyController : getPolicyControllers()) {
+ try {
+ policyController.unlock();
+ policyController.start();
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, "PolicyEngine.activate: cannot start " +
+ policyController + " because of " + e.getMessage());
+ } catch (LinkageError e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, "PolicyEngine.activate: cannot start " +
+ policyController + " because of " + e.getMessage());
+ }
+ }
+
+ this.unlock();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public synchronized void deactivate() {
+
+ this.lock();
+
+ for (PolicyController policyController : getPolicyControllers()) {
+ try {
+ policyController.stop();
+ } catch (Exception e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, "PolicyEngine.deactivate: cannot stop " +
+ policyController + " because of " + e.getMessage());
+ } catch (LinkageError e) {
+ logger.error(MessageCodes.EXCEPTION_ERROR, e, "PolicyEngine.deactivate: cannot start " +
+ policyController + " because of " + e.getMessage());
+ }
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("PolicyEngineManager [alive=").append(alive).append(", locked=").append(locked).append("]");
+ return builder.toString();
+ }
+
+}
+
+
diff --git a/policy-management/src/main/java/org/openecomp/policy/drools/system/internal/AggregatedPolicyController.java b/policy-management/src/main/java/org/openecomp/policy/drools/system/internal/AggregatedPolicyController.java
new file mode 100644
index 00000000..96f9e5bf
--- /dev/null
+++ b/policy-management/src/main/java/org/openecomp/policy/drools/system/internal/AggregatedPolicyController.java
@@ -0,0 +1,462 @@
+/*-
+ * ============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.system.internal;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Properties;
+
+import org.openecomp.policy.drools.controller.DroolsController;
+import org.openecomp.policy.drools.event.comm.Topic;
+import org.openecomp.policy.drools.event.comm.TopicEndpoint;
+import org.openecomp.policy.drools.event.comm.TopicListener;
+import org.openecomp.policy.drools.event.comm.TopicSink;
+import org.openecomp.policy.drools.event.comm.TopicSource;
+import org.openecomp.policy.common.logging.flexlogger.FlexLogger;
+import org.openecomp.policy.common.logging.flexlogger.Logger;
+import org.openecomp.policy.drools.persistence.SystemPersistence;
+import org.openecomp.policy.drools.properties.PolicyProperties;
+import org.openecomp.policy.drools.protocol.configuration.DroolsConfiguration;
+import org.openecomp.policy.drools.system.PolicyController;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/**
+ * 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 = FlexLogger.getLogger(AggregatedPolicyController.class);
+
+ /**
+ * identifier for this policy controller
+ */
+ protected final String name;
+
+ /**
+ * Abstracted Event Sources List regardless communication
+ * technology
+ */
+ protected final List<? extends TopicSource> sources;
+
+ /**
+ * Abstracted Event Sinks List regardless communication
+ * technology
+ */
+ protected final List<? extends TopicSink> sinks;
+
+ /**
+ * Mapping topics to sinks
+ */
+ @JsonIgnore
+ protected final HashMap<String, TopicSink> topic2Sinks =
+ new HashMap<String, TopicSink>();
+
+ /**
+ * 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)
+ throws IllegalArgumentException {
+
+ 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) throws IllegalArgumentException {
+ try {
+ // Register with drools infrastructure
+ this.droolsController = DroolsController.factory.build(properties, sources, sinks);
+ } catch (Exception | LinkageError e) {
+ logger.error("BUILD-INIT-DROOLS: " + e.getMessage());
+ e.printStackTrace();
+
+ // throw back exception as input properties cause problems
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * initialize sinks
+ * @throws IllegalArgumentException if invalid parameters are passed in
+ */
+ protected void initSinks() throws IllegalArgumentException {
+ 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("UPDATE-DROOLS: nothing to do: identical configuration: " + 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.warn("INIT-DROOLS: " + e.getMessage());
+ e.printStackTrace();
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public String getName() {
+ return this.name;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean start() throws IllegalStateException {
+ if (logger.isInfoEnabled())
+ logger.info("START: " + this);
+
+ 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.warn("can't start sink: " + sink + " because of " + e.getMessage());
+ e.printStackTrace();
+ }
+ }
+
+ return success;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean stop() {
+
+ logger.info("STOP: " + this);
+
+ /* 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();
+ return success;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void shutdown() throws IllegalStateException {
+ if (logger.isInfoEnabled())
+ logger.info(this + "SHUTDOWN");
+
+ this.stop();
+
+ DroolsController.factory.shutdown(this.droolsController);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public void halt() throws IllegalStateException {
+ if (logger.isInfoEnabled())
+ logger.info(this + "HALT");
+
+ this.stop();
+ DroolsController.factory.destroy(this.droolsController);
+ SystemPersistence.manager.deleteController(this.name);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean onTopicEvent(Topic.CommInfrastructure commType,
+ String topic, String event) {
+
+ logger.info("EVENT NOTIFICATION: " + commType + ":" + topic + ":" + event + " INTO " + this);
+
+ if (this.locked)
+ return false;
+
+ if (!this.alive)
+ return true;
+
+ return this.droolsController.offer(topic, event);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean deliver(Topic.CommInfrastructure commType,
+ String topic, Object event)
+ throws IllegalArgumentException, IllegalStateException,
+ UnsupportedOperationException {
+
+ logger.info("DELIVER: " + commType + ":" + topic + ":" + event + " FROM " + this);
+
+ 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.error("UNDELIVERED: " + commType + ":" + topic + ":" + event + " FROM " + this);
+ throw new IllegalArgumentException
+ ("Unsuported topic " + topic + " for delivery");
+ }
+
+ return this.droolsController.deliver
+ (this.topic2Sinks.get(topic), event);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isAlive() {
+ return this.alive;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean lock() {
+ logger.info("LOCK: " + this);
+
+ synchronized(this) {
+ if (this.locked)
+ return true;
+
+ this.locked = true;
+ }
+
+ // it does not affect associated sources/sinks, they are
+ // autonomous entities
+
+ return this.droolsController.lock();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean unlock() {
+ logger.info("UNLOCK: " + this);
+
+ synchronized(this) {
+ if (!this.locked)
+ return true;
+
+ this.locked = false;
+ }
+
+ return this.droolsController.unlock();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public boolean isLocked() {
+ return this.locked;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<? extends TopicSource> getTopicSources() {
+ return this.sources;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public List<? extends TopicSink> getTopicSinks() {
+ return this.sinks;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public DroolsController getDrools() {
+ return this.droolsController;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("AggregatedPolicyController [name=").append(name).append(", sources=").append(sources)
+ .append(", sinks=").append(sinks).append(", alive=").append(alive).append(", locked=").append(locked)
+ .append(", droolsController=").append(droolsController).append("]");
+ return builder.toString();
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ @Override
+ public Properties getInitializationProperties() {
+ return this.properties;
+ }
+
+}
+