Nodes query rewritten to generic rest client
[vid.git] / vid-app-common / src / main / java / org / onap / vid / services / AsyncInstantiationBusinessLogicImpl.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * VID
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2018 Nokia. All rights 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.onap.vid.services;
23
24 import com.google.common.collect.ImmutableMap;
25 import io.joshworks.restclient.http.HttpResponse;
26 import java.io.IOException;
27 import org.apache.commons.collections.CollectionUtils;
28 import org.apache.commons.io.IOUtils;
29 import org.apache.commons.lang3.StringUtils;
30 import org.hibernate.SessionFactory;
31 import org.onap.vid.aai.AaiClientInterface;
32 import org.onap.vid.aai.AaiOverTLSClientInterface;
33 import org.onap.vid.aai.AaiResponse;
34 import org.onap.vid.aai.exceptions.InvalidAAIResponseException;
35 import org.onap.vid.aai.model.AaiNodeQueryResponse;
36 import org.onap.vid.aai.model.ResourceType;
37 import org.onap.vid.changeManagement.RequestDetailsWrapper;
38 import org.onap.vid.domain.mso.CloudConfiguration;
39 import org.onap.vid.domain.mso.SubscriberInfo;
40 import org.onap.vid.exceptions.DbFailureUncheckedException;
41 import org.onap.vid.exceptions.GenericUncheckedException;
42 import org.onap.vid.exceptions.MaxRetriesException;
43 import org.onap.vid.exceptions.OperationNotAllowedException;
44 import org.onap.vid.job.Job;
45 import org.onap.vid.job.Job.JobStatus;
46 import org.onap.vid.job.JobAdapter;
47 import org.onap.vid.job.JobType;
48 import org.onap.vid.job.JobsBrokerService;
49 import org.onap.vid.model.JobAuditStatus;
50 import org.onap.vid.model.NameCounter;
51 import org.onap.vid.model.ServiceInfo;
52 import org.onap.vid.model.serviceInstantiation.ServiceInstantiation;
53 import org.onap.vid.model.serviceInstantiation.VfModule;
54 import org.onap.vid.model.serviceInstantiation.Vnf;
55 import org.onap.vid.mso.MsoBusinessLogicImpl;
56 import org.onap.vid.mso.MsoProperties;
57 import org.onap.vid.mso.model.ServiceInstantiationRequestDetails;
58 import org.onap.vid.mso.rest.AsyncRequestStatus;
59 import org.onap.vid.utils.DaoUtils;
60 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
61 import org.onap.portalsdk.core.service.DataAccessService;
62 import org.springframework.beans.factory.annotation.Autowired;
63 import org.springframework.stereotype.Service;
64
65 import java.sql.Timestamp;
66 import java.time.LocalDateTime;
67 import java.util.*;
68 import java.util.function.Consumer;
69 import java.util.stream.Collectors;
70
71 import static org.onap.vid.utils.Logging.debugRequestDetails;
72
73 @Service
74 public class AsyncInstantiationBusinessLogicImpl implements AsyncInstantiationBusinessLogic {
75
76     private static final int MAX_RETRIES_GETTING_COUNTER = 100;
77     private static final int MAX_RETRIES_GETTING_FREE_NAME_FROM_AAI = 10000;
78     private static final String NAME_FOR_CHECK_AAI_STATUS = "NAME_FOR_CHECK_AAI_STATUS";
79
80     private final DataAccessService dataAccessService;
81
82     private final JobAdapter jobAdapter;
83
84     private final JobsBrokerService jobService;
85
86     private SessionFactory sessionFactory;
87
88     private AaiClientInterface aaiClient;
89
90     private AaiOverTLSClientInterface aaiOverTLSClient;
91
92     private int maxRetriesGettingFreeNameFromAai = MAX_RETRIES_GETTING_FREE_NAME_FROM_AAI;
93
94     private static final EELFLoggerDelegate logger = EELFLoggerDelegate
95         .getLogger(AsyncInstantiationBusinessLogicImpl.class);
96     private Map<String, JobStatus> msoStateToJobStatusMap = ImmutableMap.<String, JobStatus>builder()
97         .put("inprogress", JobStatus.IN_PROGRESS)
98         .put("failed", JobStatus.FAILED)
99         .put("pause", JobStatus.PAUSE)
100         .put("paused", JobStatus.PAUSE)
101         .put("complete", JobStatus.COMPLETED)
102         .put("pending", JobStatus.IN_PROGRESS)
103         .put("pendingmanualtask", JobStatus.PAUSE)
104         .put("unlocked", JobStatus.IN_PROGRESS)
105         .build();
106
107
108     @Autowired
109     public AsyncInstantiationBusinessLogicImpl(DataAccessService dataAccessService,
110         JobAdapter jobAdapter,
111         JobsBrokerService jobService,
112         SessionFactory sessionFactory,
113         AaiClientInterface aaiClient,
114         AaiOverTLSClientInterface aaiOverTLSClient) {
115         this.dataAccessService = dataAccessService;
116         this.jobAdapter = jobAdapter;
117         this.jobService = jobService;
118         this.sessionFactory = sessionFactory;
119         this.aaiClient = aaiClient;
120         this.aaiOverTLSClient = aaiOverTLSClient;
121     }
122
123     @Override
124     public List<ServiceInfo> getAllServicesInfo() {
125         return dataAccessService
126             .getList(ServiceInfo.class, filterByCreationDateAndNotDeleted(), orderByCreatedDateAndStatus(), null);
127     }
128
129     private String filterByCreationDateAndNotDeleted() {
130         LocalDateTime minus3Months = LocalDateTime.now().minusMonths(3);
131         Timestamp filterDate = Timestamp.valueOf(minus3Months);
132         return " where" +
133             "   hidden = false" +
134             "   and deleted_at is null" +  // don't fetch deleted
135             "   and created >= '" + filterDate + "' ";
136     }
137
138     private String orderByCreatedDateAndStatus() {
139         return " createdBulkDate DESC ,\n" +
140             "  (CASE jobStatus\n" +
141             "   WHEN 'COMPLETED' THEN 0\n" +
142             "   WHEN 'FAILED' THEN 0\n" +
143             "   WHEN 'IN_PROGRESS' THEN 1\n" +
144             "   WHEN 'PAUSE' THEN 2\n" +
145             "   WHEN 'PENDING' THEN 3\n" +
146             "   WHEN 'STOPPED' THEN 3 END),\n" +
147             "  statusModifiedDate ";
148     }
149
150     @Override
151     public List<UUID> pushBulkJob(ServiceInstantiation request, String userId) {
152         List<UUID> uuids = new ArrayList<>();
153         Date createdBulkDate = Calendar.getInstance().getTime();
154         int bulkSize = request.getBulkSize();
155         UUID templateId = UUID.randomUUID();
156         for (int i = 0; i < bulkSize; i++) {
157             Job job = jobAdapter.createJob(JobType.ServiceInstantiation, request, templateId, userId, i);
158             UUID jobId = jobService.add(job);
159             auditVidStatus(jobId, job.getStatus());
160             uuids.add(jobId);
161             dataAccessService.saveDomainObject(createServiceInfo(userId, request, jobId, templateId, createdBulkDate),
162                 DaoUtils.getPropsMap());
163         }
164         return uuids;
165     }
166
167     private ServiceInfo createServiceInfo(String userId, ServiceInstantiation serviceInstantiation, UUID jobId,
168         UUID templateId, Date createdBulkDate) {
169         return new ServiceInfo(
170             userId, Job.JobStatus.PENDING, serviceInstantiation.isPause(), jobId, templateId,
171             serviceInstantiation.getOwningEntityId(),
172             serviceInstantiation.getOwningEntityName(),
173             serviceInstantiation.getProjectName(),
174             serviceInstantiation.getAicZoneId(),
175             serviceInstantiation.getAicZoneName(),
176             serviceInstantiation.getTenantId(),
177             serviceInstantiation.getTenantName(),
178             serviceInstantiation.getLcpCloudRegionId(),
179             null,
180             serviceInstantiation.getSubscriptionServiceType(),
181             serviceInstantiation.getSubscriberName(),
182             null,
183             serviceInstantiation.getInstanceName(),
184             serviceInstantiation.getModelInfo().getModelInvariantId(),
185             serviceInstantiation.getModelInfo().getModelName(),
186             serviceInstantiation.getModelInfo().getModelVersion(),
187             createdBulkDate
188         );
189     }
190
191
192     @Override
193     public RequestDetailsWrapper<ServiceInstantiationRequestDetails> generateServiceInstantiationRequest(UUID jobId,
194         ServiceInstantiation payload, String userId) {
195
196         ServiceInstantiationRequestDetails.ServiceInstantiationOwningEntity owningEntity = new ServiceInstantiationRequestDetails.ServiceInstantiationOwningEntity(
197             payload.getOwningEntityId(), payload.getOwningEntityName());
198
199         SubscriberInfo subscriberInfo = new SubscriberInfo();
200         subscriberInfo.setGlobalSubscriberId(payload.getGlobalSubscriberId());
201
202         String serviceInstanceName = null;
203         if (payload.isUserProvidedNaming()) {
204             serviceInstanceName = getUniqueName(payload.getInstanceName(), ResourceType.SERVICE_INSTANCE);
205             String finalServiceInstanceName = serviceInstanceName;
206             updateServiceInfo(jobId, x -> x.setServiceInstanceName(finalServiceInstanceName));
207         }
208         ServiceInstantiationRequestDetails.RequestInfo requestInfo = new ServiceInstantiationRequestDetails.RequestInfo(
209             serviceInstanceName,
210             payload.getProductFamilyId(),
211             "VID",
212             payload.isRollbackOnFailure(),
213             userId);
214
215         List<ServiceInstantiationRequestDetails.ServiceInstantiationService> serviceInstantiationService = new LinkedList<>();
216         List<Map<String, String>> unFilteredInstanceParams =
217             payload.getInstanceParams() != null ? payload.getInstanceParams() : new LinkedList<>();
218         List<Map<String, String>> filteredInstanceParams = removeUnNeededParams(unFilteredInstanceParams);
219         ServiceInstantiationRequestDetails.ServiceInstantiationService serviceInstantiationService1 = new ServiceInstantiationRequestDetails.ServiceInstantiationService(
220             payload.getModelInfo(),
221             serviceInstanceName,
222             filteredInstanceParams,
223             createServiceInstantiationVnfList(payload)
224         );
225         serviceInstantiationService.add(serviceInstantiationService1);
226
227         ServiceInstantiationRequestDetails.RequestParameters requestParameters = new ServiceInstantiationRequestDetails.RequestParameters(
228             payload.getSubscriptionServiceType(), false, serviceInstantiationService);
229
230         ServiceInstantiationRequestDetails.Project project =
231             payload.getProjectName() != null ? new ServiceInstantiationRequestDetails.Project(payload.getProjectName())
232                 : null;
233
234         ServiceInstantiationRequestDetails requestDetails = new ServiceInstantiationRequestDetails(
235             payload.getModelInfo(), owningEntity, subscriberInfo,
236             project, requestInfo, requestParameters);
237
238         RequestDetailsWrapper<ServiceInstantiationRequestDetails> requestDetailsWrapper = new RequestDetailsWrapper(
239             requestDetails);
240         debugRequestDetails(requestDetailsWrapper, logger);
241         return requestDetailsWrapper;
242     }
243
244     private List<Map<String, String>> removeUnNeededParams(List<Map<String, String>> instanceParams) {
245         List<String> keysToRemove = new ArrayList<>();
246         if (instanceParams != null && !instanceParams.isEmpty()) {
247             for (String key : instanceParams.get(0).keySet()) {
248                 for (String paramToIgnore : PARAMS_TO_IGNORE) {
249                     if ((key.equalsIgnoreCase(paramToIgnore))) {
250                         keysToRemove.add(key);
251                     }
252                 }
253             }
254             for (String key : keysToRemove) {
255                 instanceParams.get(0).remove(key);
256             }
257             //TODO will be removed on once we stop using List<Map<String, String>>
258             if (instanceParams.get(0).isEmpty()) {
259                 return Collections.emptyList();
260             }
261         }
262         return instanceParams;
263     }
264
265     private ServiceInstantiationRequestDetails.ServiceInstantiationVnfList createServiceInstantiationVnfList(
266         ServiceInstantiation payload) {
267         CloudConfiguration cloudConfiguration = new CloudConfiguration();
268         cloudConfiguration.setTenantId(payload.getTenantId());
269         cloudConfiguration.setLcpCloudRegionId(payload.getLcpCloudRegionId());
270
271         Map<String, Vnf> vnfs = payload.getVnfs();
272         List<ServiceInstantiationRequestDetails.ServiceInstantiationVnf> vnfList = new ArrayList<>();
273         for (Vnf vnf : vnfs.values()) {
274             Map<String, Map<String, VfModule>> vfModules = vnf.getVfModules();
275             List<VfModule> convertedUnFilteredVfModules = convertVfModuleMapToList(vfModules);
276             List<VfModule> filteredVfModules = filterInstanceParamsFromVfModuleAndUniqueNames(
277                 convertedUnFilteredVfModules, vnf.isUserProvidedNaming());
278             ServiceInstantiationRequestDetails.ServiceInstantiationVnf serviceInstantiationVnf = new ServiceInstantiationRequestDetails.ServiceInstantiationVnf(
279                 vnf.getModelInfo(),
280                 cloudConfiguration,
281                 vnf.getPlatformName(),
282                 vnf.getLineOfBusiness(),
283                 payload.getProductFamilyId(),
284                 removeUnNeededParams(vnf.getInstanceParams()),
285                 filteredVfModules,
286                 vnf.isUserProvidedNaming() ? getUniqueName(vnf.getInstanceName(), ResourceType.GENERIC_VNF) : null
287             );
288             vnfList.add(serviceInstantiationVnf);
289         }
290
291         return new ServiceInstantiationRequestDetails.ServiceInstantiationVnfList(vnfList);
292     }
293
294     private List<VfModule> convertVfModuleMapToList(Map<String, Map<String, VfModule>> vfModules) {
295         return vfModules.values().stream().flatMap(vfModule -> vfModule.values().stream()).collect(Collectors.toList());
296     }
297
298     private List<VfModule> filterInstanceParamsFromVfModuleAndUniqueNames(List<VfModule> unFilteredVfModules,
299         boolean isUserProvidedNaming) {
300         return unFilteredVfModules.stream().map(vfModule ->
301             new VfModule(
302                 vfModule.getModelInfo(),
303                 getUniqueNameIfNeeded(isUserProvidedNaming, vfModule.getInstanceName(), ResourceType.VF_MODULE),
304                 getUniqueNameIfNeeded(isUserProvidedNaming, vfModule.getVolumeGroupInstanceName(),
305                     ResourceType.VOLUME_GROUP),
306                 removeUnNeededParams(vfModule.getInstanceParams())))
307             .collect(Collectors.toList());
308     }
309
310     private String getUniqueNameIfNeeded(boolean isUserProvidedNaming, String name, ResourceType resourceType) {
311         return isUserProvidedNaming && !StringUtils.isEmpty(name) ?
312             getUniqueName(name, resourceType) : null;
313     }
314
315     @Override
316     public String getServiceInstantiationPath(ServiceInstantiation serviceInstantiationRequest) {
317         //in case pause flag is true - use assign , else - use create.
318         return MsoBusinessLogicImpl.validateEndpointPath(
319             serviceInstantiationRequest.isPause() ?
320                 "mso.restapi.serviceInstanceAssign" : "mso.restapi.serviceInstanceCreate"
321         );
322     }
323
324     @Override
325     public String getOrchestrationRequestsPath() {
326         return MsoBusinessLogicImpl.validateEndpointPath(MsoProperties.MSO_REST_API_GET_ORC_REQ);
327     }
328
329     @Override
330     public ServiceInfo updateServiceInfo(UUID jobUUID, Consumer<ServiceInfo> serviceUpdater) {
331         ServiceInfo serviceInfo = getServiceInfoByJobId(jobUUID);
332         serviceUpdater.accept(serviceInfo);
333         dataAccessService.saveDomainObject(serviceInfo, DaoUtils.getPropsMap());
334         return serviceInfo;
335     }
336
337     @Override
338     public ServiceInfo updateServiceInfoAndAuditStatus(UUID jobUuid, JobStatus jobStatus) {
339         auditVidStatus(jobUuid, jobStatus);
340         return updateServiceInfo(jobUuid, x -> setServiceInfoStatus(x, jobStatus));
341     }
342
343     private void setServiceInfoStatus(ServiceInfo serviceInfo, JobStatus jobStatus) {
344         serviceInfo.setJobStatus(jobStatus);
345         serviceInfo.setStatusModifiedDate(new Date());
346     }
347
348     public ServiceInfo getServiceInfoByJobId(UUID jobUUID) {
349         List<ServiceInfo> serviceInfoList = dataAccessService
350             .getList(ServiceInfo.class, String.format(" where jobId = '%s' ", jobUUID), null, null);
351         if (serviceInfoList.size() != 1) {
352             throw new GenericUncheckedException(
353                 "Failed to retrieve job with uuid " + jobUUID + " from ServiceInfo table. Instances found: "
354                     + serviceInfoList.size());
355         }
356         return serviceInfoList.get(0);
357     }
358
359     public List<JobAuditStatus> getAuditStatuses(UUID jobUUID, JobAuditStatus.SourceStatus source) {
360         return dataAccessService.getList(
361             JobAuditStatus.class,
362             String.format(" where SOURCE = '%s' and JOB_ID = '%s'", source, jobUUID),
363             " CREATED_DATE ", null);
364     }
365
366     private JobAuditStatus getLatestAuditStatus(UUID jobUUID, JobAuditStatus.SourceStatus source) {
367         List<JobAuditStatus> list = getAuditStatuses(jobUUID, source);
368         return !list.isEmpty() ? list.get(list.size() - 1) : null;
369     }
370
371     @Override
372     public void auditVidStatus(UUID jobUUID, JobStatus jobStatus) {
373         JobAuditStatus vidStatus = new JobAuditStatus(jobUUID, jobStatus.toString(), JobAuditStatus.SourceStatus.VID);
374         auditStatus(vidStatus);
375     }
376
377     @Override
378     public void auditMsoStatus(UUID jobUUID, AsyncRequestStatus.Request msoRequestStatus) {
379         auditMsoStatus(jobUUID, msoRequestStatus.requestStatus.getRequestState(), msoRequestStatus.requestId,
380             msoRequestStatus.requestStatus.getStatusMessage());
381     }
382
383     @Override
384     public void auditMsoStatus(UUID jobUUID, String jobStatus, String requestId, String additionalInfo) {
385         JobAuditStatus msoStatus = new JobAuditStatus(jobUUID, jobStatus, JobAuditStatus.SourceStatus.MSO,
386             requestId != null ? UUID.fromString(requestId) : null,
387             additionalInfo);
388         auditStatus(msoStatus);
389     }
390
391     private void auditStatus(JobAuditStatus jobAuditStatus) {
392         JobAuditStatus latestStatus = getLatestAuditStatus(jobAuditStatus.getJobId(), jobAuditStatus.getSource());
393         if (latestStatus == null || !latestStatus.equals(jobAuditStatus)) {
394             dataAccessService.saveDomainObject(jobAuditStatus, DaoUtils.getPropsMap());
395         }
396
397     }
398
399     public Job.JobStatus calcStatus(AsyncRequestStatus asyncRequestStatus) {
400         String msoRequestState = asyncRequestStatus.request.requestStatus.getRequestState().toLowerCase()
401             .replaceAll("[^a-z]+", "");
402         JobStatus jobStatus = msoStateToJobStatusMap.get(msoRequestState);
403         return (jobStatus != null ? jobStatus : JobStatus.IN_PROGRESS);
404     }
405
406     @Override
407     public void handleFailedInstantiation(UUID jobUUID) {
408         ServiceInfo serviceInfo = updateServiceInfoAndAuditStatus(jobUUID, JobStatus.FAILED);
409         List<ServiceInfo> serviceInfoList = dataAccessService.getList(
410             ServiceInfo.class,
411             String.format(" where templateId = '%s' and jobStatus = '%s'",
412                 serviceInfo.getTemplateId(),
413                 JobStatus.PENDING),
414             null, null);
415         serviceInfoList.forEach(si -> updateServiceInfoAndAuditStatus(si.getJobId(), JobStatus.STOPPED));
416     }
417
418     @Override
419     public void deleteJob(UUID jobId) {
420         jobService.delete(jobId);
421         Date now = new Date();
422         updateServiceInfo(jobId, x -> x.setDeletedAt(now));
423     }
424
425     @Override
426     public void hideServiceInfo(UUID jobUUID) {
427         ServiceInfo serviceInfo = getServiceInfoByJobId(jobUUID);
428         if (!serviceInfo.getJobStatus().isFinal()) {
429             String message = String.format("jobId %s: Service status does not allow hide service, status = %s",
430                 serviceInfo.getJobId(),
431                 serviceInfo.getJobStatus());
432             logger.error(EELFLoggerDelegate.errorLogger, message);
433             throw new OperationNotAllowedException(message);
434         }
435         serviceInfo.setHidden(true);
436         dataAccessService.saveDomainObject(serviceInfo, DaoUtils.getPropsMap());
437     }
438
439     @Override
440     public int
441
442     getCounterForName(String name) {
443
444         String hqlSelectNC = "from NameCounter where name = :name";
445         String hqlUpdateCounter = "update NameCounter set counter = :newCounter " +
446             "where name= :name " +
447             "and counter= :prevCounter";
448
449         Integer counter = null;
450         GenericUncheckedException lastException = null;
451         for (int i = 0; i < MAX_RETRIES_GETTING_COUNTER && counter == null; i++) {
452             try {
453                 counter = calcCounter(name, hqlSelectNC, hqlUpdateCounter);
454             } catch (GenericUncheckedException exception) {
455                 lastException = exception; //do nothing, we will try again in the loop
456             }
457         }
458
459         if (counter != null) {
460             return counter;
461         }
462
463         throw lastException != null ? new DbFailureUncheckedException(lastException) :
464             new DbFailureUncheckedException("Failed to get counter for " + name + " due to unknown error");
465
466     }
467
468     private Integer calcCounter(String name, String hqlSelectNC, String hqlUpdateCounter) {
469         Integer counter;
470         counter = DaoUtils.tryWithSessionAndTransaction(sessionFactory, session -> {
471             NameCounter nameCounter = (NameCounter) session.createQuery(hqlSelectNC)
472                 .setText("name", name)
473                 .uniqueResult();
474             if (nameCounter != null) {
475                 int updatedRows = session.createQuery(hqlUpdateCounter)
476                     .setText("name", nameCounter.getName())
477                     .setInteger("prevCounter", nameCounter.getCounter())
478                     .setInteger("newCounter", nameCounter.getCounter() + 1)
479                     .executeUpdate();
480                 if (updatedRows == 1) {
481                     return nameCounter.getCounter() + 1;
482                 }
483             } else {
484                 Object nameAsId = session.save(new NameCounter(name));
485                 //if save success
486                 if (nameAsId != null) {
487                     return 1;
488                 }
489             }
490             //in case of failure return null, in order to continue the loop
491             return null;
492         });
493         return counter;
494     }
495
496     @Override
497     public int getMaxRetriesGettingFreeNameFromAai() {
498         return maxRetriesGettingFreeNameFromAai;
499     }
500
501     @Override
502     public void setMaxRetriesGettingFreeNameFromAai(int maxRetriesGettingFreeNameFromAai) {
503         this.maxRetriesGettingFreeNameFromAai = maxRetriesGettingFreeNameFromAai;
504     }
505
506     @Override
507     public String getUniqueName(String name, ResourceType resourceType) {
508         //check that name aai response well before increasing counter from DB
509         //Prevents unnecessary increasing of the counter while AAI doesn't response
510         isNameFreeInAai(NAME_FOR_CHECK_AAI_STATUS, resourceType);
511
512         for (int i = 0; i < getMaxRetriesGettingFreeNameFromAai(); i++) {
513             int counter = getCounterForName(name);
514             String newName = formatNameAndCounter(name, counter);
515             if (isNameFreeInAai(newName, resourceType)) {
516                 return newName;
517             }
518         }
519
520         throw new MaxRetriesException("find unused name for " + name, getMaxRetriesGettingFreeNameFromAai());
521     }
522
523     //the method is protected so we can call it in the UT
524     protected String formatNameAndCounter(String name, int counter) {
525         return name + "_" + String.format("%03d", counter);
526     }
527
528     private boolean isNameFreeInAai(String name, ResourceType resourceType) throws InvalidAAIResponseException {
529         HttpResponse<AaiNodeQueryResponse> aaiResponse = aaiOverTLSClient
530             .searchNodeTypeByName(name, resourceType);
531         if (aaiResponse.getStatus() > 399 || aaiResponse.getBody() == null) {
532             try {
533                 String message = IOUtils.toString(aaiResponse.getRawBody(), "UTF-8");
534                 throw new InvalidAAIResponseException(aaiResponse.getStatus(), message);
535             } catch (IOException e) {
536                 throw new InvalidAAIResponseException(aaiResponse.getStatus(), aaiResponse.getStatusText());
537             }
538         }
539         return CollectionUtils.isEmpty(aaiResponse.getBody().resultData);
540     }
541
542 }