2 * ============LICENSE_START=======================================================
4 * ================================================================================
5 * Copyright (C) 2017-2020 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.controlloop.eventmanager;
23 import java.time.Instant;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.UUID;
27 import java.util.concurrent.CompletableFuture;
28 import java.util.concurrent.atomic.AtomicReference;
29 import java.util.function.Consumer;
30 import org.onap.policy.controlloop.ControlLoopOperation;
31 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
32 import org.onap.policy.controlloop.actorserviceprovider.OperationResult;
33 import org.onap.policy.drools.core.lock.Lock;
34 import org.onap.policy.drools.core.lock.LockCallback;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
40 * Data for an individual lock.
42 public class LockData implements LockCallback {
43 private static final Logger logger = LoggerFactory.getLogger(LockData.class);
45 private final String targetEntity;
46 private final UUID requestId;
49 * Time when this was created.
51 private final Instant createTime = Instant.now();
54 * Future for obtaining the lock. Initially incomplete.
56 private final AtomicReference<CompletableFuture<OperationOutcome>> future =
57 new AtomicReference<>(new CompletableFuture<>());
62 private Lock theLock = null;
65 * Listeners to invoke if the lock is unavailable/lost.
67 private final List<Consumer<OperationOutcome>> unavailableCallbacks = new ArrayList<>();
70 * Set to a failed outcome, if the lock becomes unavailable.
72 private OperationOutcome failedOutcome = null;
76 * Constructs the object.
78 * @param targetEntity target entity
80 public LockData(String targetEntity, UUID requestId) {
81 this.targetEntity = targetEntity;
82 this.requestId = requestId;
86 * Gets the future to be completed when the lock operation completes.
88 * @return the lock operation future
90 public CompletableFuture<OperationOutcome> getFuture() {
95 * Adds a callback to be invoked if the lock becomes unavailable.
97 * @param callback callback to be added
99 public void addUnavailableCallback(Consumer<OperationOutcome> callback) {
100 synchronized (this) {
101 if (failedOutcome == null) {
102 // hasn't failed yet - add it to the list
103 unavailableCallbacks.add(callback);
108 // already failed - invoke the callback immediately
109 callback.accept(failedOutcome);
118 synchronized (this) {
119 if ((lock = theLock) == null) {
128 public synchronized void lockAvailable(Lock lock) {
129 logger.info("lock granted on {} for {}", targetEntity, requestId);
132 OperationOutcome outcome = makeOutcome();
133 outcome.setResult(OperationResult.SUCCESS);
134 outcome.setMessage(ControlLoopOperation.SUCCESS_MSG);
136 future.get().complete(outcome);
140 public void lockUnavailable(Lock unused) {
141 synchronized (this) {
142 logger.warn("lock unavailable on {} for {}", targetEntity, requestId);
143 failedOutcome = makeOutcome();
144 failedOutcome.setResult(OperationResult.FAILURE);
145 failedOutcome.setMessage(ControlLoopOperation.FAILED_MSG);
149 * In case the future was already completed successfully, replace it with a failed
150 * future, but complete the old one, too, in case it wasn't completed yet.
152 future.getAndSet(CompletableFuture.completedFuture(failedOutcome)).complete(failedOutcome);
154 for (Consumer<OperationOutcome> callback : unavailableCallbacks) {
156 callback.accept(new OperationOutcome(failedOutcome));
157 } catch (RuntimeException e) {
158 logger.warn("lock callback threw an exception for {}", requestId, e);
162 unavailableCallbacks.clear();
166 * Makes a lock operation outcome.
168 * @return a new lock operation outcome
170 private OperationOutcome makeOutcome() {
171 OperationOutcome outcome = new OperationOutcome();
172 outcome.setActor(ActorConstants.LOCK_ACTOR);
173 outcome.setOperation(ActorConstants.LOCK_OPERATION);
174 outcome.setTarget(targetEntity);
175 outcome.setFinalOutcome(true);
176 outcome.setStart(createTime);
177 outcome.setEnd(Instant.now());