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