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