Update license files, sonar plugin and fix tests
[aai/aai-common.git] / aai-core / src / main / java / org / openecomp / aai / introspection / PojoStrategy.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * org.openecomp.aai
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.aai.introspection;
22
23 import java.io.StringReader;
24 import java.io.StringWriter;
25 import java.lang.reflect.Field;
26 import java.lang.reflect.InvocationTargetException;
27 import java.lang.reflect.Method;
28 import java.lang.reflect.ParameterizedType;
29 import java.lang.reflect.Type;
30 import java.util.ArrayList;
31 import java.util.Arrays;
32 import java.util.Collections;
33 import java.util.HashMap;
34 import java.util.LinkedHashSet;
35 import java.util.List;
36 import java.util.Map;
37 import java.util.Set;
38
39 import javax.xml.bind.JAXBContext;
40 import javax.xml.bind.JAXBException;
41 import javax.xml.bind.Marshaller;
42 import javax.xml.bind.Unmarshaller;
43 import javax.xml.bind.annotation.XmlElement;
44 import javax.xml.transform.stream.StreamSource;
45
46 import org.eclipse.persistence.jaxb.UnmarshallerProperties;
47
48 import org.openecomp.aai.annotations.Metadata;
49 import org.openecomp.aai.logging.ErrorLogHelper;
50 import org.openecomp.aai.restcore.MediaType;
51 import org.openecomp.aai.schema.enums.ObjectMetadata;
52 import org.openecomp.aai.schema.enums.PropertyMetadata;
53 import com.google.common.base.CaseFormat;
54 import com.google.common.base.Joiner;
55 import com.google.common.collect.Multimap;
56
57 public class PojoStrategy extends Introspector {
58
59         private Object internalObject = null;
60         private PojoInjestor injestor = null;
61         private Multimap<String, String> keyProps = null;
62         private Metadata classLevelMetadata = null;
63         private Version version;
64         private JAXBContext jaxbContext;
65         private Marshaller marshaller;
66         private Unmarshaller unmarshaller;
67         private Set<String> properties = null;
68         private Set<String> keys = null;
69         private Set<String> requiredProperties = null;
70
71         private boolean isInitialized = false;
72         
73         protected PojoStrategy(Object obj) {
74                 super(obj);
75                 className = PojoStrategy.class.getSimpleName();
76                 this.internalObject = obj;
77                 injestor = new PojoInjestor();
78                 classLevelMetadata = obj.getClass().getAnnotation(Metadata.class);
79
80                 version = injestor.getVersion(obj.getClass().getName());
81                 jaxbContext = injestor.getContextForVersion(version);
82                 super.loader = LoaderFactory.createLoaderForVersion(getModelType(), version);
83                 try {
84                         marshaller = jaxbContext.createMarshaller();
85                         unmarshaller = jaxbContext.createUnmarshaller();
86                 } catch (JAXBException e) {
87
88                 }
89                 
90         }
91
92         private void init() {
93
94                 isInitialized = true;
95
96                 Set<String> properties = new LinkedHashSet<>();
97                 Set<String> keys = new LinkedHashSet<>();
98                 Set<String> required = new LinkedHashSet<>();
99
100                 Field[] fields = this.internalObject.getClass().getDeclaredFields();
101                 
102                 for (Field field : fields) {
103                         if (!field.getName().equals("any")) {
104                                 properties.add(covertFieldToOutputFormat(field.getName()));
105                                 Metadata annotation = field.getAnnotation(Metadata.class);
106                                 XmlElement xmlAnnotation = field.getAnnotation(XmlElement.class);
107                                 if (annotation != null) {
108                                         if (annotation.isKey()) {
109                                                 keys.add(covertFieldToOutputFormat(field.getName()));
110                                         }
111                                 }
112                                 if (xmlAnnotation != null) {
113                                         if (xmlAnnotation.required()) {
114                                                 required.add(covertFieldToOutputFormat(field.getName()));
115                                         }
116                                 }
117                         }
118                 }
119                 properties = Collections.unmodifiableSet(properties);
120                 this.properties = properties;
121                 
122                 keys = Collections.unmodifiableSet(keys);
123                 this.keys = keys;
124                 
125                 required = Collections.unmodifiableSet(required);
126                 this.requiredProperties = required;
127                 
128         }
129         private String covertFieldToOutputFormat(String propName) {
130                 return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, propName);
131         }
132         
133         @Override
134         public boolean hasProperty(String name) {
135                 //TODO 
136                 return true;
137         }
138         
139         @Override
140         /**
141          * Gets the value of the property via reflection
142          */
143         public Object get(String name) {
144                 String getMethodName = "get" + CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, name);
145                 try {
146                         return this.internalObject.getClass().getDeclaredMethod(getMethodName).invoke(this.internalObject);                     
147                 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
148                         return null;
149                 }
150         }
151
152         @Override
153         public void set(String name, Object value) {
154                 String setMethodName = "set" + CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_CAMEL, name);
155                 try {
156                         this.internalObject.getClass().getDeclaredMethod(setMethodName, value.getClass()).invoke(this.internalObject, value);
157                 } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
158                         ErrorLogHelper.logError("AAI_4017", "Error setting name/value pair on POJO: " + e.getMessage());
159                 }
160         }
161
162         @Override
163         public Set<String> getProperties() {
164
165                 if(!isInitialized){
166                         this.init();
167                 }
168                 return this.properties;
169         }
170
171         
172         @Override
173         public Set<String> getRequiredProperties() {
174
175                 if(!isInitialized) {
176                         this.init();
177                 }
178                 return this.requiredProperties;
179         }
180
181         @Override
182         public Set<String> getKeys() {
183
184                 if(!isInitialized){
185                         this.init();
186                 }
187                 return this.keys;
188         }
189
190         public Class<?> getClass(String name) {
191
192                 Field field = null;
193                 try {
194                         field = this.internalObject.getClass().getDeclaredField(CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, name));
195                 } catch (NoSuchFieldException | SecurityException e) {
196                         
197                         return null;
198                 }
199                 
200                 return field.getType();
201         }
202         
203         public Class<?> getGenericTypeClass(String name) {
204                 
205                 try {
206                         String getMethodName = "get" + CaseFormat.LOWER_HYPHEN.to(CaseFormat.UPPER_CAMEL, name);
207                         Method method = internalObject.getClass().getDeclaredMethod(getMethodName);
208                         Type t = method.getGenericReturnType();
209                         if(t instanceof ParameterizedType) {
210                                 ParameterizedType pt = (ParameterizedType)t;
211                                 return ((Class<?>)pt.getActualTypeArguments()[0]);
212                         } else {
213                                 return null;
214                         }
215                         
216                 } catch (Exception e) {
217                         return null;
218                 }
219         }
220
221         @Override
222         public String getJavaClassName() {
223                 return internalObject.getClass().getName();
224         }
225         
226         @Override
227         public Object getUnderlyingObject() {
228                 return this.internalObject;
229         }
230         
231         @Override
232         public String getName() {
233                 String className = internalObject.getClass().getSimpleName();
234                 
235                 return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
236         }
237         
238         @Override
239         protected String findKey() {
240                 Set<String> keys = null;
241                 keys = this.getKeys();
242                 List<String> results = new ArrayList<>();
243                 for (String key : keys) {
244                         if (this.getType(key).toLowerCase().contains("long")) {
245                                 key = ((Long)this.getValue(key)).toString();
246                         } else {
247                                 key = (String)this.getValue(key);
248                         }
249                         results.add(key);
250                 }
251                 
252                 return Joiner.on("/").join(results);
253         }
254         
255         @Override
256         public String marshal(MarshallerProperties properties) {
257                 StringWriter result = new StringWriter();
258         try {
259                 if (properties.getMediaType().equals(MediaType.APPLICATION_JSON_TYPE)) {
260                                 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.MEDIA_TYPE, "application/json");
261                         marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_INCLUDE_ROOT, properties.getIncludeRoot());
262                         marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, properties.getWrapperAsArrayName());
263                 }
264                 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, properties.getFormatted());
265                 marshaller.marshal(this.internalObject, result);
266                 } catch (JAXBException e) {
267                         //e.printStackTrace();
268                 }
269
270         return result.toString();
271         }
272         
273         @Override
274         public Object clone() {
275                 Object result = null;
276                  try {
277                                 unmarshaller = jaxbContext.createUnmarshaller();
278
279                         unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
280                         unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
281                                 unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
282                                 
283                                 result = unmarshaller.unmarshal(new StreamSource(new StringReader(this.marshal(true))), this.internalObject.getClass()).getValue();
284                          } catch (JAXBException e) {
285                                         // TODO Auto-generated catch block
286                                         //e.printStackTrace();
287                         }
288                  result = IntrospectorFactory.newInstance(getModelType(), result);
289                  return result;
290         }
291         
292         @Override
293         public String preProcessKey (String key) {
294                 String result = "";
295                 //String trimmedRestURI = restURI.replaceAll("/[\\w\\-]+?/[\\w\\-]+?$", "");
296                 String[] split = key.split("/");
297                 int i = 0;
298                 for (i = split.length-1; i >= 0; i--) {
299                         
300                         if (keyProps.containsKey(split[i])) {
301                                 break;
302                                 
303                         }
304                         
305                 }
306                 result = Joiner.on("/").join(Arrays.copyOfRange(split, 0, i));
307                 
308                 return result;
309                 
310         }
311         
312         @Override
313         public ModelType getModelType() {
314                 return ModelType.POJO;
315         }
316
317         @Override
318         public String getChildName() {
319                 String className = internalObject.getClass().getSimpleName();
320                 String lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
321                 
322                 if (this.isContainer()) {
323                         lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,this.getGenericTypeClass(this.getProperties().iterator().next()).getSimpleName());
324                 }
325                 
326                 return lowerHyphen;
327         }
328
329         @Override
330         public Map<PropertyMetadata, String> getPropertyMetadata(String prop) {
331                 Field f;
332                 Map<PropertyMetadata, String> result = new HashMap<>();
333                 try {
334                         f = internalObject.getClass().getField(prop);
335                         Metadata m = f.getAnnotation(Metadata.class);
336                         if (m != null) {
337                                 Field[] fields = m.getClass().getFields();
338                                 String fieldName;
339                                 for (Field field : fields) {
340                                         fieldName = field.getName();
341                                         if (fieldName.equals("isAbstract")) {
342                                                 fieldName = "abstract";
343                                         } else if (fieldName.equals("extendsFrom")) {
344                                                 fieldName = "extends";
345                                         }
346                                         fieldName = CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, fieldName);
347                                         result.put(PropertyMetadata.valueOf(fieldName), (String)field.get(m));
348                                 }
349                         }
350                 } catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException e) {
351                         // TODO Auto-generated catch block
352                 }
353                 
354                 return result;
355         }
356
357         @Override
358         public String getObjectId() {
359                 // TODO Auto-generated method stub
360                 return null;
361         }
362         
363         @Override
364         public String getMetadata(ObjectMetadata metadataName) {
365                 String value = null;
366                 String methodName;
367                 if (ObjectMetadata.ABSTRACT.equals(metadataName)) {
368                         methodName = "isAbstract";
369                 } else if (ObjectMetadata.EXTENDS.equals(metadataName)) {
370                         methodName = "extendsFrom";
371                 } else {
372                         methodName = metadataName.toString();
373                 }
374                 
375                 try {
376                         value = (String)this.classLevelMetadata.getClass().getMethod(methodName).invoke(classLevelMetadata);
377                 } catch (IllegalArgumentException | IllegalAccessException | SecurityException | InvocationTargetException | NoSuchMethodException e) {
378                         //TODO
379                 }
380                 
381                 return value;
382         }
383
384         @Override
385         public Version getVersion() {
386                 // TODO Auto-generated method stub
387                 return null;
388         }
389 }