Initial commit with all the necessary files
[aai/aai-common.git] / aai-core / src / main / java / org / openecomp / aai / introspection / MoxyStrategy.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.io.UnsupportedEncodingException;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.Collections;
29 import java.util.HashMap;
30 import java.util.LinkedHashSet;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Map.Entry;
34 import java.util.Set;
35
36 import javax.xml.bind.JAXBException;
37 import javax.xml.bind.Marshaller;
38 import javax.xml.bind.Unmarshaller;
39 import javax.xml.transform.stream.StreamSource;
40
41 import org.eclipse.persistence.descriptors.ClassDescriptor;
42 import org.eclipse.persistence.dynamic.DynamicEntity;
43 import org.eclipse.persistence.dynamic.DynamicType;
44 import org.eclipse.persistence.exceptions.DynamicException;
45 import org.eclipse.persistence.jaxb.UnmarshallerProperties;
46 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
47 import org.eclipse.persistence.mappings.DatabaseMapping;
48 import org.eclipse.persistence.oxm.XMLField;
49 import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping;
50 import org.eclipse.persistence.oxm.mappings.XMLCompositeDirectCollectionMapping;
51 import org.springframework.web.util.UriUtils;
52
53 import org.openecomp.aai.restcore.MediaType;
54 import org.openecomp.aai.schema.enums.ObjectMetadata;
55 import org.openecomp.aai.schema.enums.PropertyMetadata;
56 import com.google.common.base.CaseFormat;
57 import com.google.common.base.Joiner;
58
59 public class MoxyStrategy extends Introspector {
60         
61         private DynamicEntity internalObject = null;
62         private DynamicType internalType = null;
63         private DynamicJAXBContext jaxbContext = null;
64         private ClassDescriptor cd = null;
65         private Marshaller marshaller = null;
66         private Unmarshaller unmarshaller = null;
67         private Version version = null;
68         private Set<String> properties = null;
69         private Set<String> keys = null;
70         private Set<String> requiredProperties = null;
71
72         private boolean isInitialized = false;
73         
74         protected MoxyStrategy(Object obj) {
75                 super(obj);
76                 /* must look up the correct jaxbcontext for this object */
77                 className = MoxyStrategy.class.getSimpleName();
78                 internalObject = (DynamicEntity)obj;
79                 ModelInjestor injestor = ModelInjestor.getInstance();
80                 version = injestor.getVersionFromClassName(internalObject.getClass().getName());
81                 jaxbContext = injestor.getContextForVersion(version);
82                 super.loader = LoaderFactory.createLoaderForVersion(getModelType(), version);
83                 String simpleName = internalObject.getClass().getName();
84                 internalType = jaxbContext.getDynamicType(simpleName);
85                 cd = internalType.getDescriptor();
86                 try {
87                         marshaller = jaxbContext.createMarshaller();
88                         unmarshaller = jaxbContext.createUnmarshaller();
89                 } catch (JAXBException e) {
90
91                 }
92
93         }
94         
95         private void init() {
96                 isInitialized = true;
97
98                 Set<String> props = new LinkedHashSet<>();
99                 for (String s : internalType.getPropertiesNames()) {
100                         props.add(CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, s));
101
102                 }
103                 props = Collections.unmodifiableSet(props);
104                 this.properties = props;
105                 
106                 Set<String> requiredProps = new LinkedHashSet<>();
107                 requiredProps = new LinkedHashSet<>();
108                 for (DatabaseMapping dm : cd.getMappings()) {
109                         if (dm.getField() instanceof XMLField) { 
110                                 XMLField x = (XMLField)dm.getField();
111                                 if (x != null) { 
112                                         if (x.isRequired()) {
113                                                 requiredProps.add(this.removeXPathDescriptor(x.getName()));
114                                         }
115                                 }
116                         }
117                 }
118                 requiredProps = Collections.unmodifiableSet(requiredProps);
119                 this.requiredProperties = requiredProps;
120         
121                 Set<String> keys = new LinkedHashSet<>();
122                 
123                 for (String name : internalType.getDescriptor().getPrimaryKeyFieldNames()) {
124                         keys.add(this.removeXPathDescriptor(name));
125                 }
126                 keys = Collections.unmodifiableSet(keys);
127                 this.keys = keys;
128                 
129                 
130         }
131         
132         @Override
133         public boolean hasProperty(String name) {
134                 String convertedName = convertPropertyName(name);
135
136                 return internalType.containsProperty(convertedName);    
137         }
138         
139         @Override
140         public Object get(String name) {
141                 return internalObject.get(name);
142         }
143
144         @Override
145         public void set(String name, Object obj) throws IllegalArgumentException {
146                 
147                 internalObject.set(name, obj);
148         }
149
150         @Override
151         public Set<String> getProperties() {
152
153                 if(!isInitialized){
154                         init();
155                 }
156
157                 return this.properties;
158                 
159         }
160
161         @Override
162         public Set<String> getRequiredProperties() {
163
164                 if(!isInitialized){
165                         init();
166                 }
167
168                 return this.requiredProperties;
169         }
170
171         @Override
172         public Set<String> getKeys() {
173
174                 if(!isInitialized){
175                         init();
176                 }
177
178                 return this.keys;
179         }
180         
181         @Override
182         public Map<PropertyMetadata, String> getPropertyMetadata(String prop) {
183                 String propName = this.convertPropertyName(prop);
184                 DatabaseMapping mapping = cd.getMappingForAttributeName(propName);
185                 Map<PropertyMetadata, String> result = new HashMap<>();
186                 if (mapping != null) {
187                         Set<Entry> entrySet = mapping.getProperties().entrySet();
188                         for (Entry<?,?> entry : entrySet) {
189                                 result.put(
190                                                 PropertyMetadata.valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, (String)entry.getKey())), (String)entry.getValue());
191                         }
192                 }
193                 
194                 return result;
195         }
196
197         @Override
198         public String getJavaClassName() {
199                 return internalObject.getClass().getName();
200         }
201         
202         
203
204         @Override
205         public Class<?> getClass(String name) {
206                 name = convertPropertyName(name);
207                 Class<?> resultClass = null;
208                 try {
209                         if (internalType.getPropertyType(name) == null) {
210                                 if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) {
211                                         resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
212         
213                                 } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) {
214                                         resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
215                                 } else {
216                                         ClassDescriptor referenceDiscriptor = cd.getMappingForAttributeName(name).getReferenceDescriptor();
217                                         if (referenceDiscriptor != null) {
218                                                 resultClass = referenceDiscriptor.getJavaClass();
219                                         } else {
220                                                 resultClass = Object.class;
221                                         }
222                                 }
223                         } else {
224                                 resultClass = internalType.getPropertyType(name);
225                         }
226                 } catch (DynamicException e) {
227                         //property doesn't exist
228                 }
229                 return resultClass;
230         }
231
232         @Override
233         public Class<?> getGenericTypeClass(String name) {
234                 name = convertPropertyName(name);
235                 Class<?> resultClass = null;
236                 if (internalType.getPropertyType(name) == null) {
237                         if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) {
238                                 resultClass = cd.getMappingForAttributeName(name).getFields().get(0).getType();
239
240                         } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) {
241                                 resultClass = cd.getMappingForAttributeName(name).getReferenceDescriptor().getJavaClass();
242                         }
243                 }
244                 
245                 return resultClass;
246         }
247
248         @Override
249         public Object getUnderlyingObject() {
250                 return this.internalObject;
251         }
252         
253         @Override
254         public String getChildName() {
255                 
256                 String className = internalObject.getClass().getSimpleName();
257                 String lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
258                 
259                 if (this.isContainer()) {
260                         lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,this.getGenericTypeClass(this.getProperties().iterator().next()).getSimpleName());
261                 }
262                 
263                 return lowerHyphen;
264         }
265         
266         @Override
267         public String getName() {
268                 String className = internalObject.getClass().getSimpleName();
269                 String lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
270                 /*
271                 if (this.isContainer()) {
272                         lowerHyphen = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN,this.getGenericTypeClass(this.getProperties().get(0)).getSimpleName());
273                 }*/
274                 
275
276                 return lowerHyphen;
277         }
278         
279         @Override
280         public String getObjectId() throws UnsupportedEncodingException {
281                 String result = "";
282                 String container = this.getMetadata(ObjectMetadata.CONTAINER);
283                 if (this.isContainer()) {
284                          result += "/" + this.getName();
285                 } else {
286                         
287                         if (container != null) {
288                                 result += "/" + container;
289                         }
290                         result += "/" + this.getDbName() + "/" + this.findKey();
291                         
292                 }
293                 
294                 return result;
295         }
296         
297         @Override
298         protected String findKey() throws UnsupportedEncodingException {
299                 Set<String> keys = null;
300                 keys = this.getKeys();
301                 List<String> results = new ArrayList<>();
302                 for (String key : keys) {
303                         if (this.getType(key).toLowerCase().contains("long")) {
304                                 key = ((Long)this.getValue(key)).toString();
305                         } else {
306                                 key = (String)this.getValue(key);
307                         }
308                         key = UriUtils.encode(key, "UTF-8");
309
310                         results.add(key);
311                 }
312                 
313                 return Joiner.on("/").join(results);
314         }
315         
316         @Override
317         public String preProcessKey (String key) {
318                 String result = "";
319                 //String trimmedRestURI = restURI.replaceAll("/[\\w\\-]+?/[\\w\\-]+?$", "");
320                 String[] split = key.split("/");
321                 int i = 0;
322                 for (i = split.length-1; i >= 0; i--) {
323                         
324                         if (jaxbContext.getDynamicType(split[i]) != null) {
325                                 break;
326                                 
327                         }
328                         
329                 }
330                 result = Joiner.on("/").join(Arrays.copyOfRange(split, 0, i));
331                 
332                 return result;
333                 
334         }
335         
336         @Override
337         public String marshal(MarshallerProperties properties) {
338                 StringWriter result = new StringWriter();
339         try {
340                 if (properties.getMediaType().equals(MediaType.APPLICATION_JSON_TYPE)) {
341                                 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.MEDIA_TYPE, "application/json");
342                         marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_INCLUDE_ROOT, properties.getIncludeRoot());
343                         marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, properties.getWrapperAsArrayName());
344                         marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, false);
345                 }
346                 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, properties.getFormatted());
347                 marshaller.marshal(this.internalObject, result);
348                 } catch (JAXBException e) {
349                         //e.printStackTrace();
350                 }
351
352         return result.toString();
353         }
354         
355         @Override
356         public Object clone() {
357                 Object result = null;
358                  try {
359                                 unmarshaller = jaxbContext.createUnmarshaller();
360
361                         unmarshaller.setProperty(UnmarshallerProperties.MEDIA_TYPE, "application/json");
362                         unmarshaller.setProperty(UnmarshallerProperties.JSON_INCLUDE_ROOT, false);
363                                 unmarshaller.setProperty(UnmarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, true);
364                                 
365                                 result = unmarshaller.unmarshal(new StreamSource(new StringReader(this.marshal(true))), this.internalObject.getClass()).getValue();
366                          } catch (JAXBException e) {
367                                         // TODO Auto-generated catch block
368                                         //e.printStackTrace();
369                         }
370                  result = IntrospectorFactory.newInstance(getModelType(), result);
371                  return result;
372         }
373         @Override
374         public ModelType getModelType() {
375                 return ModelType.MOXY;
376         }
377         
378         private String removeXPathDescriptor(String name) {
379                 
380                 return name.replaceAll("/text\\(\\)", "");
381         }
382
383         @Override
384         public String getMetadata(ObjectMetadata name) {
385                 
386                 return (String)cd.getProperty(name.toString());
387         }
388
389         @Override
390         public Version getVersion() {
391                 
392                 return this.version;
393         }
394 }