Implement support for inner variables
[ccsdk/sli/adaptors.git] / aai-service / provider / src / main / java / org / onap / ccsdk / sli / adaptors / aai / AAIServiceUtils.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * openECOMP : SDN-C
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights
6  *             reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21
22 package org.onap.ccsdk.sli.adaptors.aai;
23
24 import java.lang.annotation.Annotation;
25 import java.lang.reflect.Method;
26 import java.net.MalformedURLException;
27 import java.net.URI;
28 import java.net.URISyntaxException;
29 import java.util.Arrays;
30 import java.util.HashMap;
31 import java.util.Map;
32 import java.util.HashSet;
33 import java.util.Iterator;
34 import java.util.LinkedList;
35 import java.util.List;
36 import java.util.Set;
37
38 import javax.xml.bind.annotation.XmlType;
39
40 import org.apache.commons.lang.StringUtils;
41 import org.onap.aai.inventory.v14.Relationship;
42 import org.onap.aai.inventory.v14.RelationshipData;
43 import org.onap.aai.inventory.v14.RelationshipList;
44 import org.onap.ccsdk.sli.core.sli.SvcLogicContext;
45 import org.onap.ccsdk.sli.adaptors.aai.data.AAIDatum;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48
49 public class AAIServiceUtils {
50
51     private static final String VERSION_PATTERN = "/v$/";
52
53     private static final Logger LOG = LoggerFactory.getLogger(AAIService.class);
54
55     private AAIServiceUtils() {
56     }
57
58     public static String getPrimaryIdFromClass(Class<? extends AAIDatum> resourceClass){
59         // 1. find class
60         getLogger().debug(resourceClass.getName());
61
62         try {
63             Annotation[] annotations = resourceClass.getAnnotations();
64             for(Annotation annotation : annotations) {
65                 Class<? extends Annotation> anotationType = annotation.annotationType();
66                 String annotationName = anotationType.getName();
67
68                 // 2. find string property setters and getters for the lists
69                 if("javax.xml.bind.annotation.XmlType".equals(annotationName)){
70                     XmlType order = (XmlType)annotation;
71                     String[]  values = order.propOrder();
72                     for(String value : values) {
73                         String id = camelCaseToDashedString(value);
74                         return id;
75                     }
76                 }
77             }
78         } catch(Exception exc) {
79             getLogger().warn("getPrimaryIdFromClass failed", exc);
80         }
81         return null;
82     }
83
84     public static String getSecondaryIdFromClass(Class<? extends AAIDatum> resourceClass){
85         getLogger().debug(resourceClass.getName());
86
87         try {
88             Annotation[] annotations = resourceClass.getAnnotations();
89             for(Annotation annotation : annotations) {
90                 Class<? extends Annotation> anotationType = annotation.annotationType();
91                 String annotationName = anotationType.getName();
92
93                 // 2. find string property setters and getters for the lists
94                 if("javax.xml.bind.annotation.XmlType".equals(annotationName)){
95                     boolean primaryIdFound = false;
96                     XmlType order = (XmlType)annotation;
97                     String[]  values = order.propOrder();
98                     for(String value : values) {
99                         String id = camelCaseToDashedString(value);
100                         if(primaryIdFound) {
101                             return id;
102                         } else {
103                             primaryIdFound = true;
104                         }
105                     }
106                 }
107             }
108         } catch(Exception exc) {
109
110         }
111         return null;
112     }
113
114     public static Method getRelationshipListGetterMethodFromClassDefinition(Class resourceClass) {
115         Method getRelationshipListMethod = null;
116
117         try {
118              getRelationshipListMethod = resourceClass.getMethod("getRelationshipList");
119         } catch(Exception exc) {
120             getLogger().debug("Retrofiting relationship data: " + exc.getMessage());
121         }
122         return getRelationshipListMethod;
123     }
124
125     private static Logger getLogger() {
126         return LOG;
127     }
128
129
130     private static final String regex = "([A-Z][a-z,0-9]+)";
131     private static final String replacement = "-$1";
132
133     public static String camelCaseToDashedString(String propOrder) {
134         return propOrder.replaceAll(regex, replacement).toLowerCase();
135     }
136
137     public static HashMap<String,String> keyToHashMap(String key,    SvcLogicContext ctx) {
138         if (key == null) {
139             return (null);
140         }
141
142         getLogger().debug("Converting key [" + key + "] to where clause");
143
144         if (key.startsWith("'") && key.endsWith("'")) {
145             key = key.substring(1, key.length() - 1);
146
147             getLogger().debug("Stripped outer single quotes - key is now [" + key + "]");
148         }
149
150         String[] keyTerms = key.split("\\s+");
151
152         StringBuffer whereBuff = new StringBuffer();
153         String term1 = null;
154         String op = null;
155         String term2 = null;
156         HashMap<String, String> results = new HashMap<String, String>();
157
158         for (int i = 0; i < keyTerms.length; i++) {
159             if (term1 == null) {
160                 if ("and".equalsIgnoreCase(keyTerms[i])
161                         || "or".equalsIgnoreCase(keyTerms[i])) {
162                     // Skip over ADD/OR
163                 } else {
164                     term1 = resolveTerm(keyTerms[i], ctx);
165                 }
166             } else if (op == null) {
167                 if ("==".equals(keyTerms[i])) {
168                     op = "=";
169                 } else {
170                     op = keyTerms[i];
171                 }
172             } else {
173                 term2 = resolveTerm(keyTerms[i], ctx);
174                 term2 = term2.trim().replace("'", "").replace("$", "").replace("'", "");
175                 results.put(term1,  term2);
176
177                 term1 = null;
178                 op = null;
179                 term2 = null;
180             }
181         }
182
183         return (results);
184     }
185
186     private static String resolveTerm(String term, SvcLogicContext ctx) {
187         if (term == null) {
188             return (null);
189         }
190
191         getLogger().debug("resolveTerm: term is " + term);
192
193         if (term.startsWith("$") && (ctx != null)) {
194             // Resolve any index variables.
195
196             term = ("'" + resolveCtxVariable(term.substring(1), ctx) + "'");
197             if (term.contains(VERSION_PATTERN) && (ctx != null)) {
198                 return term.replace(VERSION_PATTERN, AAIRequest.getSupportedAAIVersion());
199             }
200             return term;
201         } else if (term.contains(VERSION_PATTERN) && (ctx != null)) {
202             return term.replace(VERSION_PATTERN, AAIRequest.getSupportedAAIVersion());
203         } else if (term.startsWith("'") || term.startsWith("\"")) {
204             return (term);
205         } else {
206             return (term.replaceAll("-", "_"));
207
208         }
209     }
210
211     private static String resolveCtxVariable(String ctxVarName, SvcLogicContext ctx) {
212
213         if (ctxVarName.indexOf('[') == -1) {
214             // Ctx variable contains no arrays
215             return (ctx.getAttribute(ctxVarName));
216         }
217
218         // Resolve any array references
219         StringBuffer sbuff = new StringBuffer();
220         String[] ctxVarParts = ctxVarName.split("\\[");
221         sbuff.append(ctxVarParts[0]);
222         for (int i = 1; i < ctxVarParts.length; i++) {
223             if (ctxVarParts[i].startsWith("$")) {
224                 int endBracketLoc = ctxVarParts[i].indexOf("]");
225                 if (endBracketLoc == -1) {
226                     // Missing end bracket ... give up parsing
227                     getLogger().warn("Variable reference " + ctxVarName
228                             + " seems to be missing a ']'");
229                     return (ctx.getAttribute(ctxVarName));
230                 }
231
232                 String idxVarName = ctxVarParts[i].substring(1, endBracketLoc);
233                 String remainder = ctxVarParts[i].substring(endBracketLoc);
234
235                 sbuff.append("[");
236                 sbuff.append(ctx.getAttribute(idxVarName));
237                 sbuff.append(remainder);
238
239             } else {
240                 // Index is not a variable reference
241                 sbuff.append("[");
242                 sbuff.append(ctxVarParts[i]);
243             }
244         }
245
246         return (ctx.getAttribute(sbuff.toString()));
247     }
248
249     public static void populateRelationshipDataFromPath(RelationshipList rl) throws URISyntaxException {
250         List<Relationship> list =  rl.getRelationship();
251         if(list != null && !list.isEmpty()) {
252             for(Relationship relationship : list) {
253                 if(relationship.getRelationshipData().isEmpty()){
254                     String link = relationship.getRelatedLink();
255                     URI uri = new URI(link);
256                         link = uri.getPath();
257                     HashMap<String,String> contributors = pathToHashMap(link);
258                     for(String key : contributors.keySet()) {
259                         RelationshipData rd = new RelationshipData();
260                         rd.setRelationshipKey(key);
261                         rd.setRelationshipValue(contributors.get(key));
262                         relationship.getRelationshipData().add(rd);
263                     }
264                 }
265             }
266         }
267     }
268
269     protected static HashMap<String,String> pathToHashMap(String path) {
270         HashMap<String, String> nameValues = new  HashMap<String, String>();
271
272         String[] split = path.split("/");
273
274         LinkedList<String> list = new LinkedList<String>( Arrays.asList(split));
275         Iterator<String> it = list.iterator();
276
277         while(it.hasNext()) {
278             String tag = it.next();
279             if(!tag.isEmpty()) {
280                 if(AAIRequest.getResourceNames().contains(tag)){
281                     LOG.info(tag);
282                     // get the class from tag
283                     Class<? extends AAIDatum> clazz = AAIRequest.getClassFromResource(tag);
284                     String fieldName = AAIServiceUtils.getPrimaryIdFromClass(clazz);
285
286                     String value = it.next();
287                     if(!StringUtils.isEmpty(value)){
288                         nameValues.put(String.format("%s.%s", tag, fieldName), value);
289                         switch(tag) {
290                         case "cloud-region":
291                         case "entitlement":
292                         case "license":
293                         case "route-target":
294                         case "service-capability":
295                         case "ctag-pool":
296                             String secondaryFieldName = AAIServiceUtils.getSecondaryIdFromClass(clazz);
297                             if(secondaryFieldName != null) {
298                                 value = it.next();
299                                 nameValues.put(String.format("%s.%s", tag, secondaryFieldName), value);
300                             }
301                             break;
302                         default:
303                             break;
304                         }
305                     }
306                 }
307             }
308         }
309         return nameValues;
310     }
311
312     public static String getPathForResource(String resource, String key, SvcLogicContext ctx ) throws MalformedURLException{
313         HashMap<String, String> nameValues = AAIServiceUtils.keyToHashMap(key, ctx);
314         AAIRequest request = AAIRequest.createRequest(resource, nameValues);
315
316         for(String name : nameValues.keySet()) {
317             request.addRequestProperty(name, nameValues.get(name));
318         }
319         return request.getRequestPath();
320     }
321
322     public static boolean isValidFormat(String resource, Map<String, String> nameValues) {
323
324         switch(resource){
325     case "custom-query":
326         case "formatted-query":
327         case "generic-query":
328         case "named-query":
329         case "nodes-query":
330         case "linterface":
331         case "l2-bridge-sbg":
332         case "l2-bridge-bgf":
333         case "echo":
334         case "test":
335             return true;
336         }
337         if(resource.contains(":")) {
338             resource = resource.substring(0, resource.indexOf(":"));
339         }
340
341         Set<String> keys = nameValues.keySet();
342         for(String key : keys) {
343             if(!key.contains(".")) {
344                 if("depth".equals(key) || "related-to".equals(key) || "related_to".equals(key) || "related-link".equals(key) || "related_link".equals(key) || "selflink".equals(key) || "resource_path".equals(key))
345                     continue;
346                 else {
347                     getLogger().warn(String.format("key '%s' is incompatible with resource type '%s'", key, resource));
348                 }
349             }
350         }
351         return true;
352     }
353
354     public static boolean containsResource(String resource, HashMap<String, String> nameValues) {
355         if(resource.contains(":")) {
356             return true;
357         }
358
359         switch(resource){
360         case "custom-query":
361         case "formatted-query":
362         case "generic-query":
363         case "named-query":
364         case "nodes-query":
365         case "linterface":
366         case "l2-bridge-sbg":
367         case "l2-bridge-bgf":
368         case "echo":
369         case "test":
370             return true;
371
372         default:
373             if(nameValues.containsKey("selflink")) {
374                 return true;
375             }
376         }
377
378         Set<String> tags = new HashSet<>();
379
380         for(String key : nameValues.keySet()) {
381             key = key.replace("_", "-");
382             if(key.contains(".")) {
383                 String[] split = key.split("\\.");
384                 tags.add(split[0]);
385             } else {
386                 tags.add(key);
387             }
388         }
389         return tags.contains(resource);
390     }
391 }