[CCSDK-6] Populate seed code
[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 }