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;
29 import java.util.Map.Entry;
31 import javax.xml.bind.JAXBException;
32 import javax.xml.bind.Marshaller;
34 import org.eclipse.persistence.descriptors.ClassDescriptor;
35 import org.eclipse.persistence.dynamic.DynamicEntity;
36 import org.eclipse.persistence.dynamic.DynamicType;
37 import org.eclipse.persistence.exceptions.DynamicException;
38 import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContext;
39 import org.eclipse.persistence.mappings.DatabaseMapping;
40 import org.eclipse.persistence.oxm.XMLField;
41 import org.eclipse.persistence.oxm.mappings.XMLCompositeCollectionMapping;
42 import org.eclipse.persistence.oxm.mappings.XMLCompositeDirectCollectionMapping;
43 import org.onap.aai.config.SpringContextAware;
44 import org.onap.aai.logging.LogFormatTools;
45 import org.onap.aai.restcore.MediaType;
46 import org.onap.aai.schema.enums.ObjectMetadata;
47 import org.onap.aai.schema.enums.PropertyMetadata;
48 import org.onap.aai.setup.SchemaVersion;
49 import org.slf4j.Logger;
50 import org.slf4j.LoggerFactory;
51 import org.springframework.web.util.UriUtils;
53 public class MoxyStrategy extends Introspector {
55 private static final Logger LOGGER = LoggerFactory.getLogger(MoxyStrategy.class);
56 private DynamicEntity internalObject = null;
57 private DynamicType internalType = null;
58 private DynamicJAXBContext jaxbContext = null;
59 private ClassDescriptor cd = null;
60 private SchemaVersion version = null;
61 private Set<String> properties = null;
62 private Set<String> keys = null;
63 private Set<String> requiredProperties = null;
65 private boolean isInitialized = false;
67 protected MoxyStrategy(Object obj) {
69 /* must look up the correct jaxbcontext for this object */
70 className = MoxyStrategy.class.getSimpleName();
71 internalObject = (DynamicEntity) obj;
72 version = nodeIngestor.getVersionFromClassName(internalObject.getClass().getName());
73 super.loader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(getModelType(), version);
74 jaxbContext = nodeIngestor.getContextForVersion(version);
75 String simpleName = internalObject.getClass().getName();
76 internalType = jaxbContext.getDynamicType(simpleName);
78 cd = internalType.getDescriptor();
84 Set<String> props = new LinkedHashSet<>();
85 for (String s : internalType.getPropertiesNames()) {
86 String value = caseFormatStore.fromLowerCamelToLowerHyphen(s).orElseGet(() -> {
87 LOGGER.debug("Unable to find {} in the store from lower camel to lower hyphen", s);
88 return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, s);
93 props = Collections.unmodifiableSet(props);
94 this.properties = props;
96 Set<String> requiredProps = new LinkedHashSet<>();
97 for (DatabaseMapping dm : cd.getMappings()) {
98 if (dm.getField() instanceof XMLField) {
99 XMLField x = (XMLField) dm.getField();
100 if (x != null && x.isRequired()) {
101 requiredProps.add(this.removeXPathDescriptor(x.getName()));
105 requiredProps = Collections.unmodifiableSet(requiredProps);
106 this.requiredProperties = requiredProps;
108 Set<String> keys = new LinkedHashSet<>();
110 for (String name : internalType.getDescriptor().getPrimaryKeyFieldNames()) {
111 keys.add(this.removeXPathDescriptor(name));
113 keys = Collections.unmodifiableSet(keys);
119 public boolean hasProperty(String name) {
120 String convertedName = convertPropertyName(name);
122 return internalType.containsProperty(convertedName);
126 public Object get(String name) {
127 return internalObject.get(name);
131 public void set(String name, Object obj) {
133 internalObject.set(name, obj);
137 public Set<String> getProperties() {
139 if (!isInitialized) {
143 return this.properties;
148 public Set<String> getRequiredProperties() {
150 if (!isInitialized) {
154 return this.requiredProperties;
158 public Set<String> getKeys() {
160 if (!isInitialized) {
168 public Map<PropertyMetadata, String> getPropertyMetadata(String prop) {
169 String propName = this.convertPropertyName(prop);
170 DatabaseMapping mapping = cd.getMappingForAttributeName(propName);
171 Map<PropertyMetadata, String> result = new HashMap<>();
172 if (mapping != null) {
173 Set<Entry> entrySet = mapping.getProperties().entrySet();
174 for (Entry<?, ?> entry : entrySet) {
176 PropertyMetadata.valueOf(
177 CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, (String) entry.getKey())),
178 (String) entry.getValue());
186 public String getJavaClassName() {
187 return internalObject.getClass().getName();
191 public Class<?> getClass(String name) {
192 name = convertPropertyName(name);
193 Class<?> resultClass = null;
195 if (internalType.getPropertyType(name) == null) {
196 if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) {
197 resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
199 } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) {
200 resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
202 ClassDescriptor referenceDiscriptor = cd.getMappingForAttributeName(name).getReferenceDescriptor();
203 if (referenceDiscriptor != null) {
204 resultClass = referenceDiscriptor.getJavaClass();
206 resultClass = Object.class;
210 resultClass = internalType.getPropertyType(name);
212 } catch (DynamicException e) {
213 // property doesn't exist
219 public Class<?> getGenericTypeClass(String name) {
220 name = convertPropertyName(name);
221 Class<?> resultClass = null;
222 if (internalType.getPropertyType(name) == null) {
223 if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) {
224 resultClass = cd.getMappingForAttributeName(name).getFields().get(0).getType();
226 } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) {
227 resultClass = cd.getMappingForAttributeName(name).getReferenceDescriptor().getJavaClass();
235 public Object getUnderlyingObject() {
236 return this.internalObject;
240 public String getChildName() {
242 String className = internalObject.getClass().getSimpleName();
243 String lowerHyphen = caseFormatStore.fromUpperCamelToLowerHyphen(className).orElseGet(() -> {
244 LOGGER.debug("Unable to find {} in the store for upper camel to lower hyphen", className);
245 return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
248 if (this.isContainer()) {
249 String upperCamel = this.getGenericTypeClass(this.getProperties().iterator().next()).getSimpleName();
251 lowerHyphen = caseFormatStore.fromUpperCamelToLowerHyphen(upperCamel).orElseGet(() -> {
252 LOGGER.debug("Unable to find {} in the store for upper camel to lower hyphen", upperCamel);
253 return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, upperCamel);
261 public String getName() {
262 String className = internalObject.getClass().getSimpleName();
263 return caseFormatStore.fromUpperCamelToLowerHyphen(className).orElseGet(() -> {
264 LOGGER.debug("Unable to find {} in the store for upper camel to lower hyphen", className);
265 return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
270 public String getObjectId() throws UnsupportedEncodingException {
272 String container = this.getMetadata(ObjectMetadata.CONTAINER);
273 if (this.isContainer()) {
274 result += "/" + this.getName();
277 if (container != null) {
278 result += "/" + container;
280 result += "/" + this.getDbName() + "/" + this.findKey();
288 protected String findKey() throws UnsupportedEncodingException {
289 Set<String> keys = null;
290 keys = this.getKeys();
291 List<String> results = new ArrayList<>();
292 for (String key : keys) {
293 String value = UriUtils.encode(this.getValue(key).toString(), "UTF-8");
297 return Joiner.on("/").join(results);
301 public String preProcessKey(String key) {
303 String[] split = key.split("/");
305 for (i = split.length - 1; i >= 0; i--) {
307 if (jaxbContext.getDynamicType(split[i]) != null) {
313 result = Joiner.on("/").join(Arrays.copyOfRange(split, 0, i));
320 public String marshal(MarshallerProperties properties) {
321 StringWriter result = new StringWriter();
323 Marshaller marshaller = jaxbContext.createMarshaller();
324 if (properties.getMediaType().equals(MediaType.APPLICATION_JSON_TYPE)) {
325 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.MEDIA_TYPE,
327 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_INCLUDE_ROOT,
328 properties.getIncludeRoot());
329 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME,
330 properties.getWrapperAsArrayName());
331 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS,
335 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, properties.getFormatted());
336 marshaller.marshal(this.internalObject, result);
337 } catch (JAXBException e) {
338 LOGGER.warn("Encountered an jaxb exception during marshalling ", LogFormatTools.getStackTop(e));
341 return result.toString();
345 public ModelType getModelType() {
346 return ModelType.MOXY;
349 private String removeXPathDescriptor(String name) {
351 return name.replaceAll("/text\\(\\)", "");
355 public String getMetadata(ObjectMetadata name) {
357 return (String) cd.getProperty(name.toString());
361 public SchemaVersion getVersion() {