2  * ============LICENSE_START=======================================================
 
   4  * ================================================================================
 
   5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
 
   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
 
  12  *      http://www.apache.org/licenses/LICENSE-2.0
 
  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=========================================================
 
  22 package org.onap.ccsdk.sli.adaptors.rm.comp;
 
  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;
 
  30 import java.util.SortedSet;
 
  31 import java.util.TreeSet;
 
  32 import org.onap.ccsdk.sli.adaptors.lock.comp.LockHelper;
 
  33 import org.onap.ccsdk.sli.adaptors.lock.comp.ResourceLockedException;
 
  34 import org.onap.ccsdk.sli.adaptors.lock.comp.SynchronizedFunction;
 
  35 import org.onap.ccsdk.sli.adaptors.rm.dao.ResourceDao;
 
  36 import org.onap.ccsdk.sli.adaptors.rm.data.AllocationOutcome;
 
  37 import org.onap.ccsdk.sli.adaptors.rm.data.AllocationRequest;
 
  38 import org.onap.ccsdk.sli.adaptors.rm.data.AllocationStatus;
 
  39 import org.onap.ccsdk.sli.adaptors.rm.data.LabelAllocationOutcome;
 
  40 import org.onap.ccsdk.sli.adaptors.rm.data.LabelAllocationRequest;
 
  41 import org.onap.ccsdk.sli.adaptors.rm.data.LabelResource;
 
  42 import org.onap.ccsdk.sli.adaptors.rm.data.LimitAllocationOutcome;
 
  43 import org.onap.ccsdk.sli.adaptors.rm.data.LimitAllocationRequest;
 
  44 import org.onap.ccsdk.sli.adaptors.rm.data.LimitResource;
 
  45 import org.onap.ccsdk.sli.adaptors.rm.data.MultiAssetAllocationOutcome;
 
  46 import org.onap.ccsdk.sli.adaptors.rm.data.MultiAssetAllocationRequest;
 
  47 import org.onap.ccsdk.sli.adaptors.rm.data.MultiResourceAllocationOutcome;
 
  48 import org.onap.ccsdk.sli.adaptors.rm.data.MultiResourceAllocationRequest;
 
  49 import org.onap.ccsdk.sli.adaptors.rm.data.Range;
 
  50 import org.onap.ccsdk.sli.adaptors.rm.data.RangeAllocationOutcome;
 
  51 import org.onap.ccsdk.sli.adaptors.rm.data.RangeAllocationRequest;
 
  52 import org.onap.ccsdk.sli.adaptors.rm.data.RangeResource;
 
  53 import org.onap.ccsdk.sli.adaptors.rm.data.Resource;
 
  54 import org.onap.ccsdk.sli.adaptors.rm.data.ResourceKey;
 
  55 import org.onap.ccsdk.sli.adaptors.rm.data.ResourceType;
 
  56 import org.onap.ccsdk.sli.adaptors.rm.util.LabelUtil;
 
  57 import org.onap.ccsdk.sli.adaptors.rm.util.LimitUtil;
 
  58 import org.onap.ccsdk.sli.adaptors.rm.util.RangeUtil;
 
  59 import org.slf4j.Logger;
 
  60 import org.slf4j.LoggerFactory;
 
  62 class AllocationFunction extends SynchronizedFunction {
 
  64     @SuppressWarnings("unused")
 
  65     private static final Logger log = LoggerFactory.getLogger(AllocationFunction.class);
 
  67     private ResourceDao resourceDao;
 
  69     private AllocationRequest request;
 
  70     private AllocationOutcome outcome;
 
  72     private List<Resource> updateList = new ArrayList<>();
 
  74     public AllocationFunction(LockHelper lockHelper, ResourceDao resourceDao, AllocationRequest request,
 
  76         super(lockHelper, getLockNames(request), lockTimeout);
 
  77         this.resourceDao = resourceDao;
 
  78         this.request = request;
 
  81     private static Collection<String> getLockNames(AllocationRequest request) {
 
  82         Set<String> lockResourceNames = new HashSet<>();
 
  83         addLockNames(lockResourceNames, request);
 
  84         return lockResourceNames;
 
  87     private static void addLockNames(Set<String> lockResourceNames, AllocationRequest request) {
 
  88         if (request instanceof MultiAssetAllocationRequest) {
 
  89             MultiAssetAllocationRequest req = (MultiAssetAllocationRequest) request;
 
  90             if (req.assetIdList != null) {
 
  91                 lockResourceNames.addAll(req.assetIdList);
 
  93         } else if (request instanceof MultiResourceAllocationRequest) {
 
  94             MultiResourceAllocationRequest req = (MultiResourceAllocationRequest) request;
 
  95             if (req.allocationRequestList != null) {
 
  96                 for (AllocationRequest request1 : req.allocationRequestList) {
 
  97                     addLockNames(lockResourceNames, request1);
 
 100         } else if (request.assetId != null) {
 
 101             lockResourceNames.add(request.assetId);
 
 106     public void _exec() throws ResourceLockedException {
 
 107         outcome = allocate(request);
 
 108         if (outcome.status == AllocationStatus.Success) {
 
 109             for (Resource r : updateList) {
 
 110                 resourceDao.saveResource(r);
 
 115     private AllocationOutcome allocate(AllocationRequest allocationRequest) throws ResourceLockedException {
 
 116         if (allocationRequest instanceof MultiAssetAllocationRequest) {
 
 117             return allocateMultiAsset((MultiAssetAllocationRequest) allocationRequest);
 
 119         if (allocationRequest instanceof MultiResourceAllocationRequest) {
 
 120             return allocateMultiResource((MultiResourceAllocationRequest) allocationRequest);
 
 122         if (allocationRequest instanceof LimitAllocationRequest) {
 
 123             return allocateLimit((LimitAllocationRequest) allocationRequest);
 
 125         if (allocationRequest instanceof LabelAllocationRequest) {
 
 126             return allocateLabel((LabelAllocationRequest) allocationRequest);
 
 128         if (allocationRequest instanceof RangeAllocationRequest) {
 
 129             return allocateRange((RangeAllocationRequest) allocationRequest);
 
 134     private MultiAssetAllocationOutcome allocateMultiAsset(MultiAssetAllocationRequest req) {
 
 135         // TODO Auto-generated method stub
 
 139     private MultiResourceAllocationOutcome allocateMultiResource(MultiResourceAllocationRequest req) {
 
 140         MultiResourceAllocationOutcome out = new MultiResourceAllocationOutcome();
 
 142         out.allocationOutcomeList = new ArrayList<>();
 
 143         out.status = AllocationStatus.Success;
 
 145         if (req.allocationRequestList != null) {
 
 146             for (AllocationRequest req1 : req.allocationRequestList) {
 
 147                 AllocationOutcome out1 = allocate(req1);
 
 148                 out.allocationOutcomeList.add(out1);
 
 149                 if (out1.status != AllocationStatus.Success) {
 
 150                     out.status = AllocationStatus.Failure;
 
 158     private LimitAllocationOutcome allocateLimit(LimitAllocationRequest req) {
 
 159         LimitAllocationOutcome out = new LimitAllocationOutcome();
 
 162         Resource r = resourceDao.getResource(req.assetId, req.resourceName);
 
 164             r = new LimitResource();
 
 165             r.resourceKey = new ResourceKey();
 
 166             r.resourceKey.assetId = req.assetId;
 
 167             r.resourceKey.resourceName = req.resourceName;
 
 168             r.resourceType = ResourceType.Limit;
 
 170             if (r.resourceType != ResourceType.Limit) {
 
 171                 out.status = AllocationStatus.ResourceNotFound;
 
 174             LimitUtil.recalculate((LimitResource) r);
 
 177         LimitResource l = (LimitResource) r;
 
 178         if (LimitUtil.checkLimit(l, req)) {
 
 179             out.status = AllocationStatus.Success;
 
 180             if (req.allocateCount > 0) {
 
 181                 out.allocatedCount = LimitUtil.allocateLimit(l, req);
 
 185             out.status = AllocationStatus.Failure;
 
 189         out.limit = req.checkLimit;
 
 194     private LabelAllocationOutcome allocateLabel(LabelAllocationRequest req) {
 
 195         LabelAllocationOutcome out = new LabelAllocationOutcome();
 
 199         Resource r = resourceDao.getResource(req.assetId, req.resourceName);
 
 201             r = new LabelResource();
 
 202             r.resourceKey = new ResourceKey();
 
 203             r.resourceKey.assetId = req.assetId;
 
 204             r.resourceKey.resourceName = req.resourceName;
 
 205             r.resourceType = ResourceType.Label;
 
 207             if (r.resourceType != ResourceType.Label) {
 
 208                 out.status = AllocationStatus.ResourceNotFound;
 
 211             LabelUtil.recalculate((LabelResource) r);
 
 214         LabelResource l = (LabelResource) r;
 
 215         if (LabelUtil.checkLabel(l, req)) {
 
 216             out.status = AllocationStatus.Success;
 
 217             out.currentLabel = l.label;
 
 219                 out.allocatedLabel = LabelUtil.allocateLabel(l, req);
 
 223             out.status = AllocationStatus.Failure;
 
 229     private RangeAllocationOutcome allocateRange(RangeAllocationRequest req) {
 
 230         RangeAllocationOutcome out = new RangeAllocationOutcome();
 
 234         Resource r = resourceDao.getResource(req.assetId, req.resourceName);
 
 236             r = new RangeResource();
 
 237             r.resourceKey = new ResourceKey();
 
 238             r.resourceKey.assetId = req.assetId;
 
 239             r.resourceKey.resourceName = req.resourceName;
 
 240             r.resourceType = ResourceType.Range;
 
 242             if (r.resourceType != ResourceType.Range) {
 
 243                 out.status = AllocationStatus.ResourceNotFound;
 
 246             RangeUtil.recalculate((RangeResource) r);
 
 249         RangeResource rr = (RangeResource) r;
 
 250         SortedSet<Integer> foundNumbers = null;
 
 252             out.status = AllocationStatus.Success;
 
 253             foundNumbers = req.requestedNumbers;
 
 255             if (req.requestedNumbers != null && req.requestedNumbers.size() > 0) {
 
 256                 foundNumbers = req.requestedNumbers;
 
 257                 out.status = AllocationStatus.Success;
 
 258                 for (int n : foundNumbers) {
 
 259                     if (!RangeUtil.checkRange(rr, req, n)) {
 
 260                         out.status = AllocationStatus.Failure;
 
 265                 foundNumbers = new TreeSet<>();
 
 268                 // First try to reuse the numbers already taken by the same resource union
 
 269                 SortedSet<Integer> uu = RangeUtil.getUsed(rr, req.resourceUnionId);
 
 270                 if (uu != null && !uu.isEmpty() && req.replace) {
 
 271                     if (uu.size() >= req.requestedCount) {
 
 272                         // Just take the first req.requestedCount numbers from uu
 
 273                         Iterator<Integer> i = uu.iterator();
 
 274                         while (foundCount < req.requestedCount) {
 
 275                             foundNumbers.add(i.next());
 
 279                         // Additional numbers are requested. Try to find them starting from
 
 280                         // the minimum we have in uu (the first element) towards the min
 
 281                         // parameter, and then starting from the maximum in uu (the last
 
 282                         // element) towards the max parameter.
 
 283                         // NOTE: In case of request for sequential numbers, the parameters
 
 284                         // alignBlockSize and alignModulus are ignored. It would be harder
 
 285                         // to take them into account, and currently it is not needed.
 
 287                         // Request may contain multiple ranges. We will find the range from the request
 
 288                         // that contains the currently used numbers (the first one). We will only look
 
 289                         // for additional numbers in that range.
 
 292                         if (req.rangeList != null) {
 
 293                             for (Range range1 : req.rangeList) {
 
 294                                 if (uu.first() >= range1.min && uu.first() <= range1.max) {
 
 302                             int uumin = uu.first() - 1;
 
 303                             int uumax = uu.last() + 1;
 
 304                             foundNumbers.addAll(uu);
 
 305                             foundCount = uu.size();
 
 306                             for (int n = uumin; foundCount < req.requestedCount && n >= range.min; n--) {
 
 307                                 if (RangeUtil.checkRange(rr, req, n)) {
 
 310                                 } else if (req.sequential) {
 
 314                             for (int n = uumax; foundCount < req.requestedCount && n <= range.max; n++) {
 
 315                                 if (RangeUtil.checkRange(rr, req, n)) {
 
 318                                 } else if (req.sequential) {
 
 324                         // If we could not find enough numbers trying to reuse currently
 
 325                         // allocated, reset foundNumbers and foundCount, continue with
 
 326                         // the normal allocation of new numbers.
 
 327                         if (foundCount < req.requestedCount) {
 
 328                             foundNumbers = new TreeSet<>();
 
 334                 if (req.rangeList != null) {
 
 335                     if (req.reverseOrder) {
 
 336                         for (int i = req.rangeList.size() - 1; i >= 0; i--) {
 
 337                             Range range = req.rangeList.get(i);
 
 338                             for (int n = range.max; foundCount < req.requestedCount && n >= range.min; n--) {
 
 339                                 if (RangeUtil.checkRange(rr, req, n)) {
 
 342                                 } else if (req.sequential) {
 
 348                         for (Range range : req.rangeList) {
 
 349                             for (int n = range.min; foundCount < req.requestedCount && n <= range.max; n++) {
 
 350                                 if (RangeUtil.checkRange(rr, req, n)) {
 
 353                                 } else if (req.sequential) {
 
 361                 out.status = foundCount == req.requestedCount ? AllocationStatus.Success : AllocationStatus.Failure;
 
 365         if (out.status == AllocationStatus.Success) {
 
 366             out.allocated = foundNumbers;
 
 368                 RangeUtil.allocateRange(rr, out.allocated, req);
 
 372             out.allocated = new TreeSet<>();
 
 380     public AllocationOutcome getAllocationOutcome() {