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;
24 import java.util.ArrayList;
25 import java.util.Arrays;
26 import java.util.HashMap;
27 import java.util.List;
28 import java.util.Properties;
29 import java.util.stream.Collectors;
30 import org.onap.policy.common.endpoints.event.comm.Topic;
31 import org.onap.policy.common.endpoints.event.comm.TopicEndpoint;
32 import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
33 import org.onap.policy.common.endpoints.event.comm.TopicListener;
34 import org.onap.policy.common.endpoints.event.comm.TopicSink;
35 import org.onap.policy.common.endpoints.event.comm.TopicSource;
36 import org.onap.policy.common.gson.annotation.GsonJsonIgnore;
37 import org.onap.policy.drools.controller.DroolsController;
38 import org.onap.policy.drools.controller.DroolsControllerConstants;
39 import org.onap.policy.drools.controller.DroolsControllerFactory;
40 import org.onap.policy.drools.features.PolicyControllerFeatureApi;
41 import org.onap.policy.drools.features.PolicyControllerFeatureApiConstants;
42 import org.onap.policy.drools.persistence.SystemPersistence;
43 import org.onap.policy.drools.persistence.SystemPersistenceConstants;
44 import org.onap.policy.drools.properties.DroolsPropertyConstants;
45 import org.onap.policy.drools.protocol.configuration.DroolsConfiguration;
46 import org.onap.policy.drools.system.PolicyController;
47 import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicyTypeIdentifier;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
52 * This implementation of the Policy Controller merely aggregates and tracks for management purposes
53 * all underlying resources that this controller depends upon.
55 public class AggregatedPolicyController implements PolicyController, TopicListener {
60 private static final Logger logger = LoggerFactory.getLogger(AggregatedPolicyController.class);
63 * identifier for this policy controller.
65 private final String name;
68 * Abstracted Event Sources List regardless communication technology.
70 private final List<? extends TopicSource> sources;
73 * Abstracted Event Sinks List regardless communication technology.
75 private final List<? extends TopicSink> sinks;
78 * Mapping topics to sinks.
82 private final HashMap<String, TopicSink> topic2Sinks = new HashMap<>();
85 * Is this Policy Controller running (alive) ? reflects invocation of start()/stop() only.
87 private volatile boolean alive;
90 * Is this Policy Controller locked ? reflects if i/o controller related operations and start
91 * are permitted, more specifically: start(), deliver() and onTopicEvent(). It does not affect
92 * the ability to stop the underlying drools infrastructure
94 private volatile boolean locked;
97 * Policy Drools Controller.
99 private volatile DroolsController droolsController;
102 * Properties used to initialize controller.
104 private final Properties properties;
109 private List<ToscaPolicyTypeIdentifier> policyTypes;
112 * Constructor version mainly used for bootstrapping at initialization time a policy engine
115 * @param name controller name
118 * @throws IllegalArgumentException when invalid arguments are provided
120 public AggregatedPolicyController(String name, Properties properties) {
125 * 1. Register read topics with network infrastructure (ueb, dmaap, rest) 2. Register write
126 * topics with network infrastructure (ueb, dmaap, rest) 3. Register with drools
130 // Create/Reuse Readers/Writers for all event sources endpoints
132 this.sources = getEndpointManager().addTopicSources(properties);
133 this.sinks = getEndpointManager().addTopicSinks(properties);
135 initDrools(properties);
138 /* persist new properties */
139 getPersistenceManager().storeController(name, properties);
140 this.properties = properties;
142 this.policyTypes = getPolicyTypesFromProperties();
146 public List<ToscaPolicyTypeIdentifier> getPolicyTypes() {
147 if (!policyTypes.isEmpty()) {
151 return droolsController
152 .getBaseDomainNames()
154 .map(d -> new ToscaPolicyTypeIdentifier(d,
155 DroolsPropertyConstants.DEFAULT_CONTROLLER_POLICY_TYPE_VERSION))
156 .collect(Collectors.toList());
159 protected List<ToscaPolicyTypeIdentifier> getPolicyTypesFromProperties() {
160 List<ToscaPolicyTypeIdentifier> policyTypeIds = new ArrayList<>();
162 String ptiPropValue = properties.getProperty(DroolsPropertyConstants.PROPERTY_CONTROLLER_POLICY_TYPES);
163 if (ptiPropValue == null) {
164 return policyTypeIds;
167 List<String> ptiPropList = new ArrayList<>(Arrays.asList(ptiPropValue.split("\\s*,\\s*")));
168 for (String pti : ptiPropList) {
169 String[] ptv = pti.split(":");
170 if (ptv.length == 1) {
171 policyTypeIds.add(new ToscaPolicyTypeIdentifier(ptv[0],
172 DroolsPropertyConstants.DEFAULT_CONTROLLER_POLICY_TYPE_VERSION));
173 } else if (ptv.length == 2) {
174 policyTypeIds.add(new ToscaPolicyTypeIdentifier(ptv[0], ptv[1]));
178 return policyTypeIds;
182 * initialize drools layer.
184 * @throws IllegalArgumentException if invalid parameters are passed in
186 private void initDrools(Properties properties) {
188 // Register with drools infrastructure
189 this.droolsController = getDroolsFactory().build(properties, sources, sinks);
190 } catch (Exception | LinkageError e) {
191 logger.error("{}: cannot init-drools because of {}", this, e.getMessage(), e);
192 throw new IllegalArgumentException(e);
199 * @throws IllegalArgumentException if invalid parameters are passed in
201 private void initSinks() {
202 this.topic2Sinks.clear();
203 for (TopicSink sink : sinks) {
204 this.topic2Sinks.put(sink.getTopic(), sink);
212 public boolean updateDrools(DroolsConfiguration newDroolsConfiguration) {
214 DroolsConfiguration oldDroolsConfiguration = new DroolsConfiguration(this.droolsController.getArtifactId(),
215 this.droolsController.getGroupId(), this.droolsController.getVersion());
217 if (oldDroolsConfiguration.getGroupId().equalsIgnoreCase(newDroolsConfiguration.getGroupId())
218 && oldDroolsConfiguration.getArtifactId().equalsIgnoreCase(newDroolsConfiguration.getArtifactId())
219 && oldDroolsConfiguration.getVersion().equalsIgnoreCase(newDroolsConfiguration.getVersion())) {
220 logger.warn("{}: cannot update-drools: identical configuration {} vs {}", this, oldDroolsConfiguration,
221 newDroolsConfiguration);
226 /* Drools Controller created, update initialization properties for restarts */
228 this.properties.setProperty(DroolsPropertyConstants.RULES_GROUPID, newDroolsConfiguration.getGroupId());
229 this.properties.setProperty(DroolsPropertyConstants.RULES_ARTIFACTID,
230 newDroolsConfiguration.getArtifactId());
231 this.properties.setProperty(DroolsPropertyConstants.RULES_VERSION, newDroolsConfiguration.getVersion());
233 getPersistenceManager().storeController(name, this.properties);
235 this.initDrools(this.properties);
237 /* set drools controller to current locked status */
239 if (this.isLocked()) {
240 this.droolsController.lock();
242 this.droolsController.unlock();
245 /* set drools controller to current alive status */
247 if (this.isAlive()) {
248 this.droolsController.start();
250 this.droolsController.stop();
253 } catch (IllegalArgumentException e) {
254 logger.error("{}: cannot update-drools because of {}", this, e.getMessage(), e);
265 public String getName() {
273 public boolean start() {
274 logger.info("{}: start", this);
276 for (PolicyControllerFeatureApi feature : getProviders()) {
278 if (feature.beforeStart(this)) {
281 } catch (Exception e) {
282 logger.error("{}: feature {} before-start failure because of {}", this, feature.getClass().getName(),
287 if (this.isLocked()) {
288 throw new IllegalStateException("Policy Controller " + name + " is locked");
291 synchronized (this) {
299 final boolean success = this.droolsController.start();
301 // register for events
303 for (TopicSource source : sources) {
304 source.register(this);
307 for (TopicSink sink : sinks) {
310 } catch (Exception e) {
311 logger.error("{}: cannot start {} because of {}", this, sink, e.getMessage(), e);
315 for (PolicyControllerFeatureApi feature : getProviders()) {
317 if (feature.afterStart(this)) {
320 } catch (Exception e) {
321 logger.error("{}: feature {} after-start failure because of {}", this, feature.getClass().getName(),
333 public boolean stop() {
334 logger.info("{}: stop", this);
336 for (PolicyControllerFeatureApi feature : getProviders()) {
338 if (feature.beforeStop(this)) {
341 } catch (Exception e) {
342 logger.error("{}: feature {} before-stop failure because of {}", this, feature.getClass().getName(),
347 /* stop regardless locked state */
349 synchronized (this) {
357 // 1. Stop registration
359 for (TopicSource source : sources) {
360 source.unregister(this);
363 boolean success = this.droolsController.stop();
365 for (PolicyControllerFeatureApi feature : getProviders()) {
367 if (feature.afterStop(this)) {
370 } catch (Exception e) {
371 logger.error("{}: feature {} after-stop failure because of {}", this, feature.getClass().getName(),
383 public void shutdown() {
384 logger.info("{}: shutdown", this);
386 for (PolicyControllerFeatureApi feature : getProviders()) {
388 if (feature.beforeShutdown(this)) {
391 } catch (Exception e) {
392 logger.error("{}: feature {} before-shutdown failure because of {}", this, feature.getClass().getName(),
399 getDroolsFactory().shutdown(this.droolsController);
401 for (PolicyControllerFeatureApi feature : getProviders()) {
403 if (feature.afterShutdown(this)) {
406 } catch (Exception e) {
407 logger.error("{}: feature {} after-shutdown failure because of {}", this, feature.getClass().getName(),
418 logger.info("{}: halt", this);
420 for (PolicyControllerFeatureApi feature : getProviders()) {
422 if (feature.beforeHalt(this)) {
425 } catch (Exception e) {
426 logger.error("{}: feature {} before-halt failure because of {}", this, feature.getClass().getName(),
432 getDroolsFactory().destroy(this.droolsController);
433 getPersistenceManager().deleteController(this.name);
435 for (PolicyControllerFeatureApi feature : getProviders()) {
437 if (feature.afterHalt(this)) {
440 } catch (Exception e) {
441 logger.error("{}: feature {} after-halt failure because of {}", this, feature.getClass().getName(),
451 public void onTopicEvent(Topic.CommInfrastructure commType, String topic, String event) {
452 logger.debug("{}: raw event offered from {}:{}: {}", this, commType, topic, event);
458 for (PolicyControllerFeatureApi feature : getProviders()) {
460 if (feature.beforeOffer(this, commType, topic, event)) {
463 } catch (Exception e) {
464 logger.error("{}: feature {} before-offer failure because of {}", this, feature.getClass().getName(),
469 boolean success = this.droolsController.offer(topic, event);
471 for (PolicyControllerFeatureApi feature : getProviders()) {
473 if (feature.afterOffer(this, commType, topic, event, success)) {
476 } catch (Exception e) {
477 logger.error("{}: feature {} after-offer failure because of {}", this, feature.getClass().getName(),
484 public <T> boolean offer(T event) {
485 logger.debug("{}: event offered: {}", this, event);
491 for (PolicyControllerFeatureApi feature : getProviders()) {
493 if (feature.beforeOffer(this, event)) {
496 } catch (Exception e) {
497 logger.error("{}: feature {} before-offer failure because of {}", this, feature.getClass().getName(),
502 boolean success = this.droolsController.offer(event);
504 for (PolicyControllerFeatureApi feature : getProviders()) {
506 if (feature.afterOffer(this, event, success)) {
509 } catch (Exception e) {
510 logger.error("{}: feature {} after-offer failure because of {}", this, feature.getClass().getName(),
518 private boolean skipOffer() {
519 return isLocked() || !isAlive();
526 public boolean deliver(Topic.CommInfrastructure commType, String topic, Object event) {
528 logger.debug("{}: deliver event to {}:{}: {}", this, commType, topic, event);
530 for (PolicyControllerFeatureApi feature : getProviders()) {
532 if (feature.beforeDeliver(this, commType, topic, event)) {
535 } catch (Exception e) {
536 logger.error("{}: feature {} before-deliver failure because of {}", this, feature.getClass().getName(),
541 if (topic == null || topic.isEmpty()) {
542 throw new IllegalArgumentException("Invalid Topic");
546 throw new IllegalArgumentException("Invalid Event");
549 if (!this.isAlive()) {
550 throw new IllegalStateException("Policy Engine is stopped");
553 if (this.isLocked()) {
554 throw new IllegalStateException("Policy Engine is locked");
557 if (!this.topic2Sinks.containsKey(topic)) {
558 logger.warn("{}: cannot deliver event because the sink {}:{} is not registered: {}", this, commType, topic,
560 throw new IllegalArgumentException("Unsupported topic " + topic + " for delivery");
563 boolean success = this.droolsController.deliver(this.topic2Sinks.get(topic), event);
565 for (PolicyControllerFeatureApi feature : getProviders()) {
567 if (feature.afterDeliver(this, commType, topic, event, success)) {
570 } catch (Exception e) {
571 logger.error("{}: feature {} after-deliver failure because of {}", this, feature.getClass().getName(),
583 public boolean isAlive() {
591 public boolean lock() {
592 logger.info("{}: lock", this);
594 for (PolicyControllerFeatureApi feature : getProviders()) {
596 if (feature.beforeLock(this)) {
599 } catch (Exception e) {
600 logger.error("{}: feature {} before-lock failure because of {}", this, feature.getClass().getName(),
605 synchronized (this) {
613 // it does not affect associated sources/sinks, they are
614 // autonomous entities
616 boolean success = this.droolsController.lock();
618 for (PolicyControllerFeatureApi feature : getProviders()) {
620 if (feature.afterLock(this)) {
623 } catch (Exception e) {
624 logger.error("{}: feature {} after-lock failure because of {}", this, feature.getClass().getName(),
636 public boolean unlock() {
638 logger.info("{}: unlock", this);
640 for (PolicyControllerFeatureApi feature : getProviders()) {
642 if (feature.beforeUnlock(this)) {
645 } catch (Exception e) {
646 logger.error("{}: feature {} before-unlock failure because of {}", this, feature.getClass().getName(),
651 synchronized (this) {
659 boolean success = this.droolsController.unlock();
661 for (PolicyControllerFeatureApi feature : getProviders()) {
663 if (feature.afterUnlock(this)) {
666 } catch (Exception e) {
667 logger.error("{}: feature {} after-unlock failure because of {}", this, feature.getClass().getName(),
679 public boolean isLocked() {
687 public List<? extends TopicSource> getTopicSources() {
695 public List<? extends TopicSink> getTopicSinks() {
703 public DroolsController getDrools() {
704 return this.droolsController;
714 public Properties getProperties() {
715 return this.properties;
719 public String toString() {
720 return "AggregatedPolicyController [name=" + name + ", alive=" + alive
721 + ", locked=" + locked + ", droolsController=" + droolsController + "]";
724 // the following methods may be overridden by junit tests
726 protected SystemPersistence getPersistenceManager() {
727 return SystemPersistenceConstants.getManager();
730 protected TopicEndpoint getEndpointManager() {
731 return TopicEndpointManager.getManager();
734 protected DroolsControllerFactory getDroolsFactory() {
735 return DroolsControllerConstants.getFactory();
738 protected List<PolicyControllerFeatureApi> getProviders() {
739 return PolicyControllerFeatureApiConstants.getProviders().getList();