Generate notifications when policies change
[policy/pap.git] / main / src / main / java / org / onap / policy / pap / main / comm / PdpRequests.java
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP PAP
4  * ================================================================================
5  * Copyright (C) 2019 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.pap.main.comm;
22
23 import lombok.Getter;
24 import org.onap.policy.models.pdp.concepts.PdpMessage;
25 import org.onap.policy.pap.main.comm.msgdata.Request;
26 import org.onap.policy.pap.main.notification.PolicyNotifier;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29
30 /**
31  * Tracks requests associated with a particular PDP. Requests may be broadcast requests or
32  * singleton requests (i.e., destined for a single PDP).
33  */
34 public class PdpRequests {
35     private static final Logger logger = LoggerFactory.getLogger(PdpRequests.class);
36
37     /**
38      * The maximum request priority + 1.
39      */
40     private static final int MAX_PRIORITY = 2;
41
42     /**
43      * Name of the PDP with which the requests are associated.
44      */
45     @Getter
46     private final String pdpName;
47
48     /**
49      * Notifier for policy update completions.
50      */
51     @Getter
52     private final PolicyNotifier notifier;
53
54     /**
55      * Index of request currently being published.
56      */
57     private int curIndex = 0;
58
59     /**
60      * Singleton requests. Items may be {@code null}.
61      */
62     private Request[] singletons = new Request[MAX_PRIORITY];
63
64
65     /**
66      * Constructs the object.
67      *
68      * @param pdpName name of the PDP with which the requests are associated
69      */
70     public PdpRequests(String pdpName, PolicyNotifier notifier) {
71         this.pdpName = pdpName;
72         this.notifier = notifier;
73     }
74
75     /**
76      * Adds a singleton request.
77      *
78      * @param request the request to be added
79      */
80     public void addSingleton(Request request) {
81
82         request.setNotifier(notifier);
83
84         if (request.getMessage().getName() == null) {
85             throw new IllegalArgumentException("unexpected broadcast for " + pdpName);
86         }
87
88         if (checkExisting(request)) {
89             // have an existing request that's similar - discard this request
90             return;
91         }
92
93         // no existing request of this type
94
95         int priority = request.getPriority();
96         singletons[priority] = request;
97
98         // stop publishing anything of a lower priority
99         final QueueToken<PdpMessage> token = stopPublishingLowerPriority(priority);
100
101         // start publishing if nothing of higher priority
102         if (higherPrioritySingleton(priority)) {
103             logger.info("{} not publishing due to priority higher than {}", pdpName, priority);
104             return;
105         }
106
107         curIndex = priority;
108         request.startPublishing(token);
109     }
110
111     /**
112      * Checks for an existing request.
113      *
114      * @param request the request of interest
115      * @return {@code true} if a similar request already exists, {@code false} otherwise
116      */
117     private boolean checkExisting(Request request) {
118
119         return checkExistingSingleton(request);
120     }
121
122     /**
123      * Checks for an existing singleton request.
124      *
125      * @param request the request of interest
126      * @return {@code true} if a similar singleton request already exists, {@code false}
127      *         otherwise
128      */
129     private boolean checkExistingSingleton(Request request) {
130
131         Request exsingle = singletons[request.getPriority()];
132
133         if (exsingle == null) {
134             return false;
135         }
136
137         if (exsingle.isSameContent(request)) {
138             // unchanged from existing request
139             logger.info("{} message content unchanged for {}", pdpName, exsingle.getClass().getSimpleName());
140             return true;
141         }
142
143         // reconfigure the existing request
144         PdpMessage message = request.getMessage();
145         exsingle.reconfigure(message, null);
146
147         // still have a singleton in the queue for this request
148         return true;
149     }
150
151     /**
152      * Stops all publishing and removes this PDP from any broadcast messages.
153      */
154     public void stopPublishing() {
155         // stop singletons
156         for (int x = 0; x < MAX_PRIORITY; ++x) {
157             Request single = singletons[x];
158
159             if (single != null) {
160                 singletons[x] = null;
161                 single.stopPublishing();
162             }
163         }
164     }
165
166     /**
167      * Stops publishing requests of a lower priority than the specified priority.
168      *
169      * @param priority priority of interest
170      * @return the token that was being used to publish a lower priority request
171      */
172     private QueueToken<PdpMessage> stopPublishingLowerPriority(int priority) {
173
174         // stop singletons
175         for (int x = 0; x < priority; ++x) {
176             Request single = singletons[x];
177
178             if (single != null) {
179                 logger.info("{} stop publishing priority {}", pdpName, single.getPriority());
180
181                 QueueToken<PdpMessage> token = single.stopPublishing(false);
182                 if (token != null) {
183                     // found one that was publishing
184                     return token;
185                 }
186             }
187         }
188
189         return null;
190     }
191
192     /**
193      * Starts publishing the next request in the queue.
194      *
195      * @param request the request that just completed
196      * @return {@code true} if there is another request in the queue, {@code false} if all
197      *         requests for this PDP have been processed
198      */
199     public boolean startNextRequest(Request request) {
200         if (!zapRequest(curIndex, request)) {
201             // not at curIndex - look for it in other indices
202             for (int x = 0; x < MAX_PRIORITY; ++x) {
203                 if (zapRequest(x, request)) {
204                     break;
205                 }
206             }
207         }
208
209         // find/start the highest priority request
210         for (curIndex = MAX_PRIORITY - 1; curIndex >= 0; --curIndex) {
211
212             if (singletons[curIndex] != null) {
213                 logger.info("{} start publishing priority {}", pdpName, curIndex);
214
215                 singletons[curIndex].startPublishing();
216                 return true;
217             }
218         }
219
220         logger.info("{} has no more requests", pdpName);
221         curIndex = 0;
222
223         return false;
224     }
225
226     /**
227      * Zaps request pointers, if the request appears at the given index.
228      *
229      * @param index index to examine
230      * @param request request of interest
231      * @return {@code true} if a request pointer was zapped, {@code false} if the request
232      *         did not appear at the given index
233      */
234     private boolean zapRequest(int index, Request request) {
235         if (singletons[index] == request) {
236             singletons[index] = null;
237             return true;
238         }
239
240         return false;
241     }
242
243     /**
244      * Determines if any singleton request, with a higher priority, is associated with the
245      * PDP.
246      *
247      * @param priority priority of interest
248      *
249      * @return {@code true} if the PDP has a singleton, {@code false} otherwise
250      */
251     private boolean higherPrioritySingleton(int priority) {
252         for (int x = priority + 1; x < MAX_PRIORITY; ++x) {
253             if (singletons[x] != null) {
254                 return true;
255             }
256         }
257
258         return false;
259     }
260 }