119d14651386d8392816108724c6b834135360d3
[policy/drools-applications.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
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
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
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=========================================================
19  */
20
21 package org.onap.policy.controlloop.eventmanager;
22
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;
37
38
39 /**
40  * Data for an individual lock.
41  */
42 public class LockData implements LockCallback {
43     private static final Logger logger = LoggerFactory.getLogger(LockData.class);
44
45     private final String targetEntity;
46     private final UUID requestId;
47
48     /**
49      * Time when this was created.
50      */
51     private final Instant createTime = Instant.now();
52
53     /**
54      * Future for obtaining the lock. Initially incomplete.
55      */
56     private final AtomicReference<CompletableFuture<OperationOutcome>> future =
57                     new AtomicReference<>(new CompletableFuture<>());
58
59     /**
60      * The lock.
61      */
62     private Lock theLock = null;
63
64     /**
65      * Listeners to invoke if the lock is unavailable/lost.
66      */
67     private final List<Consumer<OperationOutcome>> unavailableCallbacks = new ArrayList<>();
68
69     /**
70      * Set to a failed outcome, if the lock becomes unavailable.
71      */
72     private OperationOutcome failedOutcome = null;
73
74
75     /**
76      * Constructs the object.
77      *
78      * @param targetEntity target entity
79      */
80     public LockData(String targetEntity, UUID requestId) {
81         this.targetEntity = targetEntity;
82         this.requestId = requestId;
83     }
84
85     /**
86      * Gets the future to be completed when the lock operation completes.
87      *
88      * @return the lock operation future
89      */
90     public CompletableFuture<OperationOutcome> getFuture() {
91         return future.get();
92     }
93
94     /**
95      * Adds a callback to be invoked if the lock becomes unavailable.
96      *
97      * @param callback callback to be added
98      */
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);
104                 return;
105             }
106         }
107
108         // already failed - invoke the callback immediately
109         callback.accept(failedOutcome);
110     }
111
112     /**
113      * Frees the lock.
114      */
115     public void free() {
116         Lock lock;
117
118         synchronized (this) {
119             if ((lock = theLock) == null) {
120                 return;
121             }
122         }
123
124         lock.free();
125     }
126
127     @Override
128     public synchronized void lockAvailable(Lock lock) {
129         logger.info("lock granted on {} for {}", targetEntity, requestId);
130         theLock = lock;
131
132         OperationOutcome outcome = makeOutcome();
133         outcome.setResult(OperationResult.SUCCESS);
134         outcome.setMessage(ControlLoopOperation.SUCCESS_MSG);
135
136         future.get().complete(outcome);
137     }
138
139     @Override
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);
146         }
147
148         /*
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.
151          */
152         future.getAndSet(CompletableFuture.completedFuture(failedOutcome)).complete(failedOutcome);
153
154         for (Consumer<OperationOutcome> callback : unavailableCallbacks) {
155             try {
156                 callback.accept(new OperationOutcome(failedOutcome));
157             } catch (RuntimeException e) {
158                 logger.warn("lock callback threw an exception for {}", requestId, e);
159             }
160         }
161
162         unavailableCallbacks.clear();
163     }
164
165     /**
166      * Makes a lock operation outcome.
167      *
168      * @return a new lock operation outcome
169      */
170     private OperationOutcome makeOutcome() {
171         OperationOutcome outcome = new OperationOutcome();
172         outcome.setActor(ControlLoopOperationManager2.LOCK_ACTOR);
173         outcome.setOperation(ControlLoopOperationManager2.LOCK_OPERATION);
174         outcome.setTarget(targetEntity);
175         outcome.setFinalOutcome(true);
176         outcome.setStart(createTime);
177         outcome.setEnd(Instant.now());
178
179         return outcome;
180     }
181 }