2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2019 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.common.gson.annotation.GsonJsonIgnore;
35 import org.onap.policy.drools.controller.DroolsController;
36 import org.onap.policy.drools.controller.DroolsControllerFactory;
37 import org.onap.policy.drools.features.PolicyControllerFeatureAPI;
38 import org.onap.policy.drools.persistence.SystemPersistence;
39 import org.onap.policy.drools.properties.DroolsProperties;
40 import org.onap.policy.drools.protocol.configuration.DroolsConfiguration;
41 import org.onap.policy.drools.system.PolicyController;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
46 * This implementation of the Policy Controller merely aggregates and tracks for management purposes
47 * all underlying resources that this controller depends upon.
49 public class AggregatedPolicyController implements PolicyController, TopicListener {
54 private static final Logger logger = LoggerFactory.getLogger(AggregatedPolicyController.class);
57 * identifier for this policy controller.
59 private final String name;
62 * Abstracted Event Sources List regardless communication technology.
64 private final List<? extends TopicSource> sources;
67 * Abstracted Event Sinks List regardless communication technology.
69 private final List<? extends TopicSink> sinks;
72 * Mapping topics to sinks.
76 private final HashMap<String, TopicSink> topic2Sinks = new HashMap<>();
79 * Is this Policy Controller running (alive) ? reflects invocation of start()/stop() only.
81 private volatile boolean alive;
84 * Is this Policy Controller locked ? reflects if i/o controller related operations and start
85 * are permitted, more specifically: start(), deliver() and onTopicEvent(). It does not affect
86 * the ability to stop the underlying drools infrastructure
88 private volatile boolean locked;
91 * Policy Drools Controller.
93 private volatile DroolsController droolsController;
96 * Properties used to initialize controller.
98 private final Properties properties;
101 * Constructor version mainly used for bootstrapping at initialization time a policy engine
104 * @param name controller name
107 * @throws IllegalArgumentException when invalid arguments are provided
109 public AggregatedPolicyController(String name, Properties properties) {
114 * 1. Register read topics with network infrastructure (ueb, dmaap, rest) 2. Register write
115 * topics with network infrastructure (ueb, dmaap, rest) 3. Register with drools
119 // Create/Reuse Readers/Writers for all event sources endpoints
121 this.sources = getEndpointManager().addTopicSources(properties);
122 this.sinks = getEndpointManager().addTopicSinks(properties);
124 initDrools(properties);
127 /* persist new properties */
128 getPersistenceManager().storeController(name, properties);
129 this.properties = properties;
133 * initialize drools layer.
135 * @throws IllegalArgumentException if invalid parameters are passed in
137 private void initDrools(Properties properties) {
139 // Register with drools infrastructure
140 this.droolsController = getDroolsFactory().build(properties, sources, sinks);
141 } catch (Exception | LinkageError e) {
142 logger.error("{}: cannot init-drools because of {}", this, e.getMessage(), e);
143 throw new IllegalArgumentException(e);
150 * @throws IllegalArgumentException if invalid parameters are passed in
152 private void initSinks() {
153 this.topic2Sinks.clear();
154 for (TopicSink sink : sinks) {
155 this.topic2Sinks.put(sink.getTopic(), sink);
163 public boolean updateDrools(DroolsConfiguration newDroolsConfiguration) {
165 DroolsConfiguration oldDroolsConfiguration = new DroolsConfiguration(this.droolsController.getArtifactId(),
166 this.droolsController.getGroupId(), this.droolsController.getVersion());
168 if (oldDroolsConfiguration.getGroupId().equalsIgnoreCase(newDroolsConfiguration.getGroupId())
169 && oldDroolsConfiguration.getArtifactId().equalsIgnoreCase(newDroolsConfiguration.getArtifactId())
170 && oldDroolsConfiguration.getVersion().equalsIgnoreCase(newDroolsConfiguration.getVersion())) {
171 logger.warn("{}: cannot update-drools: identical configuration {} vs {}", this, oldDroolsConfiguration,
172 newDroolsConfiguration);
177 /* Drools Controller created, update initialization properties for restarts */
179 this.properties.setProperty(DroolsProperties.RULES_GROUPID, newDroolsConfiguration.getGroupId());
180 this.properties.setProperty(DroolsProperties.RULES_ARTIFACTID, newDroolsConfiguration.getArtifactId());
181 this.properties.setProperty(DroolsProperties.RULES_VERSION, newDroolsConfiguration.getVersion());
183 getPersistenceManager().storeController(name, this.properties);
185 this.initDrools(this.properties);
187 /* set drools controller to current locked status */
189 if (this.isLocked()) {
190 this.droolsController.lock();
192 this.droolsController.unlock();
195 /* set drools controller to current alive status */
197 if (this.isAlive()) {
198 this.droolsController.start();
200 this.droolsController.stop();
203 } catch (IllegalArgumentException e) {
204 logger.error("{}: cannot update-drools because of {}", this, e.getMessage(), e);
215 public String getName() {
223 public boolean start() {
224 logger.info("{}: start", this);
226 for (PolicyControllerFeatureAPI feature : getProviders()) {
228 if (feature.beforeStart(this)) {
231 } catch (Exception e) {
232 logger.error("{}: feature {} before-start failure because of {}", this, feature.getClass().getName(),
237 if (this.isLocked()) {
238 throw new IllegalStateException("Policy Controller " + name + " is locked");
241 synchronized (this) {
249 final boolean success = this.droolsController.start();
251 // register for events
253 for (TopicSource source : sources) {
254 source.register(this);
257 for (TopicSink sink : sinks) {
260 } catch (Exception e) {
261 logger.error("{}: cannot start {} because of {}", this, sink, e.getMessage(), e);
265 for (PolicyControllerFeatureAPI feature : getProviders()) {
267 if (feature.afterStart(this)) {
270 } catch (Exception e) {
271 logger.error("{}: feature {} after-start failure because of {}", this, feature.getClass().getName(),
283 public boolean stop() {
284 logger.info("{}: stop", this);
286 for (PolicyControllerFeatureAPI feature : getProviders()) {
288 if (feature.beforeStop(this)) {
291 } catch (Exception e) {
292 logger.error("{}: feature {} before-stop failure because of {}", this, feature.getClass().getName(),
297 /* stop regardless locked state */
299 synchronized (this) {
307 // 1. Stop registration
309 for (TopicSource source : sources) {
310 source.unregister(this);
313 boolean success = this.droolsController.stop();
315 for (PolicyControllerFeatureAPI feature : getProviders()) {
317 if (feature.afterStop(this)) {
320 } catch (Exception e) {
321 logger.error("{}: feature {} after-stop failure because of {}", this, feature.getClass().getName(),
333 public void shutdown() {
334 logger.info("{}: shutdown", this);
336 for (PolicyControllerFeatureAPI feature : getProviders()) {
338 if (feature.beforeShutdown(this)) {
341 } catch (Exception e) {
342 logger.error("{}: feature {} before-shutdown failure because of {}", this, feature.getClass().getName(),
349 getDroolsFactory().shutdown(this.droolsController);
351 for (PolicyControllerFeatureAPI feature : getProviders()) {
353 if (feature.afterShutdown(this)) {
356 } catch (Exception e) {
357 logger.error("{}: feature {} after-shutdown failure because of {}", this, feature.getClass().getName(),
368 logger.info("{}: halt", this);
370 for (PolicyControllerFeatureAPI feature : getProviders()) {
372 if (feature.beforeHalt(this)) {
375 } catch (Exception e) {
376 logger.error("{}: feature {} before-halt failure because of {}", this, feature.getClass().getName(),
382 getDroolsFactory().destroy(this.droolsController);
383 getPersistenceManager().deleteController(this.name);
385 for (PolicyControllerFeatureAPI feature : getProviders()) {
387 if (feature.afterHalt(this)) {
390 } catch (Exception e) {
391 logger.error("{}: feature {} after-halt failure because of {}", this, feature.getClass().getName(),
401 public void onTopicEvent(Topic.CommInfrastructure commType, String topic, String event) {
403 logger.debug("{}: event offered from {}:{}: {}", this, commType, topic, event);
405 for (PolicyControllerFeatureAPI feature : getProviders()) {
407 if (feature.beforeOffer(this, commType, topic, event)) {
410 } catch (Exception e) {
411 logger.error("{}: feature {} before-offer failure because of {}", this, feature.getClass().getName(),
424 boolean success = this.droolsController.offer(topic, event);
426 for (PolicyControllerFeatureAPI feature : getProviders()) {
428 if (feature.afterOffer(this, commType, topic, event, success)) {
431 } catch (Exception e) {
432 logger.error("{}: feature {} after-offer failure because of {}", this, feature.getClass().getName(),
442 public boolean deliver(Topic.CommInfrastructure commType, String topic, Object event) {
444 logger.debug("{}: deliver event to {}:{}: {}", this, commType, topic, event);
446 for (PolicyControllerFeatureAPI feature : getProviders()) {
448 if (feature.beforeDeliver(this, commType, topic, event)) {
451 } catch (Exception e) {
452 logger.error("{}: feature {} before-deliver failure because of {}", this, feature.getClass().getName(),
457 if (topic == null || topic.isEmpty()) {
458 throw new IllegalArgumentException("Invalid Topic");
462 throw new IllegalArgumentException("Invalid Event");
465 if (!this.isAlive()) {
466 throw new IllegalStateException("Policy Engine is stopped");
469 if (this.isLocked()) {
470 throw new IllegalStateException("Policy Engine is locked");
473 if (!this.topic2Sinks.containsKey(topic)) {
474 logger.warn("{}: cannot deliver event because the sink {}:{} is not registered: {}", this, commType, topic,
476 throw new IllegalArgumentException("Unsupported topic " + topic + " for delivery");
479 boolean success = this.droolsController.deliver(this.topic2Sinks.get(topic), event);
481 for (PolicyControllerFeatureAPI feature : getProviders()) {
483 if (feature.afterDeliver(this, commType, topic, event, success)) {
486 } catch (Exception e) {
487 logger.error("{}: feature {} after-deliver failure because of {}", this, feature.getClass().getName(),
499 public boolean isAlive() {
507 public boolean lock() {
508 logger.info("{}: lock", this);
510 for (PolicyControllerFeatureAPI feature : getProviders()) {
512 if (feature.beforeLock(this)) {
515 } catch (Exception e) {
516 logger.error("{}: feature {} before-lock failure because of {}", this, feature.getClass().getName(),
521 synchronized (this) {
529 // it does not affect associated sources/sinks, they are
530 // autonomous entities
532 boolean success = this.droolsController.lock();
534 for (PolicyControllerFeatureAPI feature : getProviders()) {
536 if (feature.afterLock(this)) {
539 } catch (Exception e) {
540 logger.error("{}: feature {} after-lock failure because of {}", this, feature.getClass().getName(),
552 public boolean unlock() {
554 logger.info("{}: unlock", this);
556 for (PolicyControllerFeatureAPI feature : getProviders()) {
558 if (feature.beforeUnlock(this)) {
561 } catch (Exception e) {
562 logger.error("{}: feature {} before-unlock failure because of {}", this, feature.getClass().getName(),
567 synchronized (this) {
575 boolean success = this.droolsController.unlock();
577 for (PolicyControllerFeatureAPI feature : getProviders()) {
579 if (feature.afterUnlock(this)) {
582 } catch (Exception e) {
583 logger.error("{}: feature {} after-unlock failure because of {}", this, feature.getClass().getName(),
595 public boolean isLocked() {
603 public List<? extends TopicSource> getTopicSources() {
611 public List<? extends TopicSink> getTopicSinks() {
619 public DroolsController getDrools() {
620 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 + "]";
640 // the following methods may be overridden by junit tests
642 protected SystemPersistence getPersistenceManager() {
643 return SystemPersistence.manager;
646 protected TopicEndpoint getEndpointManager() {
647 return TopicEndpoint.manager;
650 protected DroolsControllerFactory getDroolsFactory() {
651 return DroolsController.factory;
654 protected List<PolicyControllerFeatureAPI> getProviders() {
655 return PolicyControllerFeatureAPI.providers.getList();