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