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