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