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 final 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 + "]";