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