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