Implement support for inner variables
[ccsdk/sli/adaptors.git] / aai-service / provider / src / main / java / org / onap / ccsdk / sli / adaptors / aai / AAIDeclarations.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T 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.onap.ccsdk.sli.adaptors.aai;
23
24 import java.io.IOException;
25 import java.io.UnsupportedEncodingException;
26 import java.lang.annotation.Annotation;
27 import java.lang.reflect.Field;
28 import java.lang.reflect.InvocationTargetException;
29 import java.lang.reflect.Method;
30 import java.net.MalformedURLException;
31 import java.net.URISyntaxException;
32 import java.net.URL;
33 import java.net.URLDecoder;
34 import java.net.URLEncoder;
35 import java.util.ArrayList;
36 import java.util.Arrays;
37 import java.util.HashMap;
38 import java.util.LinkedList;
39 import java.util.List;
40 import java.util.Map;
41 import java.util.Set;
42 import java.util.SortedSet;
43 import java.util.TreeSet;
44 import java.util.regex.Matcher;
45 import java.util.regex.Pattern;
46
47 import javax.xml.bind.annotation.XmlType;
48
49 import org.apache.commons.lang.StringUtils;
50 import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum;
51 import org.onap.ccsdk.sli.adaptors.aai.query.FormattedQueryResultList;
52 import org.onap.ccsdk.sli.adaptors.aai.query.InstanceFilter;
53 import org.onap.ccsdk.sli.adaptors.aai.query.InstanceFilters;
54 import org.onap.ccsdk.sli.adaptors.aai.query.NamedQuery;
55 import org.onap.ccsdk.sli.adaptors.aai.query.NamedQueryData;
56 import org.onap.ccsdk.sli.adaptors.aai.query.QueryParameters;
57 import org.onap.ccsdk.sli.adaptors.aai.query.Result;
58 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
59 import org.onap.ccsdk.sli.core.sli.SvcLogicException;
60 import org.onap.aai.inventory.v14.GenericVnf;
61 import org.onap.aai.inventory.v14.Image;
62 import org.onap.aai.inventory.v14.InventoryResponseItem;
63 import org.onap.aai.inventory.v14.InventoryResponseItems;
64 import org.onap.aai.inventory.v14.L3Network;
65 import org.onap.aai.inventory.v14.LogicalLink;
66 import org.onap.aai.inventory.v14.Metadata;
67 import org.onap.aai.inventory.v14.Metadatum;
68 import org.onap.aai.inventory.v14.Pnf;
69 import org.onap.aai.inventory.v14.RelatedToProperty;
70 import org.onap.aai.inventory.v14.Relationship;
71 import org.onap.aai.inventory.v14.RelationshipData;
72 import org.onap.aai.inventory.v14.RelationshipList;
73 import org.onap.aai.inventory.v14.ResultData;
74 import org.onap.aai.inventory.v14.SearchResults;
75 import org.onap.aai.inventory.v14.ServiceInstance;
76 import org.onap.aai.inventory.v14.Vlan;
77 import org.onap.aai.inventory.v14.Vlans;
78 import org.onap.aai.inventory.v14.Vserver;
79 import org.slf4j.Logger;
80 import org.slf4j.LoggerFactory;
81
82 import com.fasterxml.jackson.core.JsonParseException;
83 import com.fasterxml.jackson.databind.JsonMappingException;
84 import com.fasterxml.jackson.databind.ObjectMapper;
85
86
87 public abstract class AAIDeclarations implements AAIClient {
88
89     public static final String TRUSTSTORE_PATH    = "org.onap.ccsdk.sli.adaptors.aai.ssl.trust";
90     public static final String TRUSTSTORE_PSSWD   = "org.onap.ccsdk.sli.adaptors.aai.ssl.trust.psswd";
91     public static final String KEYSTORE_PATH      = "org.onap.ccsdk.sli.adaptors.aai.ssl.key";
92     public static final String KEYSTORE_PSSWD     = "org.onap.ccsdk.sli.adaptors.aai.ssl.key.psswd";
93
94     public static final String APPLICATION_ID     = "org.onap.ccsdk.sli.adaptors.aai.application";
95
96     public static final String CLIENT_NAME          = "org.onap.ccsdk.sli.adaptors.aai.client.name";
97     public static final String CLIENT_PWWD          = "org.onap.ccsdk.sli.adaptors.aai.client.psswd";
98
99
100     public static final String CONNECTION_TIMEOUT = "connection.timeout";
101     public static final String READ_TIMEOUT       = "read.timeout";
102
103     public static final String TARGET_URI         = "org.onap.ccsdk.sli.adaptors.aai.uri";
104
105     public static final String AAI_VERSION          = "org.onap.ccsdk.sli.adaptors.aai.version";
106
107     // Availability zones query
108     public static final String QUERY_PATH         = "org.onap.ccsdk.sli.adaptors.aai.path.query";
109
110     // Update
111     public static final String UPDATE_PATH          = "org.onap.ccsdk.sli.adaptors.aai.update";
112
113     // Service instance
114     public static final String SVC_INSTANCE_PATH  = "org.onap.ccsdk.sli.adaptors.aai.path.svcinst";
115     public static final String SVC_INST_QRY_PATH  = "org.onap.ccsdk.sli.adaptors.aai.path.svcinst.query";
116
117     // VServer
118     public static final String NETWORK_VSERVER_PATH  = "org.onap.ccsdk.sli.adaptors.aai.path.vserver";
119
120     public static final String VNF_IMAGE_QUERY_PATH      = "org.onap.ccsdk.sli.adaptors.aai.path.vnf.image.query";
121
122     public static final String PARAM_SERVICE_TYPE     = "org.onap.ccsdk.sli.adaptors.aai.param.service.type";
123     public static final String CERTIFICATE_HOST_ERROR = "org.onap.ccsdk.sli.adaptors.aai.host.certificate.ignore";
124
125     // UBB Notify
126     public static final String UBB_NOTIFY_PATH        = "org.onap.ccsdk.sli.adaptors.aai.path.notify";
127     public static final String SELFLINK_AVPN          = "org.onap.ccsdk.sli.adaptors.aai.notify.selflink.avpn";
128     public static final String SELFLINK_FQDN          = "org.onap.ccsdk.sli.adaptors.aai.notify.selflink.fqdn";
129
130     //Service
131     public static final String SERVICE_PATH              = "org.onap.ccsdk.sli.adaptors.aai.path.service";
132
133     // P-Interfaces
134     public static final String P_INTERFACE_PATH       = "org.onap.ccsdk.sli.adaptors.aai.path.pserver.pinterface";
135
136     // site-pair-sets
137     public static final String SITE_PAIR_SET_PATH     = "org.onap.ccsdk.sli.adaptors.aai.path.site.pair.set";
138
139     // node query (1602)
140     public static final String QUERY_NODES_PATH          = "org.onap.ccsdk.sli.adaptors.aai.query.nodes";
141
142     private static final String VERSION_PATTERN = "/v$/";
143
144
145     protected abstract Logger getLogger();
146     public abstract AAIExecutorInterface getExecutor();
147
148
149     @Override
150     public QueryStatus query(String resource, boolean localOnly, String select, String key, String prefix, String orderBy, SvcLogicContext ctx)
151         throws SvcLogicException {
152
153         getLogger().debug("AAIService.query \tresource = "+resource);
154
155         String vnfId;
156         String vnfName = null;
157         HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
158         getLogger().debug("key = "+ nameValues.toString());
159
160         if(!AAIServiceUtils.isValidFormat(resource, nameValues)) {
161             ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not supported. Key string contains invaid identifiers", resource));
162             return QueryStatus.FAILURE;
163         }
164
165         if(resource == null || resource.isEmpty() || AAIRequest.createRequest(resource, nameValues) == null) {
166             ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not supported", resource));
167             return QueryStatus.FAILURE;
168         }
169
170         // process data using new model
171         boolean useNewModelProcessing = true;
172         // process server query by name the old way
173         if("vserver".equals(resource) || "vserver2".equals(resource)){
174             if(nameValues.containsKey("vserver_name") || nameValues.containsKey("vserver-name") || nameValues.containsKey("vserver.vserver_name") || nameValues.containsKey("vserver.vserver-name"))
175                 useNewModelProcessing = false;
176         }
177         if("generic-vnf".equals(resource)){
178             if(nameValues.containsKey("vnf_name") || nameValues.containsKey("vnf-name") || nameValues.containsKey("generic_vnf.vnf_name") || nameValues.containsKey("generic-vnf.vnf-name"))
179                 useNewModelProcessing = false;
180         }
181
182         // process data using new model
183         if(useNewModelProcessing && AAIRequest.createRequest(resource, nameValues) != null) {
184
185             try {
186                 return newModelQuery(resource, localOnly, select, key, prefix, orderBy, ctx);
187             } catch (Exception exc) {
188                 getLogger().warn("Failed query - returning FAILURE", exc);
189                 return QueryStatus.FAILURE;
190             }
191         }
192
193         ObjectMapper mapper = AAIService.getObjectMapper();
194         Map<String,Object> attributes = new HashMap<>();
195
196         String modifier = null;
197
198         if(resource.contains(":")) {
199             String[] tokens = resource.split(":");
200             resource = tokens[0];
201             if(tokens.length > 1) {
202                 modifier = tokens[1];
203             }
204         }
205
206         resource = resource.toLowerCase().replace("-", "_");
207
208         try {
209
210             switch(resource) {
211                 case "generic_vnf":
212                     vnfId = nameValues.get("vnf_id");
213                     if(nameValues.containsKey("vnf_id"))
214                         vnfId = nameValues.get("vnf_id");
215                     else if(nameValues.containsKey("generic_vnf.vnf_name"))
216                         vnfId = nameValues.get("generic_vnf.vserver_name");
217
218                     if(nameValues.containsKey("vnf_name"))
219                         vnfName = nameValues.get("vnf_name");
220                     else if(nameValues.containsKey("generic_vnf.vnf_name"))
221                         vnfName = nameValues.get("generic_vnf.vnf_name");
222
223                     if(vnfId != null && !vnfId.isEmpty()) {
224                         // at this point of the project this part should not be executed
225                         vnfId = vnfId.trim().replace("'", "").replace("$", "").replace("'", "");
226                         GenericVnf vnf = this.requestGenericVnfData(vnfId);
227                         if(vnf == null) {
228                             return QueryStatus.NOT_FOUND;
229                         }
230
231                         attributes = mapper.convertValue(vnf, attributes.getClass());
232                     } else if(vnfName != null && !vnfName.isEmpty()) {
233                         try {
234                             vnfName = vnfName.trim().replace("'", "").replace("$", "").replace("'", "");
235                             GenericVnf vnf = this.requestGenericVnfeNodeQuery(vnfName);
236                             if(vnf == null) {
237                                 return QueryStatus.NOT_FOUND;
238                             }
239                             vnfId=vnf.getVnfId();
240                             nameValues.put("vnf_id", vnfId);
241                             attributes = mapper.convertValue(vnf, attributes.getClass());
242                         } catch (AAIServiceException exc) {
243                             int errorCode = exc.getReturnCode();
244                             switch(errorCode) {
245                             case 400:
246                             case 404:
247                             case 412:
248                                 break;
249                             default:
250                                 getLogger().warn("Caught exception trying to refresh generic VNF", exc);
251                             }
252                             ctx.setAttribute(prefix + ".error.message", exc.getMessage());
253                             if(errorCode >= 300) {
254                                 ctx.setAttribute(prefix + ".error.http.response-code",
255                                                  Integer.toString(exc.getReturnCode()));
256                             }
257                             return QueryStatus.FAILURE;
258                         }
259                     } else {
260                         getLogger().warn("No arguments are available to process generic VNF");
261                         return QueryStatus.FAILURE;
262                     }
263                     break;
264                 case "vserver":
265                 case "vserver2":
266                     String vserverName = null;
267                     if(nameValues.containsKey("vserver_name"))
268                         vserverName = nameValues.get("vserver_name");
269                     else if(nameValues.containsKey("vserver.vserver_name"))
270                         vserverName = nameValues.get("vserver.vserver_name");
271
272                     String vserverId = null;
273                     if(nameValues.containsKey("vserver_id"))
274                         vserverId = nameValues.get("vserver_id");
275                     if(nameValues.containsKey("vserver.vserver_id"))
276                         vserverId = nameValues.get("vserver.vserver_id");
277                     String tenantId = nameValues.get("teannt_id");
278
279                     if(vserverName != null) vserverName = vserverName.trim().replace("'", "").replace("$", "").replace("'", "");
280                     if(vserverId != null) vserverId = vserverId.trim().replace("'", "").replace("$", "").replace("'", "");
281                     if(tenantId != null) tenantId = tenantId.trim().replace("'", "").replace("$", "").replace("'", "");
282
283                 if (vserverName != null) {
284                     URL vserverUrl = null;
285                     try {
286                         vserverUrl = this.requestVserverURLNodeQuery(vserverName);
287                     } catch (AAIServiceException aaiexc) {
288                         ctx.setAttribute(prefix + ".error.message", aaiexc.getMessage());
289                         if (aaiexc.getReturnCode() >= 300) {
290                             ctx.setAttribute(prefix + ".error.http" + "" + ".response-code", Integer.toString(aaiexc.getReturnCode()));
291                         }
292
293                         if (aaiexc.getReturnCode() == 404)
294                             return QueryStatus.NOT_FOUND;
295                         else
296                             return QueryStatus.FAILURE;
297                     }
298                     if (vserverUrl == null) {
299                         return QueryStatus.NOT_FOUND;
300                     }
301
302                     tenantId = getTenantIdFromVserverUrl(vserverUrl);
303                             String cloudOwner = getCloudOwnerFromVserverUrl(vserverUrl);
304                             String cloudRegionId = getCloudRegionFromVserverUrl(vserverUrl);
305
306                     Vserver vserver = null;
307                     try {
308                         vserver = this.requestVServerDataByURL(vserverUrl);
309                     } catch (AAIServiceException aaiexc) {
310                         ctx.setAttribute(prefix + ".error.message", aaiexc.getMessage());
311                         if (aaiexc.getReturnCode() >= 300) {
312                             ctx.setAttribute(prefix + ".error.http" + ".response-code", Integer.toString(aaiexc.getReturnCode()));
313                         }
314
315                         if (aaiexc.getReturnCode() == 404)
316                             return QueryStatus.NOT_FOUND;
317                         else
318                             return QueryStatus.FAILURE;
319                     }
320                     if (vserver == null) {
321                         return QueryStatus.NOT_FOUND;
322                     }
323                     attributes = mapper.convertValue(vserver, attributes.getClass());
324                     if (!attributes.containsKey("tenant-id") && tenantId != null) {
325                         attributes.put("tenant-id", tenantId);
326                     }
327                     if (!attributes.containsKey("cloud-owner") && cloudOwner != null) {
328                         attributes.put("cloud-owner", cloudOwner);
329                     }
330                     if (!attributes.containsKey("cloud-region-id") && cloudRegionId != null) {
331                         attributes.put("cloud-region-id", cloudRegionId);
332                     }
333                 } else if (vserverId != null && tenantId != null) {
334                         Vserver vserver = this.requestVServerData(tenantId, vserverId, "att-aic", "AAIAIC25");
335                         if(vserver == null) {
336                             return QueryStatus.NOT_FOUND;
337                         }
338                         attributes = mapper.convertValue(vserver, attributes.getClass());
339                         if(!attributes.containsKey("tenant-id") && tenantId != null){
340                             attributes.put("tenant-id", tenantId);
341                         }
342                     } else {
343                         return QueryStatus.FAILURE;
344                     }
345                     break;
346
347                 default:
348                     return QueryStatus.FAILURE;
349             }
350
351             QueryStatus retval = QueryStatus.SUCCESS;
352
353             if (attributes == null || attributes.isEmpty()) {
354                 retval = QueryStatus.NOT_FOUND;
355                 getLogger().debug("No data found");
356             } else {
357                 if (ctx != null) {
358                     if (prefix != null) {
359                         ArrayList<String> keys = new ArrayList<>(attributes.keySet());
360
361                         int numCols = keys.size();
362
363                         for (int i = 0; i < numCols; i++) {
364                             String colValue;
365                             String colName = keys.get(i);
366                             Object object = attributes.get(colName);
367
368                             if(object != null && object instanceof String) {
369                                 colValue = (String)object;
370
371                                 if (prefix != null) {
372                                     getLogger().debug("Setting "+prefix    + "." + colName.replaceAll("_", "-")+" = "+ colValue);
373                                     ctx.setAttribute(prefix    + "." + colName.replaceAll("_", "-"), colValue);
374                                 } else {
375                                     getLogger().debug("Setting " + colValue.replaceAll("_", "-")+" = "+colValue);
376                                     ctx.setAttribute(colValue.replaceAll("_", "-"), colValue);
377                                 }
378                             } else if(object != null && object instanceof Map) {
379                                 if(colName.equals(modifier) || "relationship-list".equals(colName)){
380                                     String localNodifier = modifier;
381                                     if(localNodifier == null)
382                                         localNodifier = "relationship-list";
383                                     Map<String, Object> properties = (Map<String, Object>)object;
384                                     writeMap(properties, prefix+"."+localNodifier,  ctx);
385                                 }
386                             }
387                         }
388                     }
389                 }
390             }
391             getLogger().debug("Query - returning " + retval);
392             return retval;
393
394         } catch (Exception exc) {
395             getLogger().warn("Failed query - returning FAILURE", exc);
396             return QueryStatus.FAILURE;
397         }
398     }
399
400
401     public void writeMap(Map<String, Object> properties, String prefix, SvcLogicContext ctx) {
402         Set<String> mapKeys = properties.keySet();
403
404         for(String mapKey : mapKeys) {
405             Object entity = properties.get(mapKey);
406             if(entity instanceof ArrayList) {
407                 writeList((ArrayList<?>)entity, prefix + "." + mapKey, ctx);
408             } else
409             if(entity instanceof String ||  entity instanceof Long || entity instanceof Integer || entity instanceof Boolean) {
410                 ctx.setAttribute(prefix + "." + mapKey, entity.toString());
411                 getLogger().debug(prefix + "." + mapKey + " : " + entity.toString());
412             } else if(entity instanceof Map) {
413                 String localPrefix = prefix;
414                 if(mapKey != null) {
415                     localPrefix = String.format("%s.%s", prefix, mapKey);
416                 }
417                 writeMap( (Map<String, Object>)entity,  localPrefix,  ctx);
418             }
419         }
420     }
421
422     private void writeList(ArrayList<?> list, String prefix, SvcLogicContext ctx) {
423         for(int i = 0; i < list.size(); i++ ) {
424             Object entity = list.get(i);
425             if(entity instanceof Map) {
426                 writeMap( (Map<String, Object>)entity,  prefix + "[" + i + "]",  ctx);
427             } else
428                 if(entity instanceof String ||  entity instanceof Long || entity instanceof Integer || entity instanceof Boolean) {
429                 ctx.setAttribute(prefix, entity.toString());
430                 getLogger().debug(prefix  + " : " + entity.toString());
431             }
432         }
433
434         if(!list.isEmpty()) {
435             ctx.setAttribute(prefix + "_length", Integer.toString(list.size()));
436             getLogger().debug(prefix + "_length"  + " : " + Integer.toString(list.size()));
437         }
438     }
439
440     @Override
441     public QueryStatus save(String resource, boolean force, boolean localOnly, String key, Map<String, String> params, String prefix, SvcLogicContext ctx)
442             throws SvcLogicException {
443
444         getLogger().debug("AAIService.save\tresource="+resource);
445         HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
446
447         if(!AAIServiceUtils.isValidFormat(resource, nameValues)) {
448             ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not supported. Key string contains invaid identifiers", resource));
449             return QueryStatus.FAILURE;
450         }
451
452         if(resource == null || resource.isEmpty() || AAIRequest.createRequest(resource, nameValues) == null) {
453             getLogger().warn("AAIService.save has unspecified resource");
454             ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not supported", resource));
455             return QueryStatus.FAILURE;
456         }
457         // keys passed
458         getLogger().debug("key = "+ Arrays.toString(nameValues.entrySet().toArray()));
459
460         // process params
461         if(params.containsKey("prefix")) {
462             Map<String, String> tmpParams = ctxGetBeginsWith(ctx, params.get("prefix"));
463             if(!tmpParams.isEmpty()) {
464                 params.putAll(tmpParams);
465 //                params.remove("prefix");
466             }
467         }
468         // params passed
469         getLogger().debug("parms = "+ Arrays.toString(params.entrySet().toArray()));
470
471         boolean useNewModelProcessing = true;
472         // process server query by name the old way
473         if("vserver".equals(resource) || "vserver2".equals(resource)){
474             if(nameValues.containsKey("vserver-name")) {
475                 useNewModelProcessing = false;
476             }
477
478             if(!params.containsKey("vserver-selflink")) {
479
480                 AAIRequest request = AAIRequest.createRequest(resource, nameValues);
481                 URL path = null;
482                 try {
483                     request.processRequestPathValues(nameValues);
484                     path = request.getRequestUrl("GET", null);
485                     params.put("vserver-selflink", path.toString());
486                 } catch (UnsupportedEncodingException | MalformedURLException | URISyntaxException e) {
487                     params.put("vserver-selflink", "/vserver");
488                 }
489             }
490         }
491
492         // process data using new model
493         if(useNewModelProcessing && AAIRequest.createRequest(resource, nameValues) != null) {
494
495             try {
496                 if(!resource.contains(":")){
497                     return newModelSave(resource, force, key, params, prefix, ctx);
498                 } else {
499                     String[] tokens = resource.split(":");
500                     String localResource = tokens[0];
501                     String dependency = tokens[1];
502
503                     AAIDatum instance = newModelObjectRequest( localResource, nameValues, prefix, ctx);
504                     if(instance == null) {
505                         return QueryStatus.NOT_FOUND;
506                     }
507
508                     switch(dependency){
509                         case "relationship-list":
510                             newModelProcessRelationshipList(instance, params, prefix, ctx);
511                             break;
512                         case "metadata":
513                             newModelProcessMetadata(instance, params, prefix, ctx);
514                             break;
515                     }
516                     // create a method to update relationship-list
517                     AAIRequest request = AAIRequest.createRequest(localResource, nameValues);
518                     request.setRequestObject(instance);
519                     request.processRequestPathValues(nameValues);
520
521                     getExecutor().post(request);
522                     getLogger().debug("Save relationship list - returning SUCCESS");
523                     return QueryStatus.SUCCESS;
524                 }
525             } catch (Exception exc) {
526                 ctx.setAttribute(prefix + ".error.message", exc.getMessage());
527                 if(exc instanceof AAIServiceException) {
528                     AAIServiceException aaiexc = (AAIServiceException)exc;
529                     if(aaiexc.getReturnCode() >= 300) {
530                         ctx.setAttribute(prefix + ".error.http" + ".response-code", Integer.toString(aaiexc.getReturnCode()));
531                     }
532
533                     if(aaiexc.getReturnCode() == 404) {
534                         return QueryStatus.NOT_FOUND;
535                     }
536                 }
537                 getLogger().warn("Failed save() - returning FAILURE", exc);
538                 return QueryStatus.FAILURE;
539             }
540         } else {
541             getLogger().debug("Save() request for {} is not supported- returning FAILURE", resource);
542             return QueryStatus.FAILURE;
543         }
544     }
545
546     @Override
547     public QueryStatus update(String resource, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) throws SvcLogicException {
548
549         resource = resource.toLowerCase();
550         HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
551         getLogger().debug("key = "+ Arrays.toString(nameValues.entrySet().toArray()));
552         if(!AAIServiceUtils.isValidFormat(resource, nameValues)) {
553             ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not supported. Key string contains invaid identifiers", resource));
554             return QueryStatus.FAILURE;
555         }
556
557         if(resource == null || resource.isEmpty() || AAIRequest.createRequest(resource, nameValues) == null) {
558             ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not supported", resource));
559             return QueryStatus.FAILURE;
560         }
561
562         // check if request is for groups
563         if(!AAIServiceUtils.containsResource(resource, nameValues)) {
564             ctx.setAttribute(String.format("%s.error.message", prefix), String.format("Resource %s is not permitted in 'update' operation", resource));
565             return QueryStatus.FAILURE;
566         }
567
568         getLogger().debug("parms = "+ Arrays.toString(params.entrySet().toArray()));
569
570         AAIRequest request = AAIRequest.createRequest(resource, nameValues);
571         request = new UpdateRequest(request, params);
572
573         String[] arguments = request.getArgsList();
574         for(String name : arguments) {
575             String modifiedKey = name.replaceAll("-", "_");
576             if(nameValues.containsKey(modifiedKey)) {
577                 String argValue = nameValues.get(modifiedKey);
578                 if(argValue != null) argValue = argValue.trim().replace("'", "").replace("$", "").replace("'", "");
579                 request.addRequestProperty(name, argValue);
580             }
581         }
582
583         try {
584             QueryStatus retval = QueryStatus.SUCCESS;
585
586             retval = newModelQuery(resource, false, null, key, "tmpDelete", null,  ctx);
587
588             if(retval == null || retval != QueryStatus.SUCCESS) {
589                 return retval;
590             }
591
592             String resourceVersion = ctx.getAttribute("tmpDelete.resource-version");
593             if(resourceVersion == null) {
594                 return QueryStatus.NOT_FOUND;
595             }
596             params.put("resource-version", resourceVersion);
597
598             request.processRequestPathValues(nameValues);
599             getExecutor().patch(request, resourceVersion);
600         } catch(AAIServiceException aaiexc) {
601             if(aaiexc.getReturnCode() == 404)
602                 return QueryStatus.NOT_FOUND;
603             else
604                 return QueryStatus.FAILURE;
605         } catch (Exception exc) {
606             getLogger().warn("Failed update - returning FAILURE", exc);
607             return QueryStatus.FAILURE;
608         }
609
610         getLogger().debug("Update - returning SUCCESS");
611         return QueryStatus.SUCCESS;
612     }
613
614     @Override
615     public QueryStatus delete(String resource, String key, SvcLogicContext ctx) throws SvcLogicException {
616         getLogger().debug("AAIService.delete\tresource="+resource);
617         HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
618         getLogger().debug("key = "+ Arrays.toString(nameValues.entrySet().toArray()));
619
620         if(!AAIServiceUtils.isValidFormat(resource, nameValues)) {
621             ctx.setAttribute(String.format("%s.error.message", "aaiData"), String.format("Resource %s is not supported. Key string contains invaid identifiers", resource));
622             return QueryStatus.FAILURE;
623         }
624
625         if(resource == null || resource.isEmpty() || AAIRequest.createRequest(resource, nameValues) == null) {
626             ctx.setAttribute(String.format("%s.error.message", "tmpDelete"), String.format("Resource %s is not supported", resource));
627             return QueryStatus.FAILURE;
628         }
629
630         // check if request is for groups
631         if(!AAIServiceUtils.containsResource(resource, nameValues)) {
632             ctx.setAttribute(String.format("%s.error.message", "tmpDelete"), String.format("Resource %s is not permitted in 'delete' operation", resource));
633             return QueryStatus.FAILURE;
634         }
635
636         if(AAIRequest.createRequest(resource, nameValues) != null) {
637             if(resource.contains(":")) {
638                 switch (resource.split(":")[1]){
639                     case "relationship-list":
640                         return processDeleteRelationshipList(resource, key, ctx, nameValues);
641                     case "metadata":
642                         return processDeleteMetadata(resource, key, ctx, nameValues);
643                 }
644             }
645
646
647             try {
648                 QueryStatus retval = QueryStatus.SUCCESS;
649
650                 retval = newModelQuery(resource, false, null, key, "tmpDelete", null,  ctx);
651
652                 if(retval == null || retval != QueryStatus.SUCCESS) {
653                     return retval;
654                 }
655
656                 String resourceVersion = ctx.getAttribute("tmpDelete.resource-version");
657                 if(resourceVersion == null) {
658                     return QueryStatus.NOT_FOUND;
659                 }
660
661                 try {
662                     AAIRequest request = AAIRequest.createRequest(resource, nameValues);
663                     if(request == null) {
664                         return QueryStatus.FAILURE;
665                     }
666
667                     request.processRequestPathValues(nameValues);
668
669                     if(getExecutor().delete(request, resourceVersion)) {
670                         return QueryStatus.SUCCESS;
671                     }
672                 } catch(AAIServiceException aaiexc) {
673                     if(aaiexc.getReturnCode() == 404)
674                         return QueryStatus.NOT_FOUND;
675                     else
676                         return QueryStatus.FAILURE;
677
678                 } catch (Exception exc) {
679                     getLogger().warn("requestGenericVnfData", exc);
680                     return QueryStatus.FAILURE;
681                 }
682
683             } catch (Exception exc) {
684                 getLogger().warn("Failed delete - returning FAILURE", exc);
685                 return QueryStatus.FAILURE;
686             }
687         } else {
688             String resourceName = resource;
689             String identifier = null;
690
691             if(resourceName.contains(":")) {
692                 String[] tokens = resourceName.split(":");
693                 if(tokens != null && tokens.length > 0) {
694                     resourceName = tokens[0];
695                     identifier = tokens[1];
696                 }
697             }
698             if("relationship-list".equals(identifier) || "relationshipList".equals(identifier)) {
699 //                RelationshipRequest relationshipRequest = new RelationshipRequest();
700                 if("generic-vnf".equals(resourceName)){
701                     String vnfId = nameValues.get("vnf_id");
702                     String relatedTo  = nameValues.get("related_to");
703                     vnfId = vnfId.trim().replace("'", "").replace("$", "").replace("'", "");
704                     relatedTo = relatedTo.trim().replace("'", "").replace("$", "").replace("'", "");
705
706                     GenericVnf vnf;
707                     try {
708                         vnf = this.requestGenericVnfData(vnfId);
709                         if(vnf == null)
710                             return QueryStatus.NOT_FOUND;
711                     } catch (AAIServiceException exc) {
712                         getLogger().warn("Failed delete - returning NOT_FOUND", exc);
713                         return QueryStatus.NOT_FOUND;
714                     }
715                     boolean itemRemoved = false;
716                     RelationshipList relationshipList = vnf.getRelationshipList();
717                     List<Relationship> relationships = relationshipList.getRelationship();
718                     List<Relationship> iterableList = new LinkedList<>(relationships);
719                     for(Relationship relationship : iterableList) {
720                         if(relationship.getRelatedTo().equals(relatedTo)) {
721                             relationships.remove(relationship);
722                             itemRemoved = true;
723                         }
724                     }
725
726                     if(!itemRemoved)
727                         return QueryStatus.NOT_FOUND;
728                     try {
729                         this.postGenericVnfData(vnf.getVnfId(), vnf);
730                     } catch (AAIServiceException exc) {
731                         if(exc.getReturnCode() == 404){
732                             return QueryStatus.NOT_FOUND;
733                         } else {
734                             getLogger().warn("Failed delete - returning FAILURE", exc);
735                             return QueryStatus.FAILURE;
736                         }
737                     }
738                     return QueryStatus.SUCCESS;
739                 }
740             }
741         }
742         return QueryStatus.FAILURE;
743     }
744
745     @Override
746     public QueryStatus exists(String resource, String key, String prefix, SvcLogicContext ctx) throws SvcLogicException {
747         return query(resource, false, null, key, prefix, null, ctx);
748     }
749
750     @Override
751     public QueryStatus isAvailable(String arg0, String arg1, String arg2, SvcLogicContext arg3)
752             throws SvcLogicException {
753         throw new SvcLogicException("Method AAIService.isAvailable() has not been implemented yet");
754     }
755
756     @Override
757     public QueryStatus notify(String resource, String action, String key, SvcLogicContext ctx) throws SvcLogicException {
758         throw new SvcLogicException("Method AAIService.notify() has not been implemented yet");
759     }
760
761 //    @Override
762     public QueryStatus newModelQuery(String resource, boolean localOnly, String select, String key, String prefix, String orderBy, SvcLogicContext ctx) {
763
764         QueryStatus retval = QueryStatus.SUCCESS;
765         String modifier = null;
766
767         HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
768         if(resource.contains(":")) {
769             modifier = resource.split(":")[1];
770         }
771
772         try {
773             AAIRequest request = AAIRequest.createRequest(resource, nameValues);
774             if(request == null) {
775                 return QueryStatus.FAILURE;
776             }
777
778             Map<String, String> params = new HashMap<>();
779
780             request.processRequestPathValues(nameValues);
781             if(nameValues.containsKey("prefix")){
782                 Map<String, String> tmpParams = ctxGetBeginsWith(ctx, nameValues.get("prefix"));
783                 if(!tmpParams.isEmpty()) {
784                     params.putAll(tmpParams);
785                 }
786                 if("named-query".equals(resource))
787                     request.setRequestObject(extractNamedQueryDataFromQueryPrefix(nameValues, params));
788             }
789             String rv = getExecutor().get(request);
790
791             retval = processResponseData(rv, resource, request, prefix,  ctx, nameValues, modifier);
792
793         } catch(AAIServiceException aaiexc) {
794             int errorCode = aaiexc.getReturnCode();
795             ctx.setAttribute(prefix + ".error.message", aaiexc.getMessage());
796             if(errorCode >= 300) {
797                 ctx.setAttribute(prefix + ".error.http.response-code",
798                         Integer.toString(aaiexc.getReturnCode()));
799             }
800
801             if(aaiexc.getReturnCode() == 404)
802                 return QueryStatus.NOT_FOUND;
803
804             return QueryStatus.FAILURE;
805         } catch (Exception exc) {
806             getLogger().warn("requestGenericVnfData", exc);
807             ctx.setAttribute(prefix + ".error.message", exc.getMessage());
808             return QueryStatus.FAILURE;
809         }
810
811         return retval;
812     }
813
814     public QueryStatus processResponseData(String rv, String resource, AAIRequest request, String prefix,  SvcLogicContext ctx, Map<String, String> nameValues, String modifier) throws JsonParseException, JsonMappingException, IOException, AAIServiceException
815     {
816         Object response;
817
818             if(rv == null) {
819                 return QueryStatus.NOT_FOUND;
820             }
821
822             response = request.jsonStringToObject(rv);
823             if(response == null) {
824                 return QueryStatus.NOT_FOUND;
825             }
826
827             if("generic-query".equals(resource)) {
828                 SearchResults rd = SearchResults.class.cast(response);
829                 List<ResultData> rdList = rd.getResultData();
830                 if(rdList == null || rdList.isEmpty()) {
831                     return QueryStatus.NOT_FOUND;
832                 }
833                 ResultData rDatum = rdList.get(0);
834                 nameValues.put("selflink", rDatum.getResourceLink());
835                 AAIRequest req2 = AAIRequest.createRequest(rDatum.getResourceType(), nameValues);
836                 req2.processRequestPathValues(nameValues);
837                 rv = getExecutor().get(req2);
838                 if(rv == null) {
839                     return QueryStatus.NOT_FOUND;
840                 }
841
842                 response = req2.jsonStringToObject(rv);
843                 if(response == null) {
844                     return QueryStatus.NOT_FOUND;
845                 }
846             }
847
848             if("named-query".equals(resource)) {
849                 InventoryResponseItems rd = InventoryResponseItems.class.cast(response);
850                 List<InventoryResponseItem> iRIlist = rd.getInventoryResponseItem();
851                 if(iRIlist == null || iRIlist.isEmpty()) {
852                     return QueryStatus.NOT_FOUND;
853                 }
854             }
855
856             if("nodes-query".equals(resource)) {
857                 SearchResults rd = SearchResults.class.cast(response);
858                 List<ResultData> rdList = rd.getResultData();
859                 if(rdList == null || rdList.isEmpty()) {
860                     return QueryStatus.NOT_FOUND;
861                 }
862                 ResultData rDatum = rdList.get(0);
863                 response = rDatum;
864             }
865
866         if("formatted-query".equals(resource) || "custom-query".equals(resource)) {
867             FormattedQueryResultList rd = FormattedQueryResultList.class.cast(response);
868             List<Result> iRIlist = rd.getResults();
869             if(iRIlist == null || iRIlist.isEmpty()) {
870                 return QueryStatus.NOT_FOUND;
871             }
872         }
873
874         // process relationship list
875         // this is a temporary soluton to address the realationship handling changes added in Release 17.07
876         try {
877             Class<?> clazz = response.getClass();
878             Method getter = clazz.getMethod("getRelationshipList");
879             Object obj = getter.invoke(response);
880             if(obj != null && obj instanceof RelationshipList) {
881                 RelationshipList list = RelationshipList.class.cast(obj);
882                 AAIServiceUtils.populateRelationshipDataFromPath(list);
883             }
884         } catch(Exception exc) {
885             getLogger().debug("Retrofiting relationship data: " + exc.getMessage());
886         }
887
888             String preFix;
889             if(prefix == null || prefix.isEmpty()) {
890                 preFix = "";
891             } else {
892                 preFix = prefix + ".";
893             }
894
895             Map<String,Object> props = objectToProperties(response);
896             Set<String> keys = props.keySet();
897             for(String theKey: keys) {
898                 if(getLogger().isTraceEnabled())
899                     getLogger().trace(theKey);
900
901                 Object value = props.get(theKey);
902                 if(value == null)
903                     continue;
904                 Object type = value.getClass();
905                 if(value instanceof String) {
906                     ctx.setAttribute(preFix + theKey, value.toString());
907                     continue;
908                 }
909                 if(value instanceof Boolean) {
910                     ctx.setAttribute(preFix + theKey, value.toString());
911                     continue;
912                 }
913                 if(value instanceof Integer) {
914                     ctx.setAttribute(preFix + theKey, value.toString());
915                     continue;
916                 }
917                 if(value instanceof Long) {
918                     ctx.setAttribute(preFix + theKey, value.toString());
919                     continue;
920                 }
921
922                 if(value instanceof ArrayList) {
923                     ArrayList<?> array = ArrayList.class.cast(value);
924                     for(int i = 0; i < array.size(); i++) {
925                         writeList(array, String.format("%s.%s", prefix, theKey), ctx);
926                     }
927                     continue;
928                 }
929
930                 if("relationship-list".equals(theKey)){
931                     Map<String, Object> relationshipList = (Map<String, Object>)value;
932                     // we are interested in seeing just the selected relationship
933                     if(theKey.equals(modifier)) {
934                         List<?> relationships = (List<?>)relationshipList.get("relationship");
935                         if(relationships != null && !relationships.isEmpty()) {
936
937                             List newRelationships = new LinkedList();
938                             newRelationships.addAll(relationships);
939
940                             for(Object obj : newRelationships){
941                                 if(obj instanceof Map<?, ?>) {
942                                     Map<?, ?> relProperties = (Map<?, ?>)obj;
943                                     if(relProperties.containsKey("related-to")) {
944                                         Object relPropsRelatedTo = relProperties.get("related-to");
945
946                                         String relatedTo = nameValues.get("related_to");
947                                         if(relatedTo != null) {
948                                             relatedTo = relatedTo.trim().replace("'", "").replace("$", "").replace("'", "");
949                                             if(!relatedTo.equals(relPropsRelatedTo)) {
950                                                 relationships.remove(relProperties);
951                                             }
952                                             continue;
953                                         } else {
954                                             continue;
955                                         }
956                                     }
957                                 }
958                             }
959                         }
960                     }
961                     writeMap(relationshipList, String.format("%s.%s", prefix, theKey), ctx);
962                     continue;
963                 }
964
965                 if(value instanceof Map) {
966                     Map<String, Object> subnetsList = (Map<String, Object>)value;
967                     writeMap(subnetsList, String.format("%s.%s", prefix, theKey), ctx);
968                     continue;
969                 }
970
971             }
972         return QueryStatus.SUCCESS;
973     }
974
975
976     public QueryStatus newModelBackupRequest(String resource,  Map<String, String> params,  String prefix,  SvcLogicContext ctx) {
977
978         QueryStatus retval = QueryStatus.SUCCESS;
979         HashMap<String, String> nameValues = new HashMap<>();
980
981         try {
982             AAIRequest request = AAIRequest.createRequest(resource, nameValues);
983             if(request == null) {
984                 return QueryStatus.FAILURE;
985             }
986
987             boolean argsFound = false;
988             String[] arguments = request.getArgsList();
989             for(String name : arguments) {
990                 String tmpName = name.replaceAll("-", "_");
991                 String value = params.get(tmpName);
992                 if(value != null && !value.isEmpty()) {
993                     value = value.trim().replace("'", "").replace("$", "").replace("'", "");
994                     request.addRequestProperty(name, value);
995                     argsFound = true;
996                 }
997             }
998             if(!argsFound) {
999                 getLogger().warn("No arguments were found. Terminating backup request.");
1000                 return QueryStatus.FAILURE;
1001             }
1002
1003             String rv = getExecutor().get(request);
1004             ctx.setAttribute(prefix, rv);
1005         } catch(AAIServiceException aaiexc) {
1006             if(aaiexc.getReturnCode() == 404)
1007                 return QueryStatus.NOT_FOUND;
1008
1009             return QueryStatus.FAILURE;
1010         } catch (Exception exc) {
1011             getLogger().warn("newModelBackupRequest", exc);
1012             return QueryStatus.FAILURE;
1013         }
1014
1015         return retval;
1016     }
1017
1018     public AAIDatum newModelObjectRequest(String resource,  Map<String, String> params,  String prefix,  SvcLogicContext ctx)
1019             throws AAIServiceException {
1020
1021         AAIDatum response = null;
1022
1023         try {
1024             AAIRequest request = AAIRequest.createRequest(resource, params);
1025             if(request == null) {
1026                 return null;
1027             }
1028
1029             request.processRequestPathValues(params);
1030             String rv = getExecutor().get(request);
1031             response = request.jsonStringToObject(rv);
1032         } catch(AAIServiceException aaiexc) {
1033             throw aaiexc;
1034         } catch (Exception exc) {
1035             getLogger().warn("newModelBackupRequest", exc);
1036             throw new AAIServiceException(exc);
1037         }
1038
1039         return response;
1040     }
1041
1042
1043     @Override
1044     public QueryStatus release(String arg0, String arg1, SvcLogicContext arg2) throws SvcLogicException {
1045         throw new SvcLogicException("Method AAIService.release() has not been implemented yet");
1046     }
1047
1048     @Override
1049     public QueryStatus reserve(String arg0, String arg1, String arg2, String arg3, SvcLogicContext arg4)
1050             throws SvcLogicException {
1051         throw new SvcLogicException("Method AAIService.reserve() has not been implemented yet");
1052     }
1053
1054     private QueryStatus newModelSave(String resource, boolean force, String key, Map<String, String> params, String prefix, SvcLogicContext ctx) {
1055         getLogger().debug("Executing newModelSave for resource : " + resource);
1056         HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
1057
1058         try {
1059             ArrayList<String> subResources = new ArrayList<>();
1060             Set<String> set = params.keySet();
1061             Map<String, Method> setters = new HashMap<>();
1062             Map<String, Method> getters = new HashMap<>();
1063
1064             // 1. find class
1065             AAIRequest request = AAIRequest.createRequest(resource, nameValues);
1066             Class<? extends AAIDatum> resourceClass = request.getModelClass();
1067             getLogger().debug(resourceClass.getName());
1068             AAIDatum instance = resourceClass.newInstance();
1069
1070             {
1071                 Annotation[] annotations = resourceClass.getAnnotations();
1072                 for(Annotation annotation : annotations) {
1073                     Class<? extends Annotation> anotationType = annotation.annotationType();
1074                     String annotationName = anotationType.getName();
1075
1076                     // 2. find string property setters and getters for the lists
1077                     if("javax.xml.bind.annotation.XmlType".equals(annotationName)){
1078                         XmlType order = (XmlType)annotation;
1079                         String[]  values = order.propOrder();
1080                         for(String value : values) {
1081                             String id = AAIServiceUtils.camelCaseToDashedString(value);
1082                             Field field = resourceClass.getDeclaredField(value);
1083                             Class<?> type = field.getType();
1084                             Method setter = null;
1085                             try {
1086                                 setter = resourceClass.getMethod("set"+StringUtils.capitalize(value), type);
1087                                 if(type.getName().startsWith("java.lang") || "boolean".equals(type.getName()) || "long".equals(type.getName()) || "int".equals(type.getName())) {
1088                                     try {
1089                                         Object arglist[] = new Object[1];
1090                                         arglist[0] = params.get(id);
1091
1092                                         if(arglist[0] != null) {
1093                                             if(!type.getName().equals("java.lang.String")) {
1094 //                                            getLogger().debug(String.format("Processing %s with parameter %s", types[0].getName(), value));
1095                                                 if("java.lang.Long".equals(type.getName()) || "java.lang.Integer".equals(type.getName())) {
1096                                                     String fv = params.get(id);
1097                                                     if(fv == null || fv.isEmpty()) {
1098                                                         arglist[0] = null;
1099                                                     } else {
1100                                                         arglist[0] = valueOf(type, params.get(id));
1101                                                     }
1102                                                 } else if("boolean".equals(type.getName())) {
1103                                                     arglist[0] = valueOf(Boolean.class, params.get(id));
1104                                                 } else if("int".equals(type.getName())) {
1105                                                     arglist[0] = valueOf(Integer.class, params.get(id));
1106                                                 } else if("long".equals(type.getName())) {
1107                                                     String fv = params.get(id);
1108                                                     if(fv == null || fv.isEmpty()) {
1109                                                         arglist[0] = null;
1110                                                     } else {
1111                                                         arglist[0] = valueOf(Long.class, params.get(id));
1112                                                     }
1113                                                 } else {
1114                                                     arglist[0] = valueOf(type, params.get(id));
1115                                                 }
1116                                             }
1117                                             Object obj = setter.invoke(instance, arglist);
1118                                         }
1119                                         set.remove(id);
1120
1121                                     } catch (Exception x) {
1122                                         Throwable cause = x.getCause();
1123                                         getLogger().warn("Failed process for " + resourceClass.getName(), x);
1124                                     }
1125                                 } else if("java.util.List".equals(type.getName())) {
1126                                     List<String> newValues = new ArrayList<>();
1127                                     String length = id+"_length";
1128                                     if(!params.isEmpty() && params.containsKey(length)) {
1129                                         String tmp = params.get(length);
1130                                         int count = Integer.parseInt(tmp);
1131                                         for(int i=0; i<count; i++) {
1132                                             String tmpValue = params.get(String.format("%s[%d]", id, i));
1133                                             newValues.add(tmpValue);
1134                                         }
1135                                         if(!newValues.isEmpty()) {
1136                                             Object o = setter.invoke(instance, newValues);
1137                                         }
1138                                     }
1139                                     set.remove(id);
1140                                 } else {
1141                                     setters.put(id, setter);
1142                                 }
1143                             } catch(Exception exc) {
1144
1145                             }
1146
1147                             Method getter;
1148                             try {
1149                                 getter = resourceClass.getMethod("get"+StringUtils.capitalize(value));
1150                                 if(!type.getName().equals("java.lang.String")) {
1151                                     getters.put(id, getter);
1152                                 }
1153                             } catch(Exception exc) {
1154
1155                             }
1156
1157                         }
1158                         subResources.addAll(Arrays.asList(values));
1159                     }
1160                 }
1161             }
1162
1163             // remove getters that have matching setter
1164             for(String setKey : setters.keySet()) {
1165                 if(getters.containsKey(setKey)) {
1166                     getters.remove(setKey);
1167                 }
1168             }
1169
1170             Set<String> relationshipKeys = new TreeSet<>();
1171             Set<String> vlansKeys = new TreeSet<>();
1172             Set<String> metadataKeys = new TreeSet<>();
1173
1174             for(String attribute : set) {
1175                 String value = params.get(attribute);
1176                 if(attribute.startsWith("relationship-list")) {
1177                     relationshipKeys.add(attribute);
1178                 } else if(attribute.startsWith("vlans")) {
1179                     vlansKeys.add(attribute);
1180                 } else if(attribute.startsWith("metadata")) {
1181                     metadataKeys.add(attribute);
1182                 }
1183             }
1184             // 3. find list property getters
1185             for(String attribute : set) {
1186                 String value = params.get(attribute);
1187                 Method method = getters.get(attribute);
1188                 if(method != null) {
1189                     try {
1190                         Object arglist[] = new Object[0];
1191 //                        arglist[0] = value;
1192                         Class<?>[] types = method.getParameterTypes();
1193                         if(types.length == 0){
1194                             Object o = method.invoke(instance, arglist);
1195                             if(o instanceof ArrayList) {
1196                                 ArrayList<String> values = (ArrayList<String>)o;
1197 //                                getLogger().debug(String.format("Processing %s with parameter %s", types[0].getName(), value));
1198                                 value = value.replace("[", "").replace("]", "");
1199                                 List<String> items = Arrays.asList(value.split("\\s*,\\s*"));
1200                                 for(String s : items) {
1201                                     values.add(s.trim());
1202                                 }
1203                             }
1204                         }
1205                     } catch (Exception x) {
1206                         Throwable cause = x.getCause();
1207                         getLogger().warn("Failed process for " + resourceClass.getName(), x);
1208                     }
1209                 }
1210             }
1211             // 4. Process Relationships
1212             // add relationship list
1213             if( (subResources.contains("relationship-list") || subResources.contains("relationshipList")) &&  !relationshipKeys.isEmpty()) {
1214                 RelationshipList relationshipList = null;
1215                 Object obj = null;
1216                 Method getRelationshipListMethod = null;
1217                 try {
1218                      getRelationshipListMethod = resourceClass.getMethod("getRelationshipList");
1219                 } catch(Exception exc) {
1220                     getLogger().debug("Retrofiting relationship data: " + exc.getMessage());
1221                 }
1222
1223                 if(getRelationshipListMethod != null){
1224                     try {
1225                         obj = getRelationshipListMethod.invoke(instance);
1226                     } catch (InvocationTargetException x) {
1227                         Throwable cause = x.getCause();
1228                     }
1229                 }
1230                 if(obj != null && obj instanceof RelationshipList){
1231                     relationshipList = (RelationshipList)obj;
1232                 } else {
1233                     relationshipList = new RelationshipList();
1234                     Method setRelationshipListMethod = resourceClass.getMethod("setRelationshipList", RelationshipList.class);
1235                     if(setRelationshipListMethod != null){
1236                         try {
1237                             Object arglist[] = new Object[1];
1238                             arglist[0] = relationshipList;
1239
1240                             obj = setRelationshipListMethod.invoke(instance, arglist);
1241                         } catch (InvocationTargetException x) {
1242                             Throwable cause = x.getCause();
1243                         }
1244                     }
1245                 }
1246
1247                 List<Relationship> relationships = relationshipList.getRelationship();
1248
1249                 int i = 0;
1250                 while(true){
1251                     String searchKey = "relationship-list.relationship[" + i + "].related-to";
1252                     if(!params.containsKey(searchKey))
1253                         break;
1254                     int j = 0;
1255                     String relatedTo = params.get(searchKey);
1256                     String relatedLinkKey = "relationship-list.relationship[" + i + "].related-link";
1257                     String relatedLink = null;
1258                     if(params.containsKey(relatedLinkKey)) {
1259                         relatedLink = params.get(relatedLinkKey);
1260                     }
1261                     Relationship relationship = new Relationship();
1262                     relationships.add(relationship);
1263                     relationship.setRelatedTo(relatedTo);
1264                     String relationshipLabel = "relationship-list.relationship[" + i + "].relationship-label";
1265                     if(params.containsKey(searchKey)) {
1266                         relationship.setRelationshipLabel(params.get(relationshipLabel));
1267                     }
1268                     getLogger().debug("About to process related link of {}", relatedLink);
1269                     if(relatedLink != null) {
1270                         if(relatedLink.contains("v$"))
1271                             relatedLink = relatedLink.replace(VERSION_PATTERN, "/v14/");
1272                         relationship.setRelatedLink(relatedLink);
1273                     } else {
1274                         Map<String, String> relParams = new HashMap<>();
1275
1276                         while(true) {
1277                             String searchRelationshipKey = "relationship-list.relationship[" + i + "].relationship-data[" + j + "].relationship-key";
1278                             String searchRelationshipValue = "relationship-list.relationship[" + i + "].relationship-data[" + j + "].relationship-value";
1279                                 if(!params.containsKey(searchRelationshipKey))
1280                                 break;
1281
1282                                 relParams.put(params.get(searchRelationshipKey), params.get(searchRelationshipValue));
1283                             j++;
1284                         }
1285                         AAIRequest rlRequest = AAIRequest.createRequest(relatedTo, relParams);
1286                         for(Map.Entry<String,String> entry : relParams.entrySet()) {
1287                             rlRequest.addRequestProperty(entry.getKey(), entry.getValue());
1288                         }
1289                         String path = rlRequest.updatePathDataValues(null);
1290                         relationship.setRelatedLink(path);
1291                     }
1292                     {
1293                         int k = 0;
1294                         // process related to properties
1295                         Map<String, String> relParams = new HashMap<String, String>();
1296
1297                         while(true) {
1298                             String searchRelatedToKey = "relationship-list.relationship[" + i + "].related-to-property[" + k + "].property-key";
1299                             String searchRelatedToValue = "relationship-list.relationship[" + i + "].related-to-property[" + k + "].property-value";
1300                             if(!params.containsKey(searchRelatedToKey))
1301                                 break;
1302
1303                             RelatedToProperty relDatum = new RelatedToProperty();
1304                             relDatum.setPropertyKey(params.get(searchRelatedToKey));
1305                             relDatum.setPropertyValue(params.get(searchRelatedToValue));
1306                             relationship.getRelatedToProperty().add(relDatum);
1307
1308                             relParams.put(params.get(searchRelatedToKey), params.get(searchRelatedToValue));
1309                             k++;
1310                         }
1311                     }
1312                     i++;
1313                 }
1314             }
1315
1316             // 4. vlans
1317             if(subResources.contains("vlans") &&  !vlansKeys.isEmpty()) {
1318                 Object obj = null;
1319                 Vlans vlanList = null;
1320                 Method getVLansMethod = resourceClass.getMethod("getVlans");
1321                 if(getVLansMethod != null){
1322                     try {
1323                         obj = getVLansMethod.invoke(instance);
1324                     } catch (InvocationTargetException x) {
1325                         Throwable cause = x.getCause();
1326                     }
1327                 }
1328                 if(obj != null && obj instanceof Vlans){
1329                     vlanList = (Vlans)obj;
1330                 } else {
1331                     vlanList = new Vlans();
1332                     Method setVlansMethod = resourceClass.getMethod("setVlans", Vlans.class);
1333                     if(setVlansMethod != null){
1334                         try {
1335                             Object arglist[] = new Object[1];
1336                             arglist[0] = vlanList;
1337
1338                             obj = setVlansMethod.invoke(instance, arglist);
1339                         } catch (InvocationTargetException x) {
1340                             Throwable cause = x.getCause();
1341                         }
1342                     }
1343                 }
1344
1345                 int i = 0;
1346                 while(true){
1347                     String searchKey = "vlans.vlan[" + i + "].vlan-interface";
1348                     if(!params.containsKey(searchKey))
1349                         break;
1350
1351                     String vlanInterface = params.get("vlans.vlan[" + i + "].vlan-interface");
1352                     String vlanIdInner    = params.get("vlans.vlan[" + i + "].vlan-id-inner");
1353                     String vlanIdOute     = params.get("vlans.vlan[" + i + "].vlan-id-outer");
1354                     String speedValue     = params.get("vlans.vlan[" + i + "].speed-value");
1355                     String speedUnits     = params.get("vlans.vlan[" + i + "].speed-units");
1356
1357                     Vlan vlan = new Vlan();
1358                     vlan.setVlanInterface(vlanInterface);
1359
1360                     if(vlanIdInner != null) {
1361                     Long iVlanIdInner = Long.parseLong(vlanIdInner);
1362                     vlan.setVlanIdInner(iVlanIdInner);
1363                     }
1364
1365                     if(vlanIdOute != null) {
1366                         Long iVlanIdOuter = Long.parseLong(vlanIdOute);
1367                     vlan.setVlanIdOuter(iVlanIdOuter);
1368                     }
1369
1370                     if(speedValue != null) {
1371                     vlan.setSpeedValue(speedValue);
1372                     vlan.setSpeedUnits(speedUnits);
1373                     }
1374
1375                     vlanList.getVlan().add(vlan);
1376                     i++;
1377                 }
1378             }
1379
1380             // 5. metadata
1381             if(subResources.contains("metadata") &&  !metadataKeys.isEmpty()) {
1382                 Object obj = null;
1383                 Metadata metadataList = null;
1384                 Method getMetadataMethod = resourceClass.getMethod("getMetadata");
1385                 if(getMetadataMethod != null){
1386                     try {
1387                         obj = getMetadataMethod.invoke(instance);
1388                     } catch (InvocationTargetException x) {
1389                         Throwable cause = x.getCause();
1390                     }
1391                 }
1392                 if(obj != null && obj instanceof Metadata){
1393                     metadataList = (Metadata)obj;
1394                 } else {
1395                     metadataList = new Metadata();
1396                     Method setMetadataMethod = resourceClass.getMethod("setMetadata", Metadata.class);
1397                     if(setMetadataMethod != null){
1398                         try {
1399                             Object arglist[] = new Object[1];
1400                             arglist[0] = metadataList;
1401
1402                             obj = setMetadataMethod.invoke(instance, arglist);
1403                         } catch (InvocationTargetException x) {
1404                             Throwable cause = x.getCause();
1405                         }
1406                     }
1407                 }
1408
1409                 // process data
1410                 int i = 0;
1411                 while(true){
1412                     String metaKey = "metadata.metadatum[" + i + "].meta-key";
1413                     if(!params.containsKey(metaKey))
1414                         break;
1415
1416                     String metaValue = params.get("metadata.metadatum[" + i + "].meta-value");
1417
1418                     Metadatum vlan = new Metadatum();
1419                     vlan.setMetaname(metaKey);
1420                     vlan.setMetaval(metaValue);
1421
1422                     metadataList.getMetadatum().add(vlan);
1423                     i++;
1424                 }
1425
1426             }
1427
1428
1429             // 6. Prepare AAI request
1430             String[] args = request.getArgsList();
1431             for(String arg : args) {
1432                 String modifiedKey = arg.replaceAll("-", "_");
1433                 if(nameValues.containsKey(modifiedKey)) {
1434                     String argValue = nameValues.get(modifiedKey);
1435                     if(argValue != null) argValue = argValue.trim().replace("'", "").replace("$", "").replace("'", "");
1436                     request.addRequestProperty(arg, argValue);
1437                 }
1438             }
1439
1440             request.processRequestPathValues(nameValues);
1441             request.setRequestObject(instance);
1442                 Object response = getExecutor().post(request);
1443                 if(request.expectsDataFromPUTRequest()){
1444                     if(response != null && response instanceof String) {
1445                         String rv = response.toString();
1446                         QueryStatus retval = processResponseData(rv, resource, request, prefix,  ctx, nameValues, null);
1447                         getLogger().debug("newModelSave - returning " + retval.toString());
1448                         return retval;
1449                     }
1450                 }
1451
1452         } catch(AAIServiceException exc){
1453             ctx.setAttribute(prefix + ".error.message", exc.getMessage());
1454             int returnCode = exc.getReturnCode();
1455             if(returnCode >= 300) {
1456                 ctx.setAttribute(prefix + ".error.http.response-code",
1457                         Integer.toString(exc.getReturnCode()));
1458             }
1459
1460             if(returnCode == 400 || returnCode == 412)
1461                 return QueryStatus.FAILURE;
1462             else if(returnCode == 404)
1463                 return QueryStatus.NOT_FOUND;
1464             else {
1465                 getLogger().warn("Failed newModelSave - returning FAILURE", exc);
1466                 return QueryStatus.FAILURE;
1467             }
1468         } catch(Exception exc){
1469             getLogger().warn("Failed newModelSave - returning FAILURE", exc);
1470             ctx.setAttribute(prefix + ".error.message", exc.getMessage());
1471             return QueryStatus.FAILURE;
1472         }
1473
1474         getLogger().debug("newModelSave - returning SUCCESS");
1475         return QueryStatus.SUCCESS;
1476     }
1477
1478     private QueryStatus newModelProcessRelationshipList(Object instance, Map<String, String> params, String prefix, SvcLogicContext ctx) throws Exception {
1479
1480         Class resourceClass = instance.getClass();
1481
1482         Set<String> relationshipKeys = new TreeSet<>();
1483
1484         Set<String> set = params.keySet();
1485
1486         for(String attribute : set) {
1487             String value = params.get(attribute);
1488
1489             if(attribute.startsWith("relationship-list")) {
1490                 relationshipKeys.add(attribute);
1491             }
1492         }
1493
1494         // 3. Process Relationships
1495         // add relationship list
1496         if(!relationshipKeys.isEmpty()) {
1497             RelationshipList relationshipList;
1498             Object obj = null;
1499             Method getRelationshipListMethod = null;
1500             try {
1501                  getRelationshipListMethod = resourceClass.getMethod("getRelationshipList");
1502             } catch(Exception exc) {
1503                 getLogger().debug("Retrofiting relationship data: " + exc.getMessage());
1504             }
1505             if(getRelationshipListMethod != null){
1506                 try {
1507                     obj = getRelationshipListMethod.invoke(instance);
1508                 } catch (InvocationTargetException x) {
1509                     Throwable cause = x.getCause();
1510                 }
1511             }
1512             if(obj != null && obj instanceof RelationshipList){
1513                 relationshipList = (RelationshipList)obj;
1514             } else {
1515                 relationshipList = new RelationshipList();
1516                 Method setRelationshipListMethod = resourceClass.getMethod("setRelationshipList", RelationshipList.class);
1517                 if(setRelationshipListMethod != null){
1518                     try {
1519                         Object arglist[] = new Object[1];
1520                         arglist[0] = relationshipList;
1521
1522                         obj = setRelationshipListMethod.invoke(instance, arglist);
1523                     } catch (InvocationTargetException x) {
1524                         Throwable cause = x.getCause();
1525                     }
1526                 }
1527             }
1528
1529             boolean createdNewRelationships = false;
1530             List<Relationship> relationships = relationshipList.getRelationship();
1531             if(relationships == null) {
1532                 relationships = new ArrayList<>();
1533                 createdNewRelationships = true;
1534             }
1535
1536             int i = 0;
1537             while(true){
1538                 String searchKey = "relationship-list.relationship[" + i + "].related-to";
1539                 if(!params.containsKey(searchKey))
1540                     break;
1541
1542                 String relatedTo = params.get(searchKey);
1543                 String relatedLinkKey = "relationship-list.relationship[" + i + "].related-link";
1544                 String relatedLink = null;
1545                 if(params.containsKey(relatedLinkKey)) {
1546                     relatedLink = params.get(relatedLinkKey);
1547                 }
1548
1549                 Relationship relationship = new Relationship();
1550                 relationships.add(relationship);
1551                 relationship.setRelatedTo(relatedTo);
1552
1553                 String relationshipLabel = "relationship-list.relationship[" + i + "].relationship-label";
1554                 if(params.containsKey(searchKey)) {
1555                     relationship.setRelationshipLabel(params.get(relationshipLabel));
1556                 }
1557
1558                 if (relatedLink != null) {
1559                     if(relatedLink.contains("v$"))
1560                         relatedLink = relatedLink.replace(VERSION_PATTERN,  AAIRequest.getSupportedAAIVersion());
1561                     relationship.setRelatedLink(relatedLink);
1562                 } else {
1563                     Map<String, String> relParams = new HashMap<>();
1564                     int j = 0;
1565
1566                     while (true) {
1567                         String searchRelationshipKey = "relationship-list.relationship[" + i + "].relationship-data["
1568                                 + j + "].relationship-key";
1569                         String searchRelationshipValue = "relationship-list.relationship[" + i + "].relationship-data["
1570                                 + j + "].relationship-value";
1571                         if (!params.containsKey(searchRelationshipKey))
1572                             break;
1573
1574                         RelationshipData relDatum = new RelationshipData();
1575                         relDatum.setRelationshipKey(params.get(searchRelationshipKey));
1576                         relDatum.setRelationshipValue(params.get(searchRelationshipValue));
1577                         relationship.getRelationshipData().add(relDatum);
1578
1579                         relParams.put(params.get(searchRelationshipKey), params.get(searchRelationshipValue));
1580                         j++;
1581                     }
1582                     AAIRequest rlRequest = AAIRequest.createRequest(relatedTo, relParams);
1583                     for (Map.Entry<String, String> entry : relParams.entrySet()) {
1584                         rlRequest.addRequestProperty(entry.getKey(), entry.getValue());
1585                     }
1586                     String path = rlRequest.updatePathDataValues(null);
1587                     relationship.setRelatedLink(path);
1588                 }
1589                 {
1590                     int k = 0;
1591                     // process related to properties
1592                     Map<String, String> relParams = new HashMap<String, String>();
1593
1594                     while(true) {
1595                         String searchRelatedToKey = "relationship-list.relationship[" + i + "].related-to-property[" + k + "].property-key";
1596                         String searchRelatedToValue = "relationship-list.relationship[" + i + "].related-to-property[" + k + "].property-value";
1597                         if(!params.containsKey(searchRelatedToKey))
1598                             break;
1599
1600                         RelatedToProperty relDatum = new RelatedToProperty();
1601                         relDatum.setPropertyKey(params.get(searchRelatedToKey));
1602                         relDatum.setPropertyValue(params.get(searchRelatedToValue));
1603                         relationship.getRelatedToProperty().add(relDatum);
1604
1605                         relParams.put(params.get(searchRelatedToKey), params.get(searchRelatedToValue));
1606                         k++;
1607                     }
1608                 }
1609
1610                 i++;
1611             }
1612         }
1613
1614         return QueryStatus.SUCCESS;
1615     }
1616
1617     private QueryStatus newModelProcessMetadata(Object instance, Map<String, String> params, String prefix, SvcLogicContext ctx) throws Exception {
1618
1619         if (!(instance instanceof ServiceInstance) && !(instance instanceof Image)) {
1620             throw new IllegalArgumentException("request is not applicable for selected request");
1621         }
1622
1623         Class resourceClass = instance.getClass();
1624         Set<String> metadataKeys = new TreeSet<String>();
1625         Set<String> set = params.keySet();
1626         for(String attribute : set) {
1627             if(attribute.startsWith("metadata")) {
1628                 metadataKeys.add(attribute);
1629             }
1630         }
1631
1632         // 3. Process Metadata
1633         // add metadata
1634         if(!metadataKeys.isEmpty()) {
1635             Metadata metadata = null;
1636             Object obj = null;
1637             Method getMetadataMethod = resourceClass.getMethod("getMetadata");
1638             if(getMetadataMethod != null){
1639                 try {
1640                     obj = getMetadataMethod.invoke(instance);
1641                 } catch (InvocationTargetException x) {
1642                     Throwable cause = x.getCause();
1643                 }
1644             }
1645             if(obj != null && obj instanceof Metadata){
1646                 metadata = (Metadata)obj;
1647             } else {
1648                 metadata = new Metadata();
1649                 Method setMetadataMethod = resourceClass.getMethod("setMetadata", Metadata.class);
1650                 if(setMetadataMethod != null){
1651                     try {
1652                         setMetadataMethod.invoke(instance, metadata);
1653                     } catch (InvocationTargetException x) {
1654                     }
1655                 }
1656             }
1657
1658             List<Metadatum> metadatumList = metadata.getMetadatum();
1659             int i = 0;
1660             while(true){
1661                 String metaNameKey = "metadata.metadatum[" + i + "].metaname";
1662                 String metaValueKey = "metadata.metadatum[" + i + "].metaval";
1663                 if(!params.containsKey(metaNameKey) || !params.containsKey(metaValueKey))
1664                     break;
1665
1666                 Metadatum metadatum = new Metadatum();
1667                 metadatum.setMetaname(params.get(metaNameKey));
1668                 metadatum.setMetaval(params.get(metaValueKey));
1669                 metadatumList.add(metadatum);
1670
1671                 i++;
1672             }
1673         }
1674
1675         return QueryStatus.SUCCESS;
1676     }
1677
1678     private Relationship findRelationship(List<Relationship> relationships, String relatedTo) {
1679         if(relatedTo == null)
1680             return null;
1681
1682         for(Relationship relationship : relationships) {
1683             if(relationship.getRelatedTo().equals(relatedTo)){
1684                 return relationship;
1685             }
1686         }
1687         return null;
1688     }
1689
1690
1691     public QueryStatus backup(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
1692         String resource = params.get("resource").toLowerCase();
1693         String prefix = params.get("data-key");
1694
1695         HashMap<String, String> nameValues = new HashMap<>();
1696         if(AAIRequest.createRequest(resource, nameValues) != null) {
1697
1698             try {
1699                 return newModelBackupRequest(resource, params, prefix, ctx);
1700             } catch (Exception exc) {
1701                 getLogger().warn("Failed backup - returning FAILURE", exc);
1702                 return QueryStatus.FAILURE;
1703             }
1704         }
1705
1706         return QueryStatus.NOT_FOUND;
1707     }
1708
1709     @Override
1710     public QueryStatus restore(Map<String, String> params, SvcLogicContext ctx) throws SvcLogicException {
1711
1712         QueryStatus retval = QueryStatus.SUCCESS;
1713         String resource = params.get("resource").toLowerCase();
1714         String prefix = params.get("data-key");
1715
1716         HashMap<String, String> nameValues = new HashMap<>();
1717         if(AAIRequest.createRequest(resource, nameValues) != null) {
1718
1719             try {
1720                 retval = newModelBackupRequest(resource, params, "tmpRestore", ctx);
1721                 if(retval == QueryStatus.SUCCESS) {
1722                     ctx.setAttribute("tmpRestore", null);
1723                 }
1724             } catch (Exception exc) {
1725                 getLogger().warn("Failed restore - returning FAILURE", exc);
1726                 return QueryStatus.FAILURE;
1727             }
1728         }
1729
1730         return QueryStatus.NOT_FOUND;
1731     }
1732
1733     protected Map<String, Object> objectToProperties(Object object) {
1734         ObjectMapper mapper = AAIService.getObjectMapper();
1735         return mapper.convertValue(object, Map.class);
1736     }
1737
1738     static <T> T valueOf(Class<T> klazz, String arg) {
1739         Exception cause = null;
1740         T ret = null;
1741         try {
1742             ret = klazz.cast(klazz.getDeclaredMethod("valueOf", String.class).invoke(null, arg));
1743         } catch (NoSuchMethodException exc) {
1744             LoggerFactory.getLogger(AAIService.class).warn("Wrong data type", exc);
1745             ret = klazz.cast(arg);
1746         } catch (IllegalAccessException e) {
1747             cause = e;
1748         } catch (InvocationTargetException e) {
1749             cause = e;
1750         }
1751         if (cause == null) {
1752             return ret;
1753         } else {
1754             throw new IllegalArgumentException(cause);
1755         }
1756     }
1757
1758     private QueryStatus processDeleteRelationshipList(String resource, String key, SvcLogicContext ctx, HashMap<String, String> nameValues) {
1759         try {
1760             AAIRequest request = AAIRequest.createRequest(resource.split(":")[0], nameValues);
1761             if(request == null) {
1762                 return QueryStatus.FAILURE;
1763             }
1764
1765             request.processRequestPathValues(nameValues);
1766             URL url = request.getRequestUrl("GET", null);
1767
1768             Class resourceClass = request.getModelClass();
1769             Object instance = getResource(url.toString(), resourceClass);
1770             if(instance == null)
1771                 return QueryStatus.NOT_FOUND;
1772
1773             // get resource version
1774             String resourceVersion = null;
1775             Method getResourceVersionMethod = resourceClass.getMethod("getResourceVersion");
1776             if(getResourceVersionMethod != null){
1777                 try {
1778                     Object object = getResourceVersionMethod.invoke(instance);
1779                     if(object != null)
1780                         resourceVersion = object.toString();
1781                 } catch (InvocationTargetException exc) {
1782                     getLogger().warn("Retrieving resource version", exc);
1783                 }
1784             }
1785
1786             RelationshipList relationshipList = null;
1787             Object obj = null;
1788             Method getRelationshipListMethod = null;
1789             try {
1790                  getRelationshipListMethod = resourceClass.getMethod("getRelationshipList");
1791             } catch(Exception exc) {
1792                 getLogger().debug("Retrofiting relationship data: " + exc.getMessage());
1793             }
1794             if(getRelationshipListMethod != null){
1795                 try {
1796                     obj = getRelationshipListMethod.invoke(instance);
1797                 } catch (InvocationTargetException x) {
1798                     Throwable cause = x.getCause();
1799                 }
1800             }
1801             if(obj != null && obj instanceof RelationshipList){
1802                 relationshipList = (RelationshipList)obj;
1803             } else {
1804                 getLogger().debug("No relationships found to process.");
1805                 return QueryStatus.NOT_FOUND;
1806             }
1807
1808             if(relationshipList.getRelationship() == null || relationshipList.getRelationship().isEmpty()) {
1809                 return QueryStatus.NOT_FOUND;
1810             }
1811             String relatedTo = nameValues.get("related_to");
1812             if(relatedTo == null) {
1813                 return QueryStatus.FAILURE;
1814             }
1815
1816             relatedTo = relatedTo.replaceAll("_", "-");
1817
1818             String relatedLink = nameValues.get("relationship.related_link");
1819             if(relatedLink != null) {
1820                 relatedLink = URLDecoder.decode(relatedLink, "UTF-8");
1821             }
1822
1823             List<Relationship> relationships = relationshipList.getRelationship();
1824             List<Relationship> relationshipsToDelete = new LinkedList<>();
1825
1826             for(Relationship relationship : relationships) {
1827                 if(relatedTo.equals(relationship.getRelatedTo())) {
1828                     if(relatedLink != null) {
1829                         if(relationship.getRelatedLink() != null ) {
1830                             String localRelatedLink = relationship.getRelatedLink();
1831                             localRelatedLink = URLDecoder.decode(localRelatedLink, "UTF-8");
1832                             if(localRelatedLink.endsWith(relatedLink)) {
1833                                 getLogger().debug(String.format("Found relationship of '%s' to keyword '%s'", relationship.getRelatedTo(),  relatedTo));
1834                                 relationshipsToDelete.add(relationship);
1835                         }
1836                     }
1837                     } else {
1838                     getLogger().debug(String.format("Found relationship of '%s' to keyword '%s'", relationship.getRelatedTo(),  relatedTo));
1839                     relationshipsToDelete.add(relationship);
1840                 }
1841             }
1842             }
1843             if(relationshipsToDelete == null || relationshipsToDelete.isEmpty()) {
1844                 getLogger().info(String.format("Relationship has not been found for %s", key));
1845                 return QueryStatus.NOT_FOUND;
1846             }
1847
1848             String path = url.toString();
1849             path = path + "/relationship-list/relationship";
1850             URL deleteUrl = new URL(path);
1851
1852             ObjectMapper mapper = AAIService.getObjectMapper();
1853
1854             boolean cumulativeResponse = true;
1855
1856             for(Relationship targetRelationship : relationshipsToDelete) {
1857                 String json_text = mapper.writeValueAsString(targetRelationship);
1858                 boolean response = deleteList(deleteUrl, json_text);
1859                 if(!response)
1860                     cumulativeResponse = response;
1861
1862             }
1863
1864             if(!cumulativeResponse)
1865                 return QueryStatus.FAILURE;
1866
1867             return QueryStatus.SUCCESS;
1868
1869         } catch(Exception exc) {
1870             getLogger().warn("processDelete", exc);
1871             return QueryStatus.FAILURE;
1872         }
1873     }
1874
1875     private QueryStatus processDeleteMetadata(String resource, String key, SvcLogicContext ctx, HashMap<String, String> nameValues) {
1876         try {
1877             AAIRequest request = AAIRequest.createRequest(resource, nameValues);
1878             if(request == null) {
1879                 return QueryStatus.FAILURE;
1880             }
1881
1882             request.processRequestPathValues(nameValues);
1883             URL url = request.getRequestUrl("GET", null);
1884
1885             Class<?> resourceClass = request.getModelClass();
1886             Object instance = getResource(url.toString(), resourceClass);
1887
1888             // get resource version
1889             String resourceVersion = null;
1890             Method getResourceVersionMethod = resourceClass.getMethod("getResourceVersion");
1891             if(getResourceVersionMethod != null){
1892                 try {
1893                     resourceVersion = (String) getResourceVersionMethod.invoke(instance);
1894                 } catch (InvocationTargetException x) {
1895                 }
1896             }
1897
1898             Metadata metadata = null;
1899             Object obj = null;
1900             Method getMetadataMethod = resourceClass.getMethod("getMetadata");
1901             if(getMetadataMethod != null){
1902                 try {
1903                     obj = getMetadataMethod.invoke(instance);
1904                 } catch (InvocationTargetException x) {
1905                     Throwable cause = x.getCause();
1906                 }
1907             }
1908             if(obj != null && obj instanceof Metadata){
1909                 metadata = (Metadata)obj;
1910             } else {
1911                 getLogger().debug("No metadata found to process.");
1912                 return QueryStatus.NOT_FOUND;
1913             }
1914
1915             if(metadata.getMetadatum() == null || metadata.getMetadatum().isEmpty()) {
1916                 return QueryStatus.NOT_FOUND;
1917             }
1918
1919             List<Metadatum> metadatumList = metadata.getMetadatum();
1920             Metadatum metadatumToDelete = null;
1921
1922             final String metaname = nameValues.get("metaname");
1923
1924             for(Metadatum metadatum : metadatumList) {
1925                 getLogger().debug(String.format("Comparing existing metadatum of '%s' to keyword '%s'", metadatum.getMetaname(),  metaname));
1926                 if(metaname.equals(metadatum.getMetaname())) {
1927                     metadatumToDelete = metadatum;
1928                     break;
1929                 }
1930             }
1931             if(metadatumToDelete == null) {
1932                 getLogger().info(String.format("Metadatum has not been found for %s", key));
1933                 return QueryStatus.NOT_FOUND;
1934             }
1935
1936             String path = url.toString();
1937             path = path + "/metadata/metadatum/" + encodeQuery( metadatumToDelete.getMetaname() ) +
1938                     "?resource-version=" + metadatumToDelete.getResourceVersion();
1939             URL deleteUrl = new URL(path);
1940             boolean response = deleteList(deleteUrl, null);
1941
1942             if(!response)
1943                 return QueryStatus.FAILURE;
1944
1945             return QueryStatus.SUCCESS;
1946
1947         } catch(Exception exc) {
1948             getLogger().warn("processDelete", exc);
1949             return QueryStatus.FAILURE;
1950         }
1951     }
1952
1953     protected String encodeQuery(String param) throws UnsupportedEncodingException {
1954         return URLEncoder.encode(param, "UTF-8").replace("+", "%20");
1955     }
1956
1957     static final Map<String, String> ctxGetBeginsWith( SvcLogicContext ctx, String prefix ) {
1958         Map<String, String> tmpPrefixMap = new HashMap<>();
1959
1960         if(prefix == null || prefix.isEmpty()){
1961             return tmpPrefixMap;
1962         }
1963
1964         for( String key : ctx.getAttributeKeySet() ) {
1965             if( key.startsWith(prefix) ) {
1966                 String tmpKey = key.substring(prefix.length() + 1);
1967                 tmpPrefixMap.put( tmpKey, ctx.getAttribute(key));
1968             }
1969         }
1970
1971         Map<String, String> prefixMap = new HashMap<>();
1972         Pattern p = Pattern.compile(".*\\[\\d\\]");
1973
1974         SortedSet<String> keys = new TreeSet<String>(tmpPrefixMap.keySet () );
1975         for(String key : keys) {
1976             Matcher m = p.matcher(key);
1977             if(m.matches()) {
1978                 continue;
1979             } else if(key.endsWith("_length")) {
1980                 String listKey = key.substring(0, key.indexOf("_length"));
1981                 int max = Integer.parseInt(tmpPrefixMap.get(key));
1982
1983                 ArrayList<String> data = new ArrayList<>();
1984                 for(int x = 0; x < max; x++){
1985                     String tmpKey = String.format("%s[%d]", listKey, x);
1986                     String tmpValue = tmpPrefixMap.get(tmpKey);
1987                     if(tmpValue != null && !tmpValue.isEmpty()) {
1988                         data.add(tmpValue);
1989                     }
1990                 }
1991                 if(!data.isEmpty()) {
1992                     prefixMap.put(listKey, data.toString());
1993                 } else {
1994                     prefixMap.put(key, tmpPrefixMap.get(key));
1995                 }
1996             } else {
1997                 prefixMap.put(key, tmpPrefixMap.get(key));
1998             }
1999         }
2000
2001         return prefixMap;
2002     }
2003
2004     /**
2005     */
2006     protected NamedQueryData extractNamedQueryDataFromQueryPrefix(HashMap<String, String> nameValues, Map<String, String> parms) {
2007         if(parms.isEmpty()) {
2008             return null;
2009         }
2010
2011         NamedQueryData data = new NamedQueryData();
2012
2013         // query parameters
2014         if(data.getQueryParameters() == null) {
2015             data.setQueryParameters(new QueryParameters());
2016         }
2017         String namedQueryUuid = nameValues.get("named-query-uuid".replaceAll("-", "_"));
2018         if(namedQueryUuid == null) {
2019             namedQueryUuid = parms.get("query-parameters.named-query.named-query-uuid");
2020         }
2021         NamedQuery namedQuery = new NamedQuery();
2022         namedQuery.setNamedQueryUuid(namedQueryUuid);
2023         data.getQueryParameters().setNamedQuery(namedQuery);
2024
2025         // instance filters
2026         if(data.getInstanceFilters() == null) {
2027             data.setInstanceFilters(new InstanceFilters());
2028         }
2029
2030
2031         String quantity = parms.get("instance-filters.instance-filter_length");
2032         if(quantity != null && StringUtils.isNumeric(quantity)) {
2033             int max = Integer.parseInt(quantity);
2034             for(int i = 0; i < max; i++) {
2035                 String keyPattern = String.format("instance-filters.instance-filter[%d].", i);
2036                 Set<String> keys = parms.keySet();
2037                 for(String key: keys) {
2038                     if(key.startsWith(keyPattern)){
2039                         String value = parms.get(key);
2040                         String remainder = key.substring(keyPattern.length());
2041                         String[] split = remainder.split("\\.");
2042                         getLogger().debug(String.format("%s", remainder));
2043                         if("logical-link".equals(split[0])) {
2044                             InstanceFilter insf = null;
2045                             if(data.getInstanceFilters().getInstanceFilter().isEmpty()) {
2046                                 insf = new InstanceFilter();
2047                                 data.getInstanceFilters().getInstanceFilter().add(insf);
2048                             } else {
2049                                 insf = data.getInstanceFilters().getInstanceFilter().get(0);
2050                             }
2051                             LogicalLink logicalLink = insf.getLogicalLink();
2052                             if(logicalLink == null) {
2053                                 logicalLink = new LogicalLink();
2054                                 insf.setLogicalLink(logicalLink);
2055                             }
2056
2057                             switch(split[1]) {
2058                             case "link-name":
2059                                 logicalLink.setLinkName(value);
2060                                 break;
2061                             case "link-type":
2062                                 logicalLink.setLinkType(value);
2063                                 break;
2064                             case "operational-state":
2065                                 logicalLink.setOperationalStatus(value);
2066                                 break;
2067                             }
2068
2069                         } else if("pnf".equals(split[0])) {
2070                             Pnf pnf = new Pnf();
2071                             pnf.setPnfName(value);
2072
2073                             InstanceFilter insf = new InstanceFilter();
2074                             insf.setPnf(pnf);
2075                             data.getInstanceFilters().getInstanceFilter().add(insf);
2076
2077                         } else if("service-instance".equals(split[0])) {
2078                             ServiceInstance serviceInstance = new ServiceInstance();
2079                             serviceInstance.setServiceInstanceId(value);
2080
2081                             InstanceFilter insf = new InstanceFilter();
2082                             insf.setServiceInstance(serviceInstance);
2083                             data.getInstanceFilters().getInstanceFilter().add(insf);
2084
2085                         } else if("l3-network".equals(split[0])) {
2086                             L3Network l3Network = new L3Network();
2087                             if("network-role".equals(split[1])) {
2088                                 l3Network.setNetworkRole(value);
2089                             }
2090
2091                             InstanceFilter insf = new InstanceFilter();
2092                             insf.setL3Network(l3Network);
2093                             data.getInstanceFilters().getInstanceFilter().add(insf);
2094                         } else if("generic-vnf".equals(split[0])) {
2095                             GenericVnf vnf = new GenericVnf();
2096                             if("vnf-id".equals(split[1])) {
2097                                 vnf.setVnfId(value);
2098                             }
2099
2100                             InstanceFilter insf = new InstanceFilter();
2101                             insf.setGenericVnf(vnf);
2102                             data.getInstanceFilters().getInstanceFilter().add(insf);
2103                         }
2104                     }
2105                 }
2106             }
2107         }
2108
2109         return data;
2110     }
2111
2112     public abstract <T> T getResource(String key, Class<T> type) throws AAIServiceException ;
2113     protected abstract boolean deleteList(URL url, String caller) throws AAIServiceException;
2114 }