5b9e10519cec31dae8ddc3ef3ed801a150ccdaa6
[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 }