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