2  * ============LICENSE_START=======================================================
 
   4  * ================================================================================
 
   5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
 
   6  * ================================================================================
 
   7  * Licensed under the Apache License, Version 2.0 (the "License");
 
   8  * you may not use this file except in compliance with the License.
 
   9  * You may obtain a copy of the License at
 
  11  *      http://www.apache.org/licenses/LICENSE-2.0
 
  13  * Unless required by applicable law or agreed to in writing, software
 
  14  * distributed under the License is distributed on an "AS IS" BASIS,
 
  15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
  16  * See the License for the specific language governing permissions and
 
  17  * limitations under the License.
 
  18  * ============LICENSE_END=========================================================
 
  21 package org.onap.policy.drools.system.internal;
 
  23 import com.fasterxml.jackson.annotation.JsonIgnore;
 
  25 import java.util.HashMap;
 
  26 import java.util.List;
 
  27 import java.util.Properties;
 
  29 import org.onap.policy.common.endpoints.event.comm.Topic;
 
  30 import org.onap.policy.common.endpoints.event.comm.TopicEndpoint;
 
  31 import org.onap.policy.common.endpoints.event.comm.TopicListener;
 
  32 import org.onap.policy.common.endpoints.event.comm.TopicSink;
 
  33 import org.onap.policy.common.endpoints.event.comm.TopicSource;
 
  34 import org.onap.policy.drools.controller.DroolsController;
 
  35 import org.onap.policy.drools.features.PolicyControllerFeatureAPI;
 
  36 import org.onap.policy.drools.persistence.SystemPersistence;
 
  37 import org.onap.policy.drools.properties.DroolsProperties;
 
  38 import org.onap.policy.drools.protocol.configuration.DroolsConfiguration;
 
  39 import org.onap.policy.drools.system.PolicyController;
 
  40 import org.slf4j.Logger;
 
  41 import org.slf4j.LoggerFactory;
 
  44  * This implementation of the Policy Controller merely aggregates and tracks for management purposes
 
  45  * all underlying resources that this controller depends upon.
 
  47 public class AggregatedPolicyController implements PolicyController, TopicListener {
 
  52     private static final Logger logger = LoggerFactory.getLogger(AggregatedPolicyController.class);
 
  55      * identifier for this policy controller
 
  57     private final String name;
 
  60      * Abstracted Event Sources List regardless communication technology
 
  62     private final List<? extends TopicSource> sources;
 
  65      * Abstracted Event Sinks List regardless communication technology
 
  67     private final List<? extends TopicSink> sinks;
 
  70      * Mapping topics to sinks
 
  73     private final HashMap<String, TopicSink> topic2Sinks = new HashMap<>();
 
  76      * Is this Policy Controller running (alive) ? reflects invocation of start()/stop() only
 
  78     private volatile boolean alive;
 
  81      * Is this Policy Controller locked ? reflects if i/o controller related operations and start
 
  82      * are permitted, more specifically: start(), deliver() and onTopicEvent(). It does not affect
 
  83      * the ability to stop the underlying drools infrastructure
 
  85     private volatile boolean locked;
 
  88      * Policy Drools Controller
 
  90     private volatile DroolsController droolsController;
 
  93      * Properties used to initialize controller
 
  95     private final Properties properties;
 
  98      * Constructor version mainly used for bootstrapping at initialization time a policy engine
 
 101      * @param name controller name
 
 104      * @throws IllegalArgumentException when invalid arguments are provided
 
 106     public AggregatedPolicyController(String name, Properties properties) {
 
 111          * 1. Register read topics with network infrastructure (ueb, dmaap, rest) 2. Register write
 
 112          * topics with network infrastructure (ueb, dmaap, rest) 3. Register with drools
 
 116         // Create/Reuse Readers/Writers for all event sources endpoints
 
 118         this.sources = TopicEndpoint.manager.addTopicSources(properties);
 
 119         this.sinks = TopicEndpoint.manager.addTopicSinks(properties);
 
 121         initDrools(properties);
 
 124         /* persist new properties */
 
 125         SystemPersistence.manager.storeController(name, properties);
 
 126         this.properties = properties;
 
 130      * initialize drools layer
 
 132      * @throws IllegalArgumentException if invalid parameters are passed in
 
 134     private void initDrools(Properties properties) {
 
 136             // Register with drools infrastructure
 
 137             this.droolsController = DroolsController.factory.build(properties, sources, sinks);
 
 138         } catch (Exception | LinkageError e) {
 
 139             logger.error("{}: cannot init-drools because of {}", this, e.getMessage(), e);
 
 140             throw new IllegalArgumentException(e);
 
 147      * @throws IllegalArgumentException if invalid parameters are passed in
 
 149     private void initSinks() {
 
 150         this.topic2Sinks.clear();
 
 151         for (TopicSink sink : sinks) {
 
 152             this.topic2Sinks.put(sink.getTopic(), sink);
 
 160     public boolean updateDrools(DroolsConfiguration newDroolsConfiguration) {
 
 162         DroolsConfiguration oldDroolsConfiguration = new DroolsConfiguration(this.droolsController.getArtifactId(),
 
 163                 this.droolsController.getGroupId(), this.droolsController.getVersion());
 
 165         if (oldDroolsConfiguration.getGroupId().equalsIgnoreCase(newDroolsConfiguration.getGroupId())
 
 166                 && oldDroolsConfiguration.getArtifactId().equalsIgnoreCase(newDroolsConfiguration.getArtifactId())
 
 167                 && oldDroolsConfiguration.getVersion().equalsIgnoreCase(newDroolsConfiguration.getVersion())) {
 
 168             logger.warn("{}: cannot update-drools: identical configuration {} vs {}", this, oldDroolsConfiguration,
 
 169                     newDroolsConfiguration);
 
 174             /* Drools Controller created, update initialization properties for restarts */
 
 176             this.properties.setProperty(DroolsProperties.RULES_GROUPID, newDroolsConfiguration.getGroupId());
 
 177             this.properties.setProperty(DroolsProperties.RULES_ARTIFACTID, newDroolsConfiguration.getArtifactId());
 
 178             this.properties.setProperty(DroolsProperties.RULES_VERSION, newDroolsConfiguration.getVersion());
 
 180             SystemPersistence.manager.storeController(name, this.properties);
 
 182             this.initDrools(this.properties);
 
 184             /* set drools controller to current locked status */
 
 186             if (this.isLocked()) {
 
 187                 this.droolsController.lock();
 
 189                 this.droolsController.unlock();
 
 192             /* set drools controller to current alive status */
 
 194             if (this.isAlive()) {
 
 195                 this.droolsController.start();
 
 197                 this.droolsController.stop();
 
 200         } catch (IllegalArgumentException e) {
 
 201             logger.error("{}: cannot update-drools because of {}", this, e.getMessage(), e);
 
 212     public String getName() {
 
 220     public boolean start() {
 
 221         logger.info("{}: start", this);
 
 223         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 225                 if (feature.beforeStart(this)) {
 
 228             } catch (Exception e) {
 
 229                 logger.error("{}: feature {} before-start failure because of {}", this, feature.getClass().getName(),
 
 234         if (this.isLocked()) {
 
 235             throw new IllegalStateException("Policy Controller " + name + " is locked");
 
 238         synchronized (this) {
 
 246         boolean success = this.droolsController.start();
 
 248         // register for events
 
 250         for (TopicSource source : sources) {
 
 251             source.register(this);
 
 254         for (TopicSink sink : sinks) {
 
 257             } catch (Exception e) {
 
 258                 logger.error("{}: cannot start {} because of {}", this, sink, e.getMessage(), e);
 
 262         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 264                 if (feature.afterStart(this)) {
 
 267             } catch (Exception e) {
 
 268                 logger.error("{}: feature {} after-start failure because of {}", this, feature.getClass().getName(),
 
 280     public boolean stop() {
 
 281         logger.info("{}: stop", this);
 
 283         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 285                 if (feature.beforeStop(this)) {
 
 288             } catch (Exception e) {
 
 289                 logger.error("{}: feature {} before-stop failure because of {}", this, feature.getClass().getName(),
 
 294         /* stop regardless locked state */
 
 296         synchronized (this) {
 
 304         // 1. Stop registration
 
 306         for (TopicSource source : sources) {
 
 307             source.unregister(this);
 
 310         boolean success = this.droolsController.stop();
 
 312         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 314                 if (feature.afterStop(this)) {
 
 317             } catch (Exception e) {
 
 318                 logger.error("{}: feature {} after-stop failure because of {}", this, feature.getClass().getName(),
 
 330     public void shutdown() {
 
 331         logger.info("{}: shutdown", this);
 
 333         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 335                 if (feature.beforeShutdown(this)) {
 
 338             } catch (Exception e) {
 
 339                 logger.error("{}: feature {} before-shutdown failure because of {}", this, feature.getClass().getName(),
 
 346         DroolsController.factory.shutdown(this.droolsController);
 
 348         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 350                 if (feature.afterShutdown(this)) {
 
 353             } catch (Exception e) {
 
 354                 logger.error("{}: feature {} after-shutdown failure because of {}", this, feature.getClass().getName(),
 
 365         logger.info("{}: halt", this);
 
 367         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 369                 if (feature.beforeHalt(this)) {
 
 372             } catch (Exception e) {
 
 373                 logger.error("{}: feature {} before-halt failure because of {}", this, feature.getClass().getName(),
 
 379         DroolsController.factory.destroy(this.droolsController);
 
 380         SystemPersistence.manager.deleteController(this.name);
 
 382         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 384                 if (feature.afterHalt(this)) {
 
 387             } catch (Exception e) {
 
 388                 logger.error("{}: feature {} after-halt failure because of {}", this, feature.getClass().getName(),
 
 398     public void onTopicEvent(Topic.CommInfrastructure commType, String topic, String event) {
 
 400         if (logger.isDebugEnabled()) {
 
 401             logger.debug("{}: event offered from {}:{}: {}", this, commType, topic, event);
 
 404         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 406                 if (feature.beforeOffer(this, commType, topic, event)) {
 
 409             } catch (Exception e) {
 
 410                 logger.error("{}: feature {} before-offer failure because of {}", this, feature.getClass().getName(),
 
 423         boolean success = this.droolsController.offer(topic, event);
 
 425         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 427                 if (feature.afterOffer(this, commType, topic, event, success)) {
 
 430             } catch (Exception e) {
 
 431                 logger.error("{}: feature {} after-offer failure because of {}", this, feature.getClass().getName(),
 
 441     public boolean deliver(Topic.CommInfrastructure commType, String topic, Object event) {
 
 443         if (logger.isDebugEnabled()) {
 
 444             logger.debug("{}: deliver event to {}:{}: {}", this, commType, topic, event);
 
 447         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 449                 if (feature.beforeDeliver(this, commType, topic, event)) {
 
 452             } catch (Exception e) {
 
 453                 logger.error("{}: feature {} before-deliver failure because of {}", this, feature.getClass().getName(),
 
 458         if (topic == null || topic.isEmpty()) {
 
 459             throw new IllegalArgumentException("Invalid Topic");
 
 463             throw new IllegalArgumentException("Invalid Event");
 
 466         if (!this.isAlive()) {
 
 467             throw new IllegalStateException("Policy Engine is stopped");
 
 470         if (this.isLocked()) {
 
 471             throw new IllegalStateException("Policy Engine is locked");
 
 474         if (!this.topic2Sinks.containsKey(topic)) {
 
 475             logger.warn("{}: cannot deliver event because the sink {}:{} is not registered: {}", this, commType, topic,
 
 477             throw new IllegalArgumentException("Unsupported topic " + topic + " for delivery");
 
 480         boolean success = this.droolsController.deliver(this.topic2Sinks.get(topic), event);
 
 482         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 484                 if (feature.afterDeliver(this, commType, topic, event, success)) {
 
 487             } catch (Exception e) {
 
 488                 logger.error("{}: feature {} after-deliver failure because of {}", this, feature.getClass().getName(),
 
 500     public boolean isAlive() {
 
 508     public boolean lock() {
 
 509         logger.info("{}: lock", this);
 
 511         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 513                 if (feature.beforeLock(this)) {
 
 516             } catch (Exception e) {
 
 517                 logger.error("{}: feature {} before-lock failure because of {}", this, feature.getClass().getName(),
 
 522         synchronized (this) {
 
 530         // it does not affect associated sources/sinks, they are
 
 531         // autonomous entities
 
 533         boolean success = this.droolsController.lock();
 
 535         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 537                 if (feature.afterLock(this)) {
 
 540             } catch (Exception e) {
 
 541                 logger.error("{}: feature {} after-lock failure because of {}", this, feature.getClass().getName(),
 
 553     public boolean unlock() {
 
 555         logger.info("{}: unlock", this);
 
 557         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 559                 if (feature.beforeUnlock(this)) {
 
 562             } catch (Exception e) {
 
 563                 logger.error("{}: feature {} before-unlock failure because of {}", this, feature.getClass().getName(),
 
 568         synchronized (this) {
 
 576         boolean success = this.droolsController.unlock();
 
 578         for (PolicyControllerFeatureAPI feature : PolicyControllerFeatureAPI.providers.getList()) {
 
 580                 if (feature.afterUnlock(this)) {
 
 583             } catch (Exception e) {
 
 584                 logger.error("{}: feature {} after-unlock failure because of {}", this, feature.getClass().getName(),
 
 596     public boolean isLocked() {
 
 604     public List<? extends TopicSource> getTopicSources() {
 
 612     public List<? extends TopicSink> getTopicSinks() {
 
 620     public DroolsController getDrools() {
 
 621         return this.droolsController;
 
 630     public Properties getProperties() {
 
 631         return this.properties;
 
 635     public String toString() {
 
 636         return "AggregatedPolicyController [name=" + name + ", alive=" + alive +
 
 637                 ", locked=" + locked + ", droolsController=" + droolsController + "]";