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.controller.DroolsControllerFactory;
36 import org.onap.policy.drools.features.PolicyControllerFeatureAPI;
37 import org.onap.policy.drools.persistence.SystemPersistence;
38 import org.onap.policy.drools.properties.DroolsProperties;
39 import org.onap.policy.drools.protocol.configuration.DroolsConfiguration;
40 import org.onap.policy.drools.system.PolicyController;
41 import org.slf4j.Logger;
42 import org.slf4j.LoggerFactory;
45 * This implementation of the Policy Controller merely aggregates and tracks for management purposes
46 * all underlying resources that this controller depends upon.
48 public class AggregatedPolicyController implements PolicyController, TopicListener {
53 private static final Logger logger = LoggerFactory.getLogger(AggregatedPolicyController.class);
56 * Used to access various objects. Can be overridden by junit tests.
58 private static Factory factory = new Factory();
61 * identifier for this policy controller.
63 private final String name;
66 * Abstracted Event Sources List regardless communication technology.
68 private final List<? extends TopicSource> sources;
71 * Abstracted Event Sinks List regardless communication technology.
73 private final List<? extends TopicSink> sinks;
76 * Mapping topics to sinks.
79 private final HashMap<String, TopicSink> topic2Sinks = new HashMap<>();
82 * Is this Policy Controller running (alive) ? reflects invocation of start()/stop() only.
84 private volatile boolean alive;
87 * Is this Policy Controller locked ? reflects if i/o controller related operations and start
88 * are permitted, more specifically: start(), deliver() and onTopicEvent(). It does not affect
89 * the ability to stop the underlying drools infrastructure
91 private volatile boolean locked;
94 * Policy Drools Controller.
96 private volatile DroolsController droolsController;
99 * Properties used to initialize controller.
101 private final Properties properties;
104 * Constructor version mainly used for bootstrapping at initialization time a policy engine
107 * @param name controller name
110 * @throws IllegalArgumentException when invalid arguments are provided
112 public AggregatedPolicyController(String name, Properties properties) {
117 * 1. Register read topics with network infrastructure (ueb, dmaap, rest) 2. Register write
118 * topics with network infrastructure (ueb, dmaap, rest) 3. Register with drools
122 // Create/Reuse Readers/Writers for all event sources endpoints
124 this.sources = factory.getEndpointManager().addTopicSources(properties);
125 this.sinks = factory.getEndpointManager().addTopicSinks(properties);
127 initDrools(properties);
130 /* persist new properties */
131 factory.getPersistenceManager().storeController(name, properties);
132 this.properties = properties;
136 * initialize drools layer.
138 * @throws IllegalArgumentException if invalid parameters are passed in
140 private void initDrools(Properties properties) {
142 // Register with drools infrastructure
143 this.droolsController = factory.getDroolsFactory().build(properties, sources, sinks);
144 } catch (Exception | LinkageError e) {
145 logger.error("{}: cannot init-drools because of {}", this, e.getMessage(), e);
146 throw new IllegalArgumentException(e);
153 * @throws IllegalArgumentException if invalid parameters are passed in
155 private void initSinks() {
156 this.topic2Sinks.clear();
157 for (TopicSink sink : sinks) {
158 this.topic2Sinks.put(sink.getTopic(), sink);
166 public boolean updateDrools(DroolsConfiguration newDroolsConfiguration) {
168 DroolsConfiguration oldDroolsConfiguration = new DroolsConfiguration(this.droolsController.getArtifactId(),
169 this.droolsController.getGroupId(), this.droolsController.getVersion());
171 if (oldDroolsConfiguration.getGroupId().equalsIgnoreCase(newDroolsConfiguration.getGroupId())
172 && oldDroolsConfiguration.getArtifactId().equalsIgnoreCase(newDroolsConfiguration.getArtifactId())
173 && oldDroolsConfiguration.getVersion().equalsIgnoreCase(newDroolsConfiguration.getVersion())) {
174 logger.warn("{}: cannot update-drools: identical configuration {} vs {}", this, oldDroolsConfiguration,
175 newDroolsConfiguration);
180 /* Drools Controller created, update initialization properties for restarts */
182 this.properties.setProperty(DroolsProperties.RULES_GROUPID, newDroolsConfiguration.getGroupId());
183 this.properties.setProperty(DroolsProperties.RULES_ARTIFACTID, newDroolsConfiguration.getArtifactId());
184 this.properties.setProperty(DroolsProperties.RULES_VERSION, newDroolsConfiguration.getVersion());
186 factory.getPersistenceManager().storeController(name, this.properties);
188 this.initDrools(this.properties);
190 /* set drools controller to current locked status */
192 if (this.isLocked()) {
193 this.droolsController.lock();
195 this.droolsController.unlock();
198 /* set drools controller to current alive status */
200 if (this.isAlive()) {
201 this.droolsController.start();
203 this.droolsController.stop();
206 } catch (IllegalArgumentException e) {
207 logger.error("{}: cannot update-drools because of {}", this, e.getMessage(), e);
218 public String getName() {
226 public boolean start() {
227 logger.info("{}: start", this);
229 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
231 if (feature.beforeStart(this)) {
234 } catch (Exception e) {
235 logger.error("{}: feature {} before-start failure because of {}", this, feature.getClass().getName(),
240 if (this.isLocked()) {
241 throw new IllegalStateException("Policy Controller " + name + " is locked");
244 synchronized (this) {
252 final boolean success = this.droolsController.start();
254 // register for events
256 for (TopicSource source : sources) {
257 source.register(this);
260 for (TopicSink sink : sinks) {
263 } catch (Exception e) {
264 logger.error("{}: cannot start {} because of {}", this, sink, e.getMessage(), e);
268 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
270 if (feature.afterStart(this)) {
273 } catch (Exception e) {
274 logger.error("{}: feature {} after-start failure because of {}", this, feature.getClass().getName(),
286 public boolean stop() {
287 logger.info("{}: stop", this);
289 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
291 if (feature.beforeStop(this)) {
294 } catch (Exception e) {
295 logger.error("{}: feature {} before-stop failure because of {}", this, feature.getClass().getName(),
300 /* stop regardless locked state */
302 synchronized (this) {
310 // 1. Stop registration
312 for (TopicSource source : sources) {
313 source.unregister(this);
316 boolean success = this.droolsController.stop();
318 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
320 if (feature.afterStop(this)) {
323 } catch (Exception e) {
324 logger.error("{}: feature {} after-stop failure because of {}", this, feature.getClass().getName(),
336 public void shutdown() {
337 logger.info("{}: shutdown", this);
339 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
341 if (feature.beforeShutdown(this)) {
344 } catch (Exception e) {
345 logger.error("{}: feature {} before-shutdown failure because of {}", this, feature.getClass().getName(),
352 factory.getDroolsFactory().shutdown(this.droolsController);
354 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
356 if (feature.afterShutdown(this)) {
359 } catch (Exception e) {
360 logger.error("{}: feature {} after-shutdown failure because of {}", this, feature.getClass().getName(),
371 logger.info("{}: halt", this);
373 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
375 if (feature.beforeHalt(this)) {
378 } catch (Exception e) {
379 logger.error("{}: feature {} before-halt failure because of {}", this, feature.getClass().getName(),
385 factory.getDroolsFactory().destroy(this.droolsController);
386 factory.getPersistenceManager().deleteController(this.name);
388 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
390 if (feature.afterHalt(this)) {
393 } catch (Exception e) {
394 logger.error("{}: feature {} after-halt failure because of {}", this, feature.getClass().getName(),
404 public void onTopicEvent(Topic.CommInfrastructure commType, String topic, String event) {
406 logger.debug("{}: event offered from {}:{}: {}", this, commType, topic, event);
408 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
410 if (feature.beforeOffer(this, commType, topic, event)) {
413 } catch (Exception e) {
414 logger.error("{}: feature {} before-offer failure because of {}", this, feature.getClass().getName(),
427 boolean success = this.droolsController.offer(topic, event);
429 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
431 if (feature.afterOffer(this, commType, topic, event, success)) {
434 } catch (Exception e) {
435 logger.error("{}: feature {} after-offer failure because of {}", this, feature.getClass().getName(),
445 public boolean deliver(Topic.CommInfrastructure commType, String topic, Object event) {
447 logger.debug("{}: deliver event to {}:{}: {}", this, commType, topic, event);
449 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
451 if (feature.beforeDeliver(this, commType, topic, event)) {
454 } catch (Exception e) {
455 logger.error("{}: feature {} before-deliver failure because of {}", this, feature.getClass().getName(),
460 if (topic == null || topic.isEmpty()) {
461 throw new IllegalArgumentException("Invalid Topic");
465 throw new IllegalArgumentException("Invalid Event");
468 if (!this.isAlive()) {
469 throw new IllegalStateException("Policy Engine is stopped");
472 if (this.isLocked()) {
473 throw new IllegalStateException("Policy Engine is locked");
476 if (!this.topic2Sinks.containsKey(topic)) {
477 logger.warn("{}: cannot deliver event because the sink {}:{} is not registered: {}", this, commType, topic,
479 throw new IllegalArgumentException("Unsupported topic " + topic + " for delivery");
482 boolean success = this.droolsController.deliver(this.topic2Sinks.get(topic), event);
484 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
486 if (feature.afterDeliver(this, commType, topic, event, success)) {
489 } catch (Exception e) {
490 logger.error("{}: feature {} after-deliver failure because of {}", this, feature.getClass().getName(),
502 public boolean isAlive() {
510 public boolean lock() {
511 logger.info("{}: lock", this);
513 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
515 if (feature.beforeLock(this)) {
518 } catch (Exception e) {
519 logger.error("{}: feature {} before-lock failure because of {}", this, feature.getClass().getName(),
524 synchronized (this) {
532 // it does not affect associated sources/sinks, they are
533 // autonomous entities
535 boolean success = this.droolsController.lock();
537 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
539 if (feature.afterLock(this)) {
542 } catch (Exception e) {
543 logger.error("{}: feature {} after-lock failure because of {}", this, feature.getClass().getName(),
555 public boolean unlock() {
557 logger.info("{}: unlock", this);
559 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
561 if (feature.beforeUnlock(this)) {
564 } catch (Exception e) {
565 logger.error("{}: feature {} before-unlock failure because of {}", this, feature.getClass().getName(),
570 synchronized (this) {
578 boolean success = this.droolsController.unlock();
580 for (PolicyControllerFeatureAPI feature : factory.getFeatureProviders()) {
582 if (feature.afterUnlock(this)) {
585 } catch (Exception e) {
586 logger.error("{}: feature {} after-unlock failure because of {}", this, feature.getClass().getName(),
598 public boolean isLocked() {
606 public List<? extends TopicSource> getTopicSources() {
614 public List<? extends TopicSink> getTopicSinks() {
622 public DroolsController getDrools() {
623 return this.droolsController;
632 public Properties getProperties() {
633 return this.properties;
637 public String toString() {
638 return "AggregatedPolicyController [name=" + name + ", alive=" + alive
639 + ", locked=" + locked + ", droolsController=" + droolsController + "]";
643 * Factory to access various objects. Can be overridden by junit tests.
645 public static class Factory {
647 public SystemPersistence getPersistenceManager() {
648 return SystemPersistence.manager;
651 public TopicEndpoint getEndpointManager() {
652 return TopicEndpoint.manager;
655 public DroolsControllerFactory getDroolsFactory() {
656 return DroolsController.factory;
659 public List<PolicyControllerFeatureAPI> getFeatureProviders() {
660 return PolicyControllerFeatureAPI.providers.getList();