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