Update Janusgraph to 0.4.0 in aai-common
[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
21 package org.onap.aai.introspection;
22
23 import com.google.common.base.CaseFormat;
24 import com.google.common.base.Joiner;
25
26 import java.io.StringWriter;
27 import java.io.UnsupportedEncodingException;
28 import java.util.ArrayList;
29 import java.util.Arrays;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.LinkedHashSet;
33 import java.util.List;
34 import java.util.Map;
35 import java.util.Map.Entry;
36 import java.util.Set;
37
38 import javax.xml.bind.JAXBException;
39 import javax.xml.bind.Marshaller;
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.dynamic.DynamicJAXBContext;
46 import org.eclipse.persistence.mappings.DatabaseMapping;
47 import org.eclipse.persistence.oxm.XMLField;
48 import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping;
49 import org.eclipse.persistence.oxm.mappings.XMLCompositeDirectCollectionMapping;
50 import org.onap.aai.config.SpringContextAware;
51 import org.onap.aai.logging.LogFormatTools;
52 import org.onap.aai.restcore.MediaType;
53 import org.onap.aai.schema.enums.ObjectMetadata;
54 import org.onap.aai.schema.enums.PropertyMetadata;
55 import org.onap.aai.setup.SchemaVersion;
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58 import org.springframework.web.util.UriUtils;
59
60 public class MoxyStrategy extends Introspector {
61
62     private static final Logger LOGGER = LoggerFactory.getLogger(MoxyStrategy.class);
63     private DynamicEntity internalObject = null;
64     private DynamicType internalType = null;
65     private DynamicJAXBContext jaxbContext = null;
66     private ClassDescriptor cd = null;
67     private SchemaVersion 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         version = nodeIngestor.getVersionFromClassName(internalObject.getClass().getName());
80         super.loader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(getModelType(), version);
81         jaxbContext = nodeIngestor.getContextForVersion(version);
82         String simpleName = internalObject.getClass().getName();
83         internalType = jaxbContext.getDynamicType(simpleName);
84
85         cd = internalType.getDescriptor();
86     }
87
88     private void init() {
89         isInitialized = true;
90
91         Set<String> props = new LinkedHashSet<>();
92         for (String s : internalType.getPropertiesNames()) {
93             String value = caseFormatStore.fromLowerCamelToLowerHyphen(s).orElseGet(() -> {
94                 LOGGER.debug("Unable to find {} in the store from lower camel to lower hyphen", s);
95                 return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, s);
96             });
97             props.add(value);
98
99         }
100         props = Collections.unmodifiableSet(props);
101         this.properties = props;
102
103         Set<String> 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 && x.isRequired()) {
108                     requiredProps.add(this.removeXPathDescriptor(x.getName()));
109                 }
110             }
111         }
112         requiredProps = Collections.unmodifiableSet(requiredProps);
113         this.requiredProperties = requiredProps;
114
115         Set<String> keys = new LinkedHashSet<>();
116
117         for (String name : internalType.getDescriptor().getPrimaryKeyFieldNames()) {
118             keys.add(this.removeXPathDescriptor(name));
119         }
120         keys = Collections.unmodifiableSet(keys);
121         this.keys = keys;
122
123     }
124
125     @Override
126     public boolean hasProperty(String name) {
127         String convertedName = convertPropertyName(name);
128
129         return internalType.containsProperty(convertedName);
130     }
131
132     @Override
133     public Object get(String name) {
134         return internalObject.get(name);
135     }
136
137     @Override
138     public void set(String name, Object obj) {
139
140         internalObject.set(name, obj);
141     }
142
143     @Override
144     public Set<String> getProperties() {
145
146         if (!isInitialized) {
147             init();
148         }
149
150         return this.properties;
151
152     }
153
154     @Override
155     public Set<String> getRequiredProperties() {
156
157         if (!isInitialized) {
158             init();
159         }
160
161         return this.requiredProperties;
162     }
163
164     @Override
165     public Set<String> getKeys() {
166
167         if (!isInitialized) {
168             init();
169         }
170
171         return this.keys;
172     }
173
174     @Override
175     public Map<PropertyMetadata, String> getPropertyMetadata(String prop) {
176         String propName = this.convertPropertyName(prop);
177         DatabaseMapping mapping = cd.getMappingForAttributeName(propName);
178         Map<PropertyMetadata, String> result = new HashMap<>();
179         if (mapping != null) {
180             Set<Map.Entry<String, String>> entrySet = mapping.getProperties().entrySet();
181             for (Entry<String, String> entry : entrySet) {
182                 result.put(
183                         PropertyMetadata
184                                 .valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, entry.getKey())),
185                         entry.getValue());
186             }
187         }
188
189         return result;
190     }
191
192     @Override
193     public String getJavaClassName() {
194         return internalObject.getClass().getName();
195     }
196
197     @Override
198     public Class<?> getClass(String name) {
199         name = convertPropertyName(name);
200         Class<?> resultClass = null;
201         try {
202             if (internalType.getPropertyType(name) == null) {
203                 if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) {
204                     resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
205
206                 } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) {
207                     resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
208                 } else {
209                     ClassDescriptor referenceDiscriptor = cd.getMappingForAttributeName(name).getReferenceDescriptor();
210                     if (referenceDiscriptor != null) {
211                         resultClass = referenceDiscriptor.getJavaClass();
212                     } else {
213                         resultClass = Object.class;
214                     }
215                 }
216             } else {
217                 resultClass = internalType.getPropertyType(name);
218             }
219         } catch (DynamicException e) {
220             // property doesn't exist
221         }
222         return resultClass;
223     }
224
225     @Override
226     public Class<?> getGenericTypeClass(String name) {
227         name = convertPropertyName(name);
228         Class<?> resultClass = null;
229         if (internalType.getPropertyType(name) == null) {
230             if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) {
231                 resultClass = cd.getMappingForAttributeName(name).getFields().get(0).getType();
232
233             } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) {
234                 resultClass = cd.getMappingForAttributeName(name).getReferenceDescriptor().getJavaClass();
235             }
236         }
237
238         return resultClass;
239     }
240
241     @Override
242     public Object getUnderlyingObject() {
243         return this.internalObject;
244     }
245
246     @Override
247     public String getChildName() {
248
249         String className = internalObject.getClass().getSimpleName();
250         String lowerHyphen = caseFormatStore.fromUpperCamelToLowerHyphen(className).orElseGet(() -> {
251             LOGGER.debug("Unable to find {} in the store for upper camel to lower hyphen", className);
252             return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
253         });
254
255         if (this.isContainer()) {
256             String upperCamel = this.getGenericTypeClass(this.getProperties().iterator().next()).getSimpleName();
257
258             lowerHyphen = caseFormatStore.fromUpperCamelToLowerHyphen(upperCamel).orElseGet(() -> {
259                 LOGGER.debug("Unable to find {} in the store for upper camel to lower hyphen", upperCamel);
260                 return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, upperCamel);
261             });
262         }
263
264         return lowerHyphen;
265     }
266
267     @Override
268     public String getName() {
269         String className = internalObject.getClass().getSimpleName();
270         return caseFormatStore.fromUpperCamelToLowerHyphen(className).orElseGet(() -> {
271             LOGGER.debug("Unable to find {} in the store for upper camel to lower hyphen", className);
272             return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
273         });
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[] split = key.split("/");
311         int i = 0;
312         for (i = split.length - 1; i >= 0; i--) {
313
314             if (jaxbContext.getDynamicType(split[i]) != null) {
315                 break;
316
317             }
318
319         }
320         result = Joiner.on("/").join(Arrays.copyOfRange(split, 0, i));
321
322         return result;
323
324     }
325
326     @Override
327     public String marshal(MarshallerProperties properties) {
328         StringWriter result = new StringWriter();
329         try {
330             Marshaller marshaller = jaxbContext.createMarshaller();
331             if (properties.getMediaType().equals(MediaType.APPLICATION_JSON_TYPE)) {
332                 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.MEDIA_TYPE,
333                         "application/json");
334                 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_INCLUDE_ROOT,
335                         properties.getIncludeRoot());
336                 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME,
337                         properties.getWrapperAsArrayName());
338                 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS,
339                         false);
340             }
341
342             marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, properties.getFormatted());
343             marshaller.marshal(this.internalObject, result);
344         } catch (JAXBException e) {
345             LOGGER.warn("Encountered an jaxb exception during marshalling ", LogFormatTools.getStackTop(e));
346         }
347
348         return result.toString();
349     }
350
351     @Override
352     public ModelType getModelType() {
353         return ModelType.MOXY;
354     }
355
356     private String removeXPathDescriptor(String name) {
357
358         return name.replaceAll("/text\\(\\)", "");
359     }
360
361     @Override
362     public String getMetadata(ObjectMetadata name) {
363
364         return (String) cd.getProperty(name.toString());
365     }
366
367     @Override
368     public SchemaVersion getVersion() {
369
370         return this.version;
371     }
372 }