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