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