2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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=========================================================
21 package org.onap.aai.introspection;
23 import com.google.common.base.CaseFormat;
24 import com.google.common.base.Joiner;
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;
35 import java.util.Map.Entry;
38 import javax.xml.bind.JAXBException;
39 import javax.xml.bind.Marshaller;
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;
60 public class MoxyStrategy extends Introspector {
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;
72 private boolean isInitialized = false;
74 protected MoxyStrategy(Object 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);
85 cd = internalType.getDescriptor();
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);
100 props = Collections.unmodifiableSet(props);
101 this.properties = props;
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()));
112 requiredProps = Collections.unmodifiableSet(requiredProps);
113 this.requiredProperties = requiredProps;
115 Set<String> keys = new LinkedHashSet<>();
117 for (String name : internalType.getDescriptor().getPrimaryKeyFieldNames()) {
118 keys.add(this.removeXPathDescriptor(name));
120 keys = Collections.unmodifiableSet(keys);
126 public boolean hasProperty(String name) {
127 String convertedName = convertPropertyName(name);
129 return internalType.containsProperty(convertedName);
133 public Object get(String name) {
134 return internalObject.get(name);
138 public void set(String name, Object obj) {
140 internalObject.set(name, obj);
144 public Set<String> getProperties() {
146 if (!isInitialized) {
150 return this.properties;
155 public Set<String> getRequiredProperties() {
157 if (!isInitialized) {
161 return this.requiredProperties;
165 public Set<String> getKeys() {
167 if (!isInitialized) {
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) {
184 .valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, entry.getKey())),
193 public String getJavaClassName() {
194 return internalObject.getClass().getName();
198 public Class<?> getClass(String name) {
199 name = convertPropertyName(name);
200 Class<?> resultClass = null;
202 if (internalType.getPropertyType(name) == null) {
203 if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) {
204 resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
206 } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) {
207 resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
209 ClassDescriptor referenceDiscriptor = cd.getMappingForAttributeName(name).getReferenceDescriptor();
210 if (referenceDiscriptor != null) {
211 resultClass = referenceDiscriptor.getJavaClass();
213 resultClass = Object.class;
217 resultClass = internalType.getPropertyType(name);
219 } catch (DynamicException e) {
220 // property doesn't exist
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();
233 } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) {
234 resultClass = cd.getMappingForAttributeName(name).getReferenceDescriptor().getJavaClass();
242 public Object getUnderlyingObject() {
243 return this.internalObject;
247 public String getChildName() {
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);
255 if (this.isContainer()) {
256 String upperCamel = this.getGenericTypeClass(this.getProperties().iterator().next()).getSimpleName();
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);
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);
277 public String getObjectId() throws UnsupportedEncodingException {
279 String container = this.getMetadata(ObjectMetadata.CONTAINER);
280 if (this.isContainer()) {
281 result += "/" + this.getName();
284 if (container != null) {
285 result += "/" + container;
287 result += "/" + this.getDbName() + "/" + this.findKey();
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");
304 return Joiner.on("/").join(results);
308 public String preProcessKey(String key) {
310 String[] split = key.split("/");
312 for (i = split.length - 1; i >= 0; i--) {
314 if (jaxbContext.getDynamicType(split[i]) != null) {
320 result = Joiner.on("/").join(Arrays.copyOfRange(split, 0, i));
327 public String marshal(MarshallerProperties properties) {
328 StringWriter result = new StringWriter();
330 Marshaller marshaller = jaxbContext.createMarshaller();
331 if (properties.getMediaType().equals(MediaType.APPLICATION_JSON_TYPE)) {
332 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.MEDIA_TYPE,
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,
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));
348 return result.toString();
352 public ModelType getModelType() {
353 return ModelType.MOXY;
356 private String removeXPathDescriptor(String name) {
358 return name.replaceAll("/text\\(\\)", "");
362 public String getMetadata(ObjectMetadata name) {
364 return (String) cd.getProperty(name.toString());
368 public SchemaVersion getVersion() {