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