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