From a6d4077e3639a0f3478f0cbf51e06ef46517a10d Mon Sep 17 00:00:00 2001 From: "Straubs, Ralph (rs8887)" Date: Fri, 17 Jul 2020 10:38:02 -0400 Subject: Add tdjam-controller the details is on wiki: https://wiki.onap.org/display/DW/tdjam+Feature+for+Tosca-Driven+Control+Loops Fixed some eclipse warnings. Revised the interaction between a manager and its SerialWorkQueue to address some threading issues. The original code started processing the event as soon as the manager was created, WHILE it was still being added to the map. During junit tests, the event responses came back, within the same thread, which then attempted to remove the manager from the map. This resulted in a ConcurrentHashMap exception. Issue-ID: POLICY-2415 Change-Id: I94a4152637be76e5b2aea2d869afd84dfb413a0e Signed-off-by: Straubs, Ralph (rs8887) Signed-off-by: jhh Signed-off-by: Taka Cho Signed-off-by: Jim Hahn --- .../eventmanager/ControlLoopEventManager2.java | 33 ++++++---- .../ControlLoopEventManager2Drools.java | 74 ++++++++++++++++++++++ .../eventmanager/ControlLoopEventManager2Test.java | 41 ++++++------ 3 files changed, 114 insertions(+), 34 deletions(-) create mode 100644 controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager2Drools.java (limited to 'controlloop/common/eventmanager') diff --git a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager2.java b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager2.java index 556fa31d5..b738cefe1 100644 --- a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager2.java +++ b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager2.java @@ -44,8 +44,6 @@ import java.util.stream.Stream; import lombok.Getter; import lombok.ToString; import org.apache.commons.lang3.StringUtils; -import org.drools.core.WorkingMemory; -import org.kie.api.runtime.rule.FactHandle; import org.onap.policy.controlloop.ControlLoopEventStatus; import org.onap.policy.controlloop.ControlLoopException; import org.onap.policy.controlloop.ControlLoopNotificationType; @@ -73,7 +71,7 @@ import org.slf4j.LoggerFactory; * {@link #isActive()} returns {@code false}, indicating that all steps have completed. */ @ToString(onlyExplicitlyIncluded = true) -public class ControlLoopEventManager2 implements ManagerContext, Serializable { +public abstract class ControlLoopEventManager2 implements ManagerContext, Serializable { private static final Logger logger = LoggerFactory.getLogger(ControlLoopEventManager2.class); private static final long serialVersionUID = -1216568161322872641L; @@ -161,20 +159,16 @@ public class ControlLoopEventManager2 implements ManagerContext, Serializable { @Getter private boolean updated = false; - private final transient WorkingMemory workMem; - private transient FactHandle factHandle; - /** * Constructs the object. * * @param params control loop parameters * @param event event to be managed by this object - * @param workMem working memory to update if this changes * @throws ControlLoopException if the event is invalid or if a YAML processor cannot * be created */ - public ControlLoopEventManager2(ControlLoopParams params, VirtualControlLoopEvent event, WorkingMemory workMem) + public ControlLoopEventManager2(ControlLoopParams params, VirtualControlLoopEvent event) throws ControlLoopException { createCount.incrementAndGet(); @@ -197,7 +191,6 @@ public class ControlLoopEventManager2 implements ManagerContext, Serializable { this.policyScope = params.getPolicyScope(); this.policyVersion = params.getPolicyVersion(); this.processor = new ControlLoopProcessor(params.getToscaPolicy()); - this.workMem = workMem; this.endTimeMs = System.currentTimeMillis() + detmControlLoopTimeoutMs(); } @@ -219,9 +212,7 @@ public class ControlLoopEventManager2 implements ManagerContext, Serializable { throw new IllegalStateException("manager is no longer active"); } - if ((factHandle = workMem.getFactHandle(this)) == null) { - throw new IllegalStateException("manager is not in working memory"); - } + startHook(); if (currentOperation.get() != null) { throw new IllegalStateException("manager already started"); @@ -373,7 +364,7 @@ public class ControlLoopEventManager2 implements ManagerContext, Serializable { } updated = true; - workMem.update(factHandle, this); + notifyUpdate(); } /** @@ -637,4 +628,20 @@ public class ControlLoopEventManager2 implements ManagerContext, Serializable { public OperationHistoryDataManager getDataManager() { return LazyInitData.DATA_MANAGER; } + + /* ============================================================ */ + + /** + * This is a method, invoked from the 'start' method -- it gives subclasses + * the ability to add operations. The default implementation does nothing. + */ + protected void startHook() { + } + + /** + * This is an abstract method that is called after a notable update has + * occurred to the 'ControlLoopEventManager2' object. It gives subclasses + * the ability to add a callback method to process state changes. + */ + protected abstract void notifyUpdate(); } diff --git a/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager2Drools.java b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager2Drools.java new file mode 100644 index 000000000..3af9defc7 --- /dev/null +++ b/controlloop/common/eventmanager/src/main/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager2Drools.java @@ -0,0 +1,74 @@ +/*- + * ============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.eventmanager; + +import org.drools.core.WorkingMemory; +import org.kie.api.runtime.rule.FactHandle; +import org.onap.policy.controlloop.ControlLoopException; +import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.drl.legacy.ControlLoopParams; + +/** + * Manager for a single control loop event. Once this has been created, the event can be + * retracted from working memory. Once this has been created, {@link #start()} should be + * invoked, and then {@link #nextStep()} should be invoked continually until + * {@link #isActive()} returns {@code false}, indicating that all steps have completed. + */ +public class ControlLoopEventManager2Drools extends ControlLoopEventManager2 { + private final transient WorkingMemory workMem; + private transient FactHandle factHandle; + + /** + * Constructs the object. + * + * @param params control loop parameters + * @param event event to be managed by this object + * @param workMem working memory to update if this changes + * @throws ControlLoopException if the event is invalid or if a YAML processor cannot + * be created + */ + public ControlLoopEventManager2Drools(ControlLoopParams params, VirtualControlLoopEvent event, + WorkingMemory workMem) throws ControlLoopException { + + super(params, event); + this.workMem = workMem; + } + + /** + * This is a hook added to 'ControlLoopEventManager2.start()' -- + * here, we add an additional check. + */ + @Override + protected void startHook() { + if ((factHandle = workMem.getFactHandle(this)) == null) { + throw new IllegalStateException("manager is not in working memory"); + } + } + + /** + * This is a hook added to 'ControlLoopEventManager2.updated(...)' -- + * here, we mark it as updated in Drools memory. + */ + @Override + protected void notifyUpdate() { + workMem.update(factHandle, this); + } +} diff --git a/controlloop/common/eventmanager/src/test/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager2Test.java b/controlloop/common/eventmanager/src/test/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager2Test.java index 1c4030c08..da37e6fc3 100644 --- a/controlloop/common/eventmanager/src/test/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager2Test.java +++ b/controlloop/common/eventmanager/src/test/java/org/onap/policy/controlloop/eventmanager/ControlLoopEventManager2Test.java @@ -118,7 +118,7 @@ public class ControlLoopEventManager2Test { private ControlLoopParams params; private VirtualControlLoopEvent event; private int updateCount; - private ControlLoopEventManager2 mgr; + private ControlLoopEventManager2Drools mgr; /** * Sets up. @@ -180,11 +180,11 @@ public class ControlLoopEventManager2Test { Map orig = event.getAai(); event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "true")); - assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem)) + assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem)) .hasMessage("is-closed-loop-disabled is set to true on VServer or VNF"); event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "inactive")); - assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem)) + assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem)) .hasMessage("prov-status is not ACTIVE on VServer or VNF"); // valid @@ -193,7 +193,7 @@ public class ControlLoopEventManager2Test { // invalid event.setTarget("unknown-target"); - assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem)) + assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem)) .isInstanceOf(ControlLoopException.class); } @@ -237,8 +237,8 @@ public class ControlLoopEventManager2Test { @Test public void testStartErrors() throws Exception { // wrong jvm - ControlLoopEventManager2 mgr2 = new ControlLoopEventManager2(params, event, workMem); - ControlLoopEventManager2 mgr3 = Serializer.roundTrip(mgr2); + ControlLoopEventManager2Drools mgr2 = new ControlLoopEventManager2Drools(params, event, workMem); + ControlLoopEventManager2Drools mgr3 = Serializer.roundTrip(mgr2); assertThatCode(() -> mgr3.start()).isInstanceOf(IllegalStateException.class) .hasMessage("manager is no longer active"); @@ -317,10 +317,10 @@ public class ControlLoopEventManager2Test { @Test public void testIsActive() throws Exception { - mgr = new ControlLoopEventManager2(params, event, workMem); + mgr = new ControlLoopEventManager2Drools(params, event, workMem); assertTrue(mgr.isActive()); - ControlLoopEventManager2 mgr2 = Serializer.roundTrip(mgr); + ControlLoopEventManager2Drools mgr2 = Serializer.roundTrip(mgr); assertFalse(mgr2.isActive()); } @@ -597,15 +597,15 @@ public class ControlLoopEventManager2Test { Map orig = event.getAai(); event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "true")); - assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem)) + assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem)) .isInstanceOf(IllegalStateException.class); event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_IS_CLOSED_LOOP_DISABLED, "true")); - assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem)) + assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem)) .isInstanceOf(IllegalStateException.class); event.setAai(addAai(orig, ControlLoopEventManager2.PNF_IS_IN_MAINT, "true")); - assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem)) + assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem)) .isInstanceOf(IllegalStateException.class); } @@ -620,17 +620,16 @@ public class ControlLoopEventManager2Test { Map orig = event.getAai(); event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "ACTIVE")); - assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException(); + assertThatCode(() -> new ControlLoopEventManager2Drools(params, event, workMem)).doesNotThrowAnyException(); event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_PROV_STATUS, "inactive")); - assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem)) + assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem)) .isInstanceOf(IllegalStateException.class); event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_PROV_STATUS, "ACTIVE")); - assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException(); - + assertThatCode(() -> new ControlLoopEventManager2Drools(params, event, workMem)).doesNotThrowAnyException(); event.setAai(addAai(orig, ControlLoopEventManager2.GENERIC_VNF_PROV_STATUS, "inactive")); - assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem)) + assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem)) .isInstanceOf(IllegalStateException.class); } @@ -640,15 +639,15 @@ public class ControlLoopEventManager2Test { for (String value : Arrays.asList("yes", "y", "true", "t", "yEs", "trUe")) { event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, value)); - assertThatThrownBy(() -> new ControlLoopEventManager2(params, event, workMem)) + assertThatThrownBy(() -> new ControlLoopEventManager2Drools(params, event, workMem)) .isInstanceOf(IllegalStateException.class); } event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "false")); - assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException(); + assertThatCode(() -> new ControlLoopEventManager2Drools(params, event, workMem)).doesNotThrowAnyException(); event.setAai(addAai(orig, ControlLoopEventManager2.VSERVER_IS_CLOSED_LOOP_DISABLED, "no")); - assertThatCode(() -> new ControlLoopEventManager2(params, event, workMem)).doesNotThrowAnyException(); + assertThatCode(() -> new ControlLoopEventManager2Drools(params, event, workMem)).doesNotThrowAnyException(); } @Test @@ -684,7 +683,7 @@ public class ControlLoopEventManager2Test { @Test public void testGetBlockingExecutor() throws Exception { - mgr = new ControlLoopEventManager2(params, event, workMem); + mgr = new ControlLoopEventManager2Drools(params, event, workMem); assertThatCode(() -> mgr.getBlockingExecutor()).doesNotThrowAnyException(); } @@ -764,7 +763,7 @@ public class ControlLoopEventManager2Test { } - private class MyManager extends ControlLoopEventManager2 { + private class MyManager extends ControlLoopEventManager2Drools { private static final long serialVersionUID = 1L; public MyManager(ControlLoopParams params, VirtualControlLoopEvent event, WorkingMemory workMem) -- cgit 1.2.3-korg