00cfb1fc436850e91c6eed56f93df365815772fa
[ccsdk/sli/adaptors.git] / resource-assignment / provider / src / main / java / org / openecomp / sdnc / rm / comp / AllocationFunction.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 ONAP Intellectual Property. All rights
6  * reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  * 
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  * 
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.openecomp.sdnc.rm.comp;
23
24 import java.util.ArrayList;
25 import java.util.Collection;
26 import java.util.HashSet;
27 import java.util.Iterator;
28 import java.util.List;
29 import java.util.Set;
30 import java.util.SortedSet;
31 import java.util.TreeSet;
32
33 import org.openecomp.sdnc.lock.comp.LockHelper;
34 import org.openecomp.sdnc.lock.comp.ResourceLockedException;
35 import org.openecomp.sdnc.lock.comp.SynchronizedFunction;
36 import org.openecomp.sdnc.rm.dao.ResourceDao;
37 import org.openecomp.sdnc.rm.data.AllocationOutcome;
38 import org.openecomp.sdnc.rm.data.AllocationRequest;
39 import org.openecomp.sdnc.rm.data.AllocationStatus;
40 import org.openecomp.sdnc.rm.data.LabelAllocationOutcome;
41 import org.openecomp.sdnc.rm.data.LabelAllocationRequest;
42 import org.openecomp.sdnc.rm.data.LabelResource;
43 import org.openecomp.sdnc.rm.data.LimitAllocationOutcome;
44 import org.openecomp.sdnc.rm.data.LimitAllocationRequest;
45 import org.openecomp.sdnc.rm.data.LimitResource;
46 import org.openecomp.sdnc.rm.data.MultiAssetAllocationOutcome;
47 import org.openecomp.sdnc.rm.data.MultiAssetAllocationRequest;
48 import org.openecomp.sdnc.rm.data.MultiResourceAllocationOutcome;
49 import org.openecomp.sdnc.rm.data.MultiResourceAllocationRequest;
50 import org.openecomp.sdnc.rm.data.RangeAllocationOutcome;
51 import org.openecomp.sdnc.rm.data.RangeAllocationRequest;
52 import org.openecomp.sdnc.rm.data.RangeResource;
53 import org.openecomp.sdnc.rm.data.Resource;
54 import org.openecomp.sdnc.rm.data.ResourceKey;
55 import org.openecomp.sdnc.rm.data.ResourceType;
56 import org.openecomp.sdnc.rm.util.LabelUtil;
57 import org.openecomp.sdnc.rm.util.LimitUtil;
58 import org.openecomp.sdnc.rm.util.RangeUtil;
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 class AllocationFunction extends SynchronizedFunction {
63
64     @SuppressWarnings("unused")
65     private static final Logger log = LoggerFactory.getLogger(AllocationFunction.class);
66
67     private ResourceDao resourceDao;
68
69     private String applicationId;
70     private AllocationRequest request;
71     private AllocationOutcome outcome;
72
73     private List<Resource> updateList = new ArrayList<Resource>();
74
75     public AllocationFunction(LockHelper lockHelper, ResourceDao resourceDao, String applicationId,
76             AllocationRequest request, int lockTimeout) {
77         super(lockHelper, getLockNames(request), lockTimeout);
78         this.applicationId = applicationId;
79         this.resourceDao = resourceDao;
80         this.request = request;
81     }
82
83     private static Collection<String> getLockNames(AllocationRequest request) {
84         Set<String> lockResourceNames = new HashSet<String>();
85         addLockNames(lockResourceNames, request);
86         return lockResourceNames;
87     }
88
89     private static void addLockNames(Set<String> lockResourceNames, AllocationRequest request) {
90         if (request instanceof MultiAssetAllocationRequest) {
91             MultiAssetAllocationRequest req = (MultiAssetAllocationRequest) request;
92             if (req.assetIdList != null)
93                 lockResourceNames.addAll(req.assetIdList);
94         } else if (request instanceof MultiResourceAllocationRequest) {
95             MultiResourceAllocationRequest req = (MultiResourceAllocationRequest) request;
96             if (req.allocationRequestList != null)
97                 for (AllocationRequest request1 : req.allocationRequestList)
98                     addLockNames(lockResourceNames, request1);
99         } else if (request.assetId != null)
100             lockResourceNames.add(request.assetId);
101     }
102
103     @Override
104     public void _exec() throws ResourceLockedException {
105         outcome = allocate(request);
106         if (outcome.status == AllocationStatus.Success)
107             for (Resource r : updateList)
108                 resourceDao.saveResource(r);
109     }
110
111     private AllocationOutcome allocate(AllocationRequest allocationRequest) throws ResourceLockedException {
112         if (allocationRequest instanceof MultiAssetAllocationRequest)
113             return allocateMultiAsset((MultiAssetAllocationRequest) allocationRequest);
114         if (allocationRequest instanceof MultiResourceAllocationRequest)
115             return allocateMultiResource((MultiResourceAllocationRequest) allocationRequest);
116         if (allocationRequest instanceof LimitAllocationRequest)
117             return allocateLimit((LimitAllocationRequest) allocationRequest);
118         if (allocationRequest instanceof LabelAllocationRequest)
119             return allocateLabel((LabelAllocationRequest) allocationRequest);
120         if (allocationRequest instanceof RangeAllocationRequest)
121             return allocateRange((RangeAllocationRequest) allocationRequest);
122         return null;
123     }
124
125     private MultiAssetAllocationOutcome allocateMultiAsset(MultiAssetAllocationRequest req) {
126         // TODO Auto-generated method stub
127         return null;
128     }
129
130     private MultiResourceAllocationOutcome allocateMultiResource(MultiResourceAllocationRequest req) {
131         MultiResourceAllocationOutcome out = new MultiResourceAllocationOutcome();
132         out.request = req;
133         out.allocationOutcomeList = new ArrayList<AllocationOutcome>();
134         out.status = AllocationStatus.Success;
135
136         if (req.allocationRequestList != null)
137             for (AllocationRequest req1 : req.allocationRequestList) {
138                 AllocationOutcome out1 = allocate(req1);
139                 out.allocationOutcomeList.add(out1);
140                 if (out1.status != AllocationStatus.Success)
141                     out.status = AllocationStatus.Failure;
142             }
143
144         return out;
145     }
146
147     private LimitAllocationOutcome allocateLimit(LimitAllocationRequest req) {
148         LimitAllocationOutcome out = new LimitAllocationOutcome();
149         out.request = req;
150
151         Resource r = resourceDao.getResource(req.assetId, req.resourceName);
152         if (r == null) {
153             r = new LimitResource();
154             r.resourceKey = new ResourceKey();
155             r.resourceKey.assetId = req.assetId;
156             r.resourceKey.resourceName = req.resourceName;
157             r.resourceType = ResourceType.Limit;
158         } else {
159             if (r.resourceType != ResourceType.Limit) {
160                 out.status = AllocationStatus.ResourceNotFound;
161                 return out;
162             }
163             LimitUtil.recalculate((LimitResource) r);
164         }
165
166         LimitResource l = (LimitResource) r;
167         if (LimitUtil.checkLimit(l, req)) {
168             out.status = AllocationStatus.Success;
169             if (req.allocateCount > 0) {
170                 out.allocatedCount = LimitUtil.allocateLimit(l, req, applicationId);
171                 updateList.add(l);
172             }
173         } else
174             out.status = AllocationStatus.Failure;
175
176         out.used = l.used;
177         out.limit = req.checkLimit;
178
179         return out;
180     }
181
182     private LabelAllocationOutcome allocateLabel(LabelAllocationRequest req) {
183         LabelAllocationOutcome out = new LabelAllocationOutcome();
184
185         out.request = req;
186
187         Resource r = resourceDao.getResource(req.assetId, req.resourceName);
188         if (r == null) {
189             r = new LabelResource();
190             r.resourceKey = new ResourceKey();
191             r.resourceKey.assetId = req.assetId;
192             r.resourceKey.resourceName = req.resourceName;
193             r.resourceType = ResourceType.Label;
194         } else {
195             if (r.resourceType != ResourceType.Label) {
196                 out.status = AllocationStatus.ResourceNotFound;
197                 return out;
198             }
199             LabelUtil.recalculate((LabelResource) r);
200         }
201
202         LabelResource l = (LabelResource) r;
203         if (LabelUtil.checkLabel(l, req)) {
204             out.status = AllocationStatus.Success;
205             out.currentLabel = l.label;
206             if (req.allocate) {
207                 out.allocatedLabel = LabelUtil.allocateLabel(l, req, applicationId);
208                 updateList.add(l);
209             }
210         } else
211             out.status = AllocationStatus.Failure;
212
213         return out;
214     }
215
216     private RangeAllocationOutcome allocateRange(RangeAllocationRequest req) {
217         RangeAllocationOutcome out = new RangeAllocationOutcome();
218
219         out.request = req;
220
221         Resource r = resourceDao.getResource(req.assetId, req.resourceName);
222         if (r == null) {
223             r = new RangeResource();
224             r.resourceKey = new ResourceKey();
225             r.resourceKey.assetId = req.assetId;
226             r.resourceKey.resourceName = req.resourceName;
227             r.resourceType = ResourceType.Range;
228         } else {
229             if (r.resourceType != ResourceType.Range) {
230                 out.status = AllocationStatus.ResourceNotFound;
231                 return out;
232             }
233             RangeUtil.recalculate((RangeResource) r);
234         }
235
236         RangeResource rr = (RangeResource) r;
237         SortedSet<Integer> foundNumbers = null;
238         if (!req.check) {
239             out.status = AllocationStatus.Success;
240             foundNumbers = req.requestedNumbers;
241         } else {
242             if (req.requestedNumbers != null && req.requestedNumbers.size() > 0) {
243                 foundNumbers = req.requestedNumbers;
244                 out.status = AllocationStatus.Success;
245                 for (int n : foundNumbers)
246                     if (!RangeUtil.checkRange(rr, req, n)) {
247                         out.status = AllocationStatus.Failure;
248                         break;
249                     }
250             } else {
251                 foundNumbers = new TreeSet<Integer>();
252                 int foundCount = 0;
253
254                 // First try to reuse the numbers already taken by the same resource union
255                 SortedSet<Integer> uu = RangeUtil.getUsed(rr, req.resourceUnionId);
256                 if (uu != null && !uu.isEmpty()) {
257                     if (uu.size() >= req.requestedCount) {
258                         // Just take the first req.requestedCount numbers from uu
259                         Iterator<Integer> i = uu.iterator();
260                         while (foundCount < req.requestedCount) {
261                             foundNumbers.add(i.next());
262                             foundCount++;
263                         }
264                     } else {
265                         // Additional numbers are requested. Try to find them starting from
266                         // the minimum we have in uu (the first element) towards the min
267                         // parameter, and then starting from the maximum in uu (the last
268                         // element) towards the max parameter.
269                         // NOTE: In case of request for sequential numbers, the parameters
270                         // alignBlockSize and alignModulus are ignored. It would be harder
271                         // to take them into account, and currently it is not needed.
272
273                         int uumin = uu.first() - 1;
274                         int uumax = uu.last() + 1;
275                         foundNumbers.addAll(uu);
276                         foundCount = uu.size();
277                         for (int n = uumin; foundCount < req.requestedCount && n >= req.checkMin; n--) {
278                             if (RangeUtil.checkRange(rr, req, n)) {
279                                 foundNumbers.add(n);
280                                 foundCount++;
281                             } else if (req.sequential)
282                                 break;
283                         }
284                         for (int n = uumax; foundCount < req.requestedCount && n <= req.checkMax; n++) {
285                             if (RangeUtil.checkRange(rr, req, n)) {
286                                 foundNumbers.add(n);
287                                 foundCount++;
288                             } else if (req.sequential)
289                                 break;
290                         }
291
292                         // If we could not find enough numbers trying to reuse currently
293                         // allocated, reset foundNumbers and foundCount, continue with
294                         // the normal allocation of new numbers.
295                         if (foundCount < req.requestedCount) {
296                             foundNumbers = new TreeSet<Integer>();
297                             foundCount = 0;
298                         }
299                     }
300                 }
301
302                 for (int n = req.checkMin; foundCount < req.requestedCount && n <= req.checkMax; n++)
303                     if (RangeUtil.checkRange(rr, req, n)) {
304                         foundNumbers.add(n);
305                         foundCount++;
306                     } else if (req.sequential)
307                         foundCount = 0;
308
309                 out.status = foundCount == req.requestedCount ? AllocationStatus.Success : AllocationStatus.Failure;
310             }
311         }
312
313         if (out.status == AllocationStatus.Success) {
314             out.allocated = foundNumbers;
315             if (req.allocate) {
316                 RangeUtil.allocateRange(rr, out.allocated, req, applicationId);
317                 updateList.add(rr);
318             }
319         } else
320             out.allocated = new TreeSet<Integer>();
321
322         out.used = rr.used;
323
324         return out;
325     }
326
327     public AllocationOutcome getAllocationOutcome() {
328         return outcome;
329     }
330 }