aboutsummaryrefslogtreecommitdiffstats
path: root/controlloop/common/controller-tdjam/src/main/java/org/onap/policy/controlloop/tdjam/TdjamController.java
diff options
context:
space:
mode:
Diffstat (limited to 'controlloop/common/controller-tdjam/src/main/java/org/onap/policy/controlloop/tdjam/TdjamController.java')
-rw-r--r--controlloop/common/controller-tdjam/src/main/java/org/onap/policy/controlloop/tdjam/TdjamController.java833
1 files changed, 833 insertions, 0 deletions
diff --git a/controlloop/common/controller-tdjam/src/main/java/org/onap/policy/controlloop/tdjam/TdjamController.java b/controlloop/common/controller-tdjam/src/main/java/org/onap/policy/controlloop/tdjam/TdjamController.java
new file mode 100644
index 000000000..0b17f196f
--- /dev/null
+++ b/controlloop/common/controller-tdjam/src/main/java/org/onap/policy/controlloop/tdjam/TdjamController.java
@@ -0,0 +1,833 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * Copyright (C) 2020 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.tdjam;
+
+import static org.onap.policy.drools.properties.DroolsPropertyConstants.PROPERTY_CONTROLLER_TYPE;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import org.onap.policy.common.endpoints.event.comm.Topic;
+import org.onap.policy.common.endpoints.event.comm.TopicEndpointManager;
+import org.onap.policy.common.endpoints.event.comm.TopicListener;
+import org.onap.policy.common.endpoints.event.comm.TopicSource;
+import org.onap.policy.controlloop.CanonicalOnset;
+import org.onap.policy.controlloop.ControlLoopEvent;
+import org.onap.policy.controlloop.ControlLoopException;
+import org.onap.policy.controlloop.ControlLoopNotificationType;
+import org.onap.policy.controlloop.ControlLoopResponse;
+import org.onap.policy.controlloop.VirtualControlLoopEvent;
+import org.onap.policy.controlloop.VirtualControlLoopNotification;
+import org.onap.policy.controlloop.drl.legacy.ControlLoopParams;
+import org.onap.policy.controlloop.eventmanager.ControlLoopEventManager2;
+import org.onap.policy.controlloop.utils.ControlLoopUtils;
+import org.onap.policy.drools.controller.DroolsController;
+import org.onap.policy.drools.features.DroolsControllerFeatureApi;
+import org.onap.policy.drools.features.PolicyControllerFeatureApi;
+import org.onap.policy.drools.protocol.coders.EventProtocolCoder.CoderFilters;
+import org.onap.policy.drools.protocol.coders.EventProtocolCoderConstants;
+import org.onap.policy.drools.protocol.coders.ProtocolCoderToolset;
+import org.onap.policy.drools.protocol.coders.TopicCoderFilterConfiguration;
+import org.onap.policy.drools.system.PolicyController;
+import org.onap.policy.drools.system.PolicyEngineConstants;
+import org.onap.policy.extension.system.NonDroolsPolicyController;
+import org.onap.policy.models.tosca.authorative.concepts.ToscaPolicy;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * This replaces a Drools session with Java code. Although Drools memory
+ * is simulated when running the Junit tests, there is no actual use of
+ * Drools here.
+ */
+public class TdjamController extends NonDroolsPolicyController {
+ private static Logger logger = LoggerFactory.getLogger(TdjamController.class);
+
+ // the 'controller.type' property is set to this value
+ private static final String TDJAM_CONTROLLER_BUILDER_TAG = "tdjam";
+
+ // additional data associated with session
+ private final String groupId;
+ private final String artifactId;
+
+ // top-level tosca policy table (first key = name, second key = version)
+ private final Map<String, Map<String, ToscaPolicy>> toscaPolicies = new HashMap<>();
+
+ // maps 'controlLoopControlName' to 'ControlLoopParams'
+ private final Map<String, ControlLoopParams> controlLoopParams = new HashMap<>();
+
+ // maps 'requestId' to 'ControlLoopEventManager'
+ private final Map<UUID, ControlLoopEventManager> eventManagers = new ConcurrentHashMap<>();
+
+ // maps onset to 'ControlLoopEventManager'
+ private final Map<VirtualControlLoopEvent, ControlLoopEventManager> onsetToEventManager = new ConcurrentHashMap<>();
+
+ // maps 'topic' to 'TopicData'
+ private final Map<String, TopicData> topicDataTable = new ConcurrentHashMap<>();
+
+ /* ============================================================ */
+
+ /**
+ * Initialize a new 'TdjamController'.
+ *
+ * @param name the controller name
+ * @param properties properties defining the controller
+ */
+ public TdjamController(String name, Properties properties) {
+ super(name, properties);
+
+ this.groupId = getGroupId();
+ this.artifactId = getArtifactId();
+
+ init();
+ }
+
+ private void init() {
+ // go through all of the incoming message decoders associated
+ // with this controller
+ for (ProtocolCoderToolset pct :
+ EventProtocolCoderConstants.getManager()
+ .getDecoders(groupId, artifactId)) {
+ // go through the 'CoderFilters' instances, and see if there are
+ // any that we are interested in
+ for (CoderFilters cf : pct.getCoders()) {
+ try {
+ Class<?> clazz = Class.forName(cf.getCodedClass());
+ if (ControlLoopEvent.class.isAssignableFrom(clazz)) {
+ // this one is of interest
+ logger.debug("TdjamController using CoderFilters: {}", cf);
+ getTopicData(pct.getTopic());
+ }
+ } catch (ClassNotFoundException e) {
+ logger.error("CoderFilter refers to unknown class: {}",
+ cf.getCodedClass(), e);
+ }
+ }
+ }
+
+ // start all 'TopicData' instances
+ for (TopicData topicData : topicDataTable.values()) {
+ topicData.start();
+ }
+ }
+
+ @Override
+ public <T> boolean offer(T object) {
+ if (object instanceof ToscaPolicy) {
+ addToscaPolicy((ToscaPolicy) object);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Add or replace a ToscaPolicy instance. The policy is keyed by name and
+ * version.
+ *
+ * @param toscaPolicy the ToscaPolicy being added
+ * @return if a ToscaPolicy with this name/version previously existed within
+ * this TdjamController, it is returned; otherwise, 'null' is returned.
+ */
+ public synchronized ToscaPolicy addToscaPolicy(ToscaPolicy toscaPolicy) {
+ Map<String, ToscaPolicy> level2 =
+ toscaPolicies.computeIfAbsent(toscaPolicy.getName(),
+ key -> new HashMap<String, ToscaPolicy>());
+ ToscaPolicy prev = level2.put(toscaPolicy.getVersion(), toscaPolicy);
+ if (prev != null) {
+ // update 'ControlLoopParams' entries
+ for (ControlLoopParams clp : controlLoopParams.values()) {
+ if (clp.getToscaPolicy() == prev) {
+ clp.setToscaPolicy(toscaPolicy);
+ }
+ }
+ }
+ logger.debug("ToscaPolicy name={}, version={}, count={}, prev={}",
+ toscaPolicy.getName(), toscaPolicy.getVersion(), toscaPolicies.size(), (prev != null));
+ dumpTables();
+
+ // attempt to create a 'ControlLoopParams' instance from this object
+ ControlLoopParams params =
+ ControlLoopUtils.toControlLoopParams(toscaPolicy);
+ if (params != null) {
+ addControlLoopParams(params);
+ }
+ return prev;
+ }
+
+ /**
+ * Remove a ToscaPolicy instance associated with the specified name and
+ * version.
+ *
+ * @param name the name of the ToscaPolicy to remove
+ * @param version the version of the ToscaPolicy to remove
+ * @return the ToscaPolicy that was removed, or 'null' if not found
+ */
+ public synchronized ToscaPolicy removeToscaPolicy(String name, String version) {
+ ToscaPolicy prev = null;
+ Map<String, ToscaPolicy> level2 = toscaPolicies.get(name);
+
+ if (level2 != null && (prev = level2.remove(version)) != null) {
+ // remove all 'ControlLoopParams' entries referencing this policy
+ for (ControlLoopParams clp :
+ new ArrayList<>(controlLoopParams.values())) {
+ if (clp.getToscaPolicy() == prev) {
+ controlLoopParams.remove(clp.getClosedLoopControlName());
+ }
+ }
+ }
+ return prev;
+ }
+
+ /**
+ * Fetch a ToscaPolicy instance associated with the specified name and
+ * version.
+ *
+ * @param name the name of the ToscaPolicy
+ * @param version the version of the ToscaPolicy
+ * @return the ToscaPolicy, or 'null' if not found
+ */
+ public synchronized ToscaPolicy getToscaPolicy(String name, String version) {
+ Map<String, ToscaPolicy> level2 = toscaPolicies.get(name);
+ return (level2 == null ? null : level2.get(version));
+ }
+
+ /**
+ * Return a collection of all ToscaPolicy instances.
+ *
+ * @return all ToscaPolicy instances
+ */
+ public synchronized Collection<ToscaPolicy> getAllToscaPolicies() {
+ HashSet<ToscaPolicy> rval = new HashSet<>();
+ for (Map<String, ToscaPolicy> map : toscaPolicies.values()) {
+ rval.addAll(map.values());
+ }
+ return rval;
+ }
+
+ /**
+ * Add a new 'ControlLoopParams' instance -- they are keyed by
+ * 'closedLoopControlName'.
+ *
+ * @param clp the 'ControlLoopParams' instance to add
+ * @return the 'ControlLoopParams' instance previously associated with the
+ * 'closedLoopControlName' ('null' if it didn't exist)
+ */
+ public synchronized ControlLoopParams addControlLoopParams(ControlLoopParams clp) {
+ ToscaPolicy toscaPolicy =
+ getToscaPolicy(clp.getPolicyName(), clp.getPolicyVersion());
+ if (toscaPolicy == null) {
+ // there needs to be a 'ToscaPolicy' instance with a matching
+ // name/version
+ logger.debug("Missing ToscaPolicy, name={}, version={}",
+ clp.getPolicyName(), clp.getPolicyVersion());
+ return clp;
+ }
+
+ clp.setToscaPolicy(toscaPolicy);
+ ControlLoopParams prev =
+ controlLoopParams.put(clp.getClosedLoopControlName(), clp);
+
+ logger.debug("ControlLoopParams name={}, version={}, closedLoopControlName={}, count={}, prev={}",
+ clp.getPolicyName(), clp.getPolicyVersion(),
+ clp.getClosedLoopControlName(), controlLoopParams.size(), (prev != null));
+ dumpTables();
+ return prev;
+ }
+
+ /**
+ * Return a collection of all ControlLoopParams instances.
+ *
+ * @return all ControlLoopParams instances
+ */
+ public synchronized Collection<ControlLoopParams> getAllControlLoopParams() {
+ return new ArrayList<>(controlLoopParams.values());
+ }
+
+ /**
+ * Return a collection of all EventManager instances.
+ *
+ * @return all EventManager instances
+ *
+ */
+ public synchronized Collection<ControlLoopEventManager> getAllEventManagers() {
+ return new ArrayList<>(eventManagers.values());
+ }
+
+ /**
+ * Return a collection of all onsetToEventManager instances.
+ *
+ * @return all onsetToEventManager instances
+ *
+ */
+ public synchronized Collection<ControlLoopEventManager> getAllOnsetToEventManager() {
+ return new ArrayList<>(onsetToEventManager.values());
+ }
+
+ /**
+ * Reset the controller.
+ *
+ */
+ public synchronized void reset() {
+ toscaPolicies.clear();
+ controlLoopParams.clear();
+ eventManagers.clear();
+ onsetToEventManager.clear();
+ }
+
+ @Override
+ public boolean stop() {
+ super.stop();
+
+ // stop all 'TopicData' instances
+ for (TopicData topicData : topicDataTable.values()) {
+ topicData.stop();
+ }
+ return true;
+ }
+
+ /**
+ * Remove a ControlLoopParams instance associated with the specified
+ * 'closedLoopControlName'.
+ *
+ * @param closedLoopControlName the closedLoopControlName identifying the
+ * ControlLoopParams instance
+ * @return the 'ControlLoopParams' instance, 'null' if not found
+ */
+ public synchronized ControlLoopParams removeControlLoopParams(String closedLoopControlName) {
+ return controlLoopParams.remove(closedLoopControlName);
+ }
+
+ /**
+ * Dump out the ToscaPolicy and ControlLoopParams tables in
+ * human-readable form.
+ */
+ private void dumpTables() {
+ ByteArrayOutputStream bos = new ByteArrayOutputStream();
+ PrintStream out = new PrintStream(bos, true);
+
+ // name(25) version(10) closedLoopControlName(...)
+
+ String format = "%-25s %-10s %s\n";
+ out.println("ToscaPolicy Table");
+ out.format(format, "Name", "Version", "");
+ out.format(format, "----", "-------", "");
+
+ for (Map<String, ToscaPolicy> level2 : toscaPolicies.values()) {
+ for (ToscaPolicy tp : level2.values()) {
+ out.format(format, tp.getName(), tp.getVersion(), "");
+ }
+ }
+
+ out.println("\nControlLoopParams Table");
+ out.format(format, "Name", "Version", "ClosedLoopControlName");
+ out.format(format, "----", "-------", "---------------------");
+ for (ControlLoopParams cp : controlLoopParams.values()) {
+ out.format(format, cp.getPolicyName(), cp.getPolicyVersion(),
+ cp.getClosedLoopControlName());
+ }
+
+ logger.debug(new String(bos.toByteArray()));
+ }
+
+ /**
+ * Find or create a 'TopicData' instance associated with the specified
+ * topic name.
+ *
+ * @param name the topic name
+ * @return the new or existing 'TopicData' instance associated with 'name'
+ */
+ private TopicData getTopicData(String name) {
+ return topicDataTable.computeIfAbsent(name, key -> new TopicData(name));
+ }
+
+ /* ============================================================ */
+
+ /**
+ * Process an incoming 'ControlLoopEvent'.
+ *
+ * @param event the incoming 'ControlLoopEvent'
+ */
+ private void processEvent(ControlLoopEvent event) {
+ String clName = event.getClosedLoopControlName();
+ ControlLoopParams params = controlLoopParams.get(clName);
+ if (params == null) {
+ logger.debug("No ControlLoopParams for event: {}", event);
+ return;
+ }
+
+ UUID requestId = event.getRequestId();
+ if (event instanceof CanonicalOnset) {
+ CanonicalOnset coEvent = (CanonicalOnset) event;
+
+ if (requestId == null) {
+ // the requestId should not be 'null'
+ handleNullRequestId(coEvent, params);
+ return;
+ }
+
+ ControlLoopEventManager manager = onsetToEventManager.computeIfAbsent(coEvent, key -> {
+ // a ControlLoopEventManager does not yet exist for this
+ // 'event' -- create one, with the initial event
+ try {
+ ControlLoopEventManager mgr = new ControlLoopEventManager(params, coEvent);
+ eventManagers.put(requestId, mgr);
+ return mgr;
+ } catch (ControlLoopException e) {
+ logger.error("Exception creating ControlLoopEventManager", e);
+ return null;
+ }
+ });
+
+ if (manager != null && !manager.getSerialWorkQueue().isRunning()) {
+ // new manager - start it by processing the initial event
+ manager.getSerialWorkQueue().start();
+ return;
+ }
+ }
+
+ if (event instanceof VirtualControlLoopEvent) {
+ ControlLoopEventManager manager = eventManagers.get(requestId);
+ if (manager != null) {
+ manager.getSerialWorkQueue()
+ .queueAndRun(() -> manager.subsequentEvent((VirtualControlLoopEvent) event));
+ return;
+ }
+ }
+
+ // this block of code originally appeared in the 'EVENT.CLEANUP'
+ // Drools rule
+ String ruleName = "EVENT.CLEANUP";
+
+ logger.info("{}: {}", clName, ruleName);
+ logger.debug("{}: {}: orphan event={}", clName, ruleName, event);
+ }
+
+ /**
+ * Generate and send a notification message in response to a 'CanonicalOnset'
+ * with a null 'requestId'.
+ *
+ * @param event the CanonicalOnset event
+ * @param params the associated ControlLoopParams
+ */
+ private void handleNullRequestId(CanonicalOnset event,
+ ControlLoopParams params) {
+ // this block of code originally appeared in the 'EVENT' Drools rule
+ String ruleName = "EVENT";
+ String clName = event.getClosedLoopControlName();
+
+ VirtualControlLoopNotification notification =
+ new VirtualControlLoopNotification(event);
+ notification.setNotification(ControlLoopNotificationType.REJECTED);
+ notification.setFrom("policy");
+ notification.setMessage("Missing requestId");
+ notification.setPolicyName(params.getPolicyName() + "." + ruleName);
+ notification.setPolicyScope(params.getPolicyScope());
+ notification.setPolicyVersion(params.getPolicyVersion());
+
+ //
+ // Generate notification
+ //
+ try {
+ PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
+
+ } catch (RuntimeException e) {
+ logger.warn("{}: {}.{}: event={} exception generating notification",
+ clName, params.getPolicyName(), ruleName,
+ event, e);
+ }
+ }
+
+ /* ============================================================ */
+
+ /**
+ * This nested class corresponds to a single topic name. At present, the
+ * only topics that are directly handled by this class are
+ * 'ControlLoopEvent', and subclasses (hence, the call to 'processEvent').
+ * If other event types later need to be directly handled, this may need to
+ * become an abstract class, with subclasses for the various event types.
+ */
+ private class TopicData implements TopicListener {
+ // topic name
+ private String name;
+
+ // set of 'TopicSource' instances associated with this topic
+ // (probably only one, but the underlying APIs support a list)
+ private List<TopicSource> topicSources = null;
+
+ /**
+ * Constructor -- initialize the 'TopicData' instance.
+ *
+ * @param name the topic name
+ */
+ private TopicData(String name) {
+ this.name = name;
+ }
+
+ /**
+ * Register all of the 'TopicSource' instances associated with this
+ * topic, and start the listeners.
+ */
+ private void start() {
+ if (topicSources == null) {
+ // locate topic sources
+ ArrayList<String> topics = new ArrayList<>();
+ topics.add(name);
+ topicSources = TopicEndpointManager.getManager().getTopicSources(topics);
+ }
+
+ for (TopicSource consumer : topicSources) {
+ consumer.register(this);
+ consumer.start();
+ }
+ }
+
+ /**
+ * Unregister all of the 'TopicSource' instances associated with this
+ * topic, and stop the listeners.
+ */
+ private void stop() {
+ if (topicSources != null) {
+ for (TopicSource consumer : topicSources) {
+ consumer.unregister(this);
+ consumer.stop();
+ }
+ }
+ }
+
+ /*===========================*/
+ /* 'TopicListener' interface */
+ /*===========================*/
+
+ @Override
+ public void onTopicEvent(Topic.CommInfrastructure commType, String topic, String event) {
+ logger.debug("TopicData.onTopicEvent: {}", event);
+ Object decodedObject =
+ EventProtocolCoderConstants.getManager().decode(groupId, artifactId, topic, event);
+ if (decodedObject != null) {
+ logger.debug("Decoded to object of {}", decodedObject.getClass());
+ if (decodedObject instanceof ControlLoopEvent) {
+ PolicyEngineConstants.getManager().getExecutorService().execute(() ->
+ processEvent((ControlLoopEvent) decodedObject));
+ }
+ }
+ }
+ }
+
+ /* ============================================================ */
+
+ /**
+ * This is a 'ControlLoopEventManager2' variant designed to run under
+ * 'TdjamController'.
+ */
+ private class ControlLoopEventManager extends ControlLoopEventManager2 {
+ private static final long serialVersionUID = 1L;
+
+ // used to serialize method calls from multiple threads, which avoids the
+ // need for additional synchronization
+ private final SerialWorkQueue serialWorkQueue;
+
+ private final ControlLoopParams params;
+
+ // onset event
+ private final CanonicalOnset event;
+
+ /**
+ * Constructor - initialize a ControlLoopEventManager.
+ *
+ * @param params the 'ControlLoopParam's instance associated with the
+ * 'closedLoopControlName'
+ * @param event the initial ControlLoopEvent
+ */
+ private ControlLoopEventManager(ControlLoopParams params, CanonicalOnset event)
+ throws ControlLoopException {
+
+ super(params, event);
+ this.params = params;
+ this.event = event;
+ this.serialWorkQueue = new SerialWorkQueue(this::initialEvent);
+ }
+
+ /**
+ * Return the SerialWorkQueue.
+ *
+ * @return the SerialWorkQueue
+ */
+ private SerialWorkQueue getSerialWorkQueue() {
+ return serialWorkQueue;
+ }
+
+ /**
+ * This is a notification from the base class that a state transition
+ * has occurred.
+ */
+ @Override
+ protected void notifyUpdate() {
+ update();
+ }
+
+ /**
+ * Process the initial event from DCAE that caused the
+ * 'ControlLoopEventManager' to be created.
+ */
+ private void initialEvent() {
+ // this block of code originally appeared in the 'EVENT' Drools rule
+ String ruleName = "EVENT";
+ UUID requestId = event.getRequestId();
+ String clName = event.getClosedLoopControlName();
+
+ VirtualControlLoopNotification notification;
+
+ try {
+ //
+ // Check the event, because we need it to not be null when
+ // we create the ControlLoopEventManager. The ControlLoopEventManager
+ // will do extra syntax checking as well as check if the closed loop is disabled.
+ //
+ try {
+ start();
+ } catch (Exception e) {
+ eventManagers.remove(requestId, this);
+ onsetToEventManager.remove(event, this);
+ throw e;
+ }
+ notification = makeNotification();
+ notification.setNotification(ControlLoopNotificationType.ACTIVE);
+ notification.setPolicyName(params.getPolicyName() + "." + ruleName);
+ } catch (Exception e) {
+ logger.warn("{}: {}.{}", clName, params.getPolicyName(), ruleName, e);
+ notification = new VirtualControlLoopNotification(event);
+ notification.setNotification(ControlLoopNotificationType.REJECTED);
+ notification.setMessage("Exception occurred: " + e.getMessage());
+ notification.setPolicyName(params.getPolicyName() + "." + ruleName);
+ notification.setPolicyScope(params.getPolicyScope());
+ notification.setPolicyVersion(params.getPolicyVersion());
+ }
+ //
+ // Generate notification
+ //
+ try {
+ PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
+
+ } catch (RuntimeException e) {
+ logger.warn("{}: {}.{}: event={} exception generating notification",
+ clName, params.getPolicyName(), ruleName,
+ event, e);
+ }
+ }
+
+ /**
+ * Process a subsequent event from DCAE.
+ *
+ * @param event the VirtualControlLoopEvent event
+ */
+ private void subsequentEvent(VirtualControlLoopEvent event) {
+ // this block of code originally appeared in the
+ // 'EVENT.MANAGER>NEW.EVENT' Drools rule
+ String ruleName = "EVENT.MANAGER.NEW.EVENT";
+
+ //
+ // Check what kind of event this is
+ //
+ switch (onNewEvent(event)) {
+ case SYNTAX_ERROR:
+ //
+ // Ignore any bad syntax events
+ //
+ logger.warn("{}: {}.{}: syntax error",
+ getClosedLoopControlName(), getPolicyName(), ruleName);
+ break;
+
+ case FIRST_ABATEMENT:
+ case SUBSEQUENT_ABATEMENT:
+ //
+ // TODO: handle the abatement. Currently, it's just discarded.
+ //
+ break;
+
+ case FIRST_ONSET:
+ case SUBSEQUENT_ONSET:
+ default:
+ //
+ // We don't care about subsequent onsets
+ //
+ logger.warn("{}: {}.{}: subsequent onset",
+ getClosedLoopControlName(), getPolicyName(), ruleName);
+ break;
+ }
+ }
+
+ /**
+ * Called when a state transition occurs.
+ */
+ private void update() {
+ // handle synchronization by running it under the SerialWorkQueue
+ getSerialWorkQueue().queueAndRun(() -> {
+ if (isActive()) {
+ updateActive();
+ } else {
+ updateInactive();
+ }
+ });
+ }
+
+ /**
+ * Called when a state transition occurs, and we are in the active state.
+ */
+ private void updateActive() {
+ if (!isUpdated()) {
+ // no notification needed
+ return;
+ }
+
+ // this block of code originally appeared in the
+ // 'EVENT.MANAGER.PROCESSING' Drools rule
+ String ruleName = "EVENT.MANAGER.PROCESSING";
+ VirtualControlLoopNotification notification =
+ getNotification();
+
+ logger.info("{}: {}.{}: manager={}",
+ getClosedLoopControlName(), getPolicyName(), ruleName,
+ this);
+ //
+ // Generate notification
+ //
+ try {
+ notification.setPolicyName(getPolicyName() + "." + ruleName);
+ PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
+
+ } catch (RuntimeException e) {
+ logger.warn("{}: {}.{}: manager={} exception generating notification",
+ getClosedLoopControlName(), getPolicyName(), ruleName,
+ this, e);
+ }
+ //
+ // Generate Response notification
+ //
+ try {
+ ControlLoopResponse clResponse = getControlLoopResponse();
+ if (clResponse != null) {
+ PolicyEngineConstants.getManager().deliver("DCAE_CL_RSP", clResponse);
+ }
+
+ } catch (RuntimeException e) {
+ logger.warn("{}: {}.{}: manager={} exception generating Response notification",
+ getClosedLoopControlName(), getPolicyName(), ruleName,
+ this, e);
+ }
+ //
+ // Discard this message and wait for the next response.
+ //
+ nextStep();
+ update();
+ }
+
+ /**
+ * Called when a state transition has occurred, and we are not in the
+ * active state.
+ */
+ private void updateInactive() {
+ // this block of code originally appeared in the 'EVENT.MANAGER.FINAL'
+ // Drools rule
+ String ruleName = "EVENT.MANAGER.FINAL";
+ VirtualControlLoopNotification notification =
+ getNotification();
+
+ logger.info("{}: {}.{}: manager={}",
+ getClosedLoopControlName(), getPolicyName(), ruleName,
+ this);
+ //
+ // Generate notification
+ //
+ try {
+ notification.setPolicyName(getPolicyName() + "." + ruleName);
+ PolicyEngineConstants.getManager().deliver("POLICY-CL-MGT", notification);
+ } catch (RuntimeException e) {
+ logger.warn("{}: {}.{}: manager={} exception generating notification",
+ getClosedLoopControlName(), getPolicyName(), ruleName,
+ this, e);
+ }
+ //
+ // Destroy the manager
+ //
+ destroy();
+
+ // Remove the entry from the table
+ eventManagers.remove(getRequestId(), this);
+ onsetToEventManager.remove(event, this);
+ }
+ }
+
+ /* ============================================================ */
+
+ /**
+ * An instance of this class is called by 'IndexedPolicyControllerFactory'.
+ * It does the build operation when the value of the 'controller.type'
+ * property matches the value of TDJAM_CONTROLLER_BUILDER_TAG.
+ */
+ public static class PolicyBuilder implements PolicyControllerFeatureApi {
+ @Override
+ public int getSequenceNumber() {
+ return 1;
+ }
+
+ @Override
+ public PolicyController beforeInstance(String name, Properties properties) {
+ if (TDJAM_CONTROLLER_BUILDER_TAG.equals(properties.getProperty(PROPERTY_CONTROLLER_TYPE))) {
+ return new TdjamController(name, properties);
+ }
+ return null;
+ }
+ }
+
+ /* ============================================================ */
+
+ /**
+ * An instance of this class is called by 'IndexedDroolsControllerFactory'.
+ * It does the build operation when the value of the 'controller.type'
+ * property matches the value of TDJAM_CONTROLLER_BUILDER_TAG.
+ */
+ public static class DroolsBuilder implements DroolsControllerFeatureApi {
+ @Override
+ public int getSequenceNumber() {
+ return 1;
+ }
+
+ @Override
+ public DroolsController beforeInstance(Properties properties,
+ String groupId, String artifactId, String version,
+ List<TopicCoderFilterConfiguration> decoderConfigurations,
+ List<TopicCoderFilterConfiguration> encoderConfigurations) throws LinkageError {
+
+ if (TDJAM_CONTROLLER_BUILDER_TAG.equals(properties.getProperty(PROPERTY_CONTROLLER_TYPE))) {
+ return TdjamController.getBuildInProgress();
+ }
+ return null;
+ }
+ }
+}