Point to snapshot versions
[policy/models.git] / models-interactions / model-actors / actorServiceProvider / src / main / java / org / onap / policy / controlloop / actorserviceprovider / controlloop / ControlLoopEventContext.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP
4  * ================================================================================
5  * Copyright (C) 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.actorserviceprovider.controlloop;
22
23 import java.io.Serializable;
24 import java.util.Map;
25 import java.util.UUID;
26 import java.util.concurrent.CompletableFuture;
27 import java.util.concurrent.ConcurrentHashMap;
28 import lombok.AccessLevel;
29 import lombok.Getter;
30 import lombok.NonNull;
31 import lombok.Setter;
32 import org.onap.policy.controlloop.VirtualControlLoopEvent;
33 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
34 import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
35
36 /**
37  * Context associated with a control loop event.
38  */
39 @Getter
40 @Setter
41 public class ControlLoopEventContext implements Serializable {
42     private static final long serialVersionUID = 1L;
43
44
45     private final VirtualControlLoopEvent event;
46
47     /**
48      * Enrichment data extracted from the event. Never {@code null}, though it may be
49      * immutable.
50      */
51     private final Map<String, String> enrichment;
52
53     /**
54      * Set of properties that have been stored in the context.
55      */
56     @Getter(AccessLevel.NONE)
57     @Setter(AccessLevel.NONE)
58     private Map<String, Serializable> properties = new ConcurrentHashMap<>();
59
60     /**
61      * When {@link #obtain(String, ControlLoopOperationParams)} is invoked and the
62      * specified property is not found in {@link #properties}, it is retrieved. This holds
63      * the futures for the operations retrieving the properties.
64      */
65     @Getter(AccessLevel.NONE)
66     @Setter(AccessLevel.NONE)
67     private transient Map<String, CompletableFuture<OperationOutcome>> retrievers = new ConcurrentHashMap<>();
68
69     /**
70      * Request ID extracted from the event, or a generated value if the event has no
71      * request id; never {@code null}.
72      */
73     private final UUID requestId;
74
75
76     /**
77      * Constructs the object.
78      *
79      * @param event event with which this is associated
80      */
81     public ControlLoopEventContext(@NonNull VirtualControlLoopEvent event) {
82         this.event = event;
83         this.requestId = (event.getRequestId() != null ? event.getRequestId() : UUID.randomUUID());
84         this.enrichment = (event.getAai() != null ? event.getAai() : Map.of());
85     }
86
87     /**
88      * Determines if the context contains a property.
89      *
90      * @param name name of the property of interest
91      * @return {@code true} if the context contains the property, {@code false} otherwise
92      */
93     public boolean contains(String name) {
94         return properties.containsKey(name);
95     }
96
97     /**
98      * Gets a property, casting it to the desired type.
99      *
100      * @param <T> desired type
101      * @param name name of the property whose value is to be retrieved
102      * @return the property's value, or {@code null} if it does not yet have a value
103      */
104     @SuppressWarnings("unchecked")
105     public <T> T getProperty(String name) {
106         return (T) properties.get(name);
107     }
108
109     /**
110      * Sets a property's value.
111      *
112      * @param name property name
113      * @param value new property value
114      */
115     public void setProperty(String name, Serializable value) {
116         properties.put(name, value);
117     }
118
119     /**
120      * Removes a property.
121      * @param name property name
122      */
123     public void removeProperty(String name) {
124         properties.remove(name);
125     }
126
127     /**
128      * Obtains the given property.
129      *
130      * @param name name of the desired property
131      * @param params parameters needed to perform the operation to retrieve the desired
132      *        property
133      * @return a future for retrieving the property, {@code null} if the property has
134      *         already been retrieved
135      */
136     public CompletableFuture<OperationOutcome> obtain(String name, ControlLoopOperationParams params) {
137         if (properties.containsKey(name)) {
138             return null;
139         }
140
141         /*
142          * Return any existing future, if it wasn't canceled. Otherwise, start a new
143          * request.
144          */
145
146         // @formatter:off
147         CompletableFuture<OperationOutcome> oldFuture =
148             retrievers.computeIfPresent(name, (key, future) -> future.isCancelled() ? null : future);
149         // @formatter:on
150
151         if (oldFuture != null) {
152             return oldFuture;
153         }
154
155         /*
156          * Note: must NOT invoke params.start() within retrievers.compute(), as start()
157          * may invoke obtain() which would cause a recursive update to the retrievers map.
158          */
159         CompletableFuture<OperationOutcome> future = params.start();
160
161         if ((oldFuture = retrievers.putIfAbsent(name, future)) != null) {
162             future.cancel(false);
163             return oldFuture;
164         }
165
166         return future;
167     }
168 }