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=========================================================
20 package org.onap.aai.introspection;
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 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.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.onap.aai.config.SpringContextAware;
36 import org.onap.aai.logging.LogFormatTools;
37 import org.onap.aai.nodes.CaseFormatStore;
38 import org.onap.aai.nodes.NodeIngestor;
39 import org.onap.aai.restcore.MediaType;
40 import org.onap.aai.schema.enums.ObjectMetadata;
41 import org.onap.aai.schema.enums.PropertyMetadata;
42 import org.onap.aai.setup.SchemaVersion;
43 import org.springframework.web.util.UriUtils;
45 import javax.xml.bind.JAXBException;
46 import javax.xml.bind.Marshaller;
47 import java.io.StringWriter;
48 import java.io.UnsupportedEncodingException;
50 import java.util.Map.Entry;
52 public class MoxyStrategy extends Introspector {
54 private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(MoxyStrategy.class);
55 private DynamicEntity internalObject = null;
56 private DynamicType internalType = null;
57 private DynamicJAXBContext jaxbContext = null;
58 private ClassDescriptor cd = null;
59 private SchemaVersion version = null;
60 private Set<String> properties = null;
61 private Set<String> keys = null;
62 private Set<String> requiredProperties = null;
64 private boolean isInitialized = false;
66 protected MoxyStrategy(Object obj) {
68 /* must look up the correct jaxbcontext for this object */
69 className = MoxyStrategy.class.getSimpleName();
70 internalObject = (DynamicEntity)obj;
71 version = nodeIngestor.getVersionFromClassName(internalObject.getClass().getName());
72 super.loader = SpringContextAware.getBean(LoaderFactory.class).createLoaderForVersion(getModelType(), version);
73 jaxbContext = nodeIngestor.getContextForVersion(version);
74 String simpleName = internalObject.getClass().getName();
75 internalType = jaxbContext.getDynamicType(simpleName);
77 cd = internalType.getDescriptor();
83 Set<String> props = new LinkedHashSet<>();
84 for (String s : internalType.getPropertiesNames()) {
85 String value = caseFormatStore
86 .fromLowerCamelToLowerHyphen(s)
89 LOGGER.debug("Unable to find {} in the store from lower camel to lower hyphen", s);
90 return CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_HYPHEN, s);
96 props = Collections.unmodifiableSet(props);
97 this.properties = props;
99 Set<String> 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 && x.isRequired()) {
104 requiredProps.add(this.removeXPathDescriptor(x.getName()));
108 requiredProps = Collections.unmodifiableSet(requiredProps);
109 this.requiredProperties = requiredProps;
111 Set<String> keys = new LinkedHashSet<>();
113 for (String name : internalType.getDescriptor().getPrimaryKeyFieldNames()) {
114 keys.add(this.removeXPathDescriptor(name));
116 keys = Collections.unmodifiableSet(keys);
123 public boolean hasProperty(String name) {
124 String convertedName = convertPropertyName(name);
126 return internalType.containsProperty(convertedName);
130 public Object get(String name) {
131 return internalObject.get(name);
135 public void set(String name, Object obj){
137 internalObject.set(name, obj);
141 public Set<String> getProperties() {
147 return this.properties;
152 public Set<String> getRequiredProperties() {
158 return this.requiredProperties;
162 public Set<String> getKeys() {
172 public Map<PropertyMetadata, String> getPropertyMetadata(String prop) {
173 String propName = this.convertPropertyName(prop);
174 DatabaseMapping mapping = cd.getMappingForAttributeName(propName);
175 Map<PropertyMetadata, String> result = new HashMap<>();
176 if (mapping != null) {
177 Set<Entry> entrySet = mapping.getProperties().entrySet();
178 for (Entry<?,?> entry : entrySet) {
180 PropertyMetadata.valueOf(CaseFormat.LOWER_CAMEL.to(CaseFormat.UPPER_UNDERSCORE, (String)entry.getKey())), (String)entry.getValue());
188 public String getJavaClassName() {
189 return internalObject.getClass().getName();
195 public Class<?> getClass(String name) {
196 name = convertPropertyName(name);
197 Class<?> resultClass = null;
199 if (internalType.getPropertyType(name) == null) {
200 if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) {
201 resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
203 } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) {
204 resultClass = cd.getMappingForAttributeName(name).getContainerPolicy().getContainerClass();
206 ClassDescriptor referenceDiscriptor = cd.getMappingForAttributeName(name).getReferenceDescriptor();
207 if (referenceDiscriptor != null) {
208 resultClass = referenceDiscriptor.getJavaClass();
210 resultClass = Object.class;
214 resultClass = internalType.getPropertyType(name);
216 } catch (DynamicException e) {
217 //property doesn't exist
223 public Class<?> getGenericTypeClass(String name) {
224 name = convertPropertyName(name);
225 Class<?> resultClass = null;
226 if (internalType.getPropertyType(name) == null) {
227 if (cd.getMappingForAttributeName(name) instanceof XMLCompositeDirectCollectionMapping) {
228 resultClass = cd.getMappingForAttributeName(name).getFields().get(0).getType();
230 } else if (cd.getMappingForAttributeName(name) instanceof XMLCompositeCollectionMapping) {
231 resultClass = cd.getMappingForAttributeName(name).getReferenceDescriptor().getJavaClass();
239 public Object getUnderlyingObject() {
240 return this.internalObject;
244 public String getChildName() {
246 String className = internalObject.getClass().getSimpleName();
247 String lowerHyphen = caseFormatStore
248 .fromUpperCamelToLowerHyphen(className)
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);
256 if (this.isContainer()) {
257 String upperCamel = this.getGenericTypeClass(this.getProperties().iterator().next()).getSimpleName();
259 lowerHyphen = caseFormatStore
260 .fromUpperCamelToLowerHyphen(upperCamel)
263 LOGGER.debug("Unable to find {} in the store for upper camel to lower hyphen", upperCamel);
264 return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, upperCamel);
273 public String getName() {
274 String className = internalObject.getClass().getSimpleName();
275 return caseFormatStore
276 .fromUpperCamelToLowerHyphen(className)
278 LOGGER.debug("Unable to find {} in the store for upper camel to lower hyphen", className);
279 return CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_HYPHEN, className);
284 public String getObjectId() throws UnsupportedEncodingException {
286 String container = this.getMetadata(ObjectMetadata.CONTAINER);
287 if (this.isContainer()) {
288 result += "/" + this.getName();
291 if (container != null) {
292 result += "/" + container;
294 result += "/" + this.getDbName() + "/" + this.findKey();
302 protected String findKey() throws UnsupportedEncodingException {
303 Set<String> keys = null;
304 keys = this.getKeys();
305 List<String> results = new ArrayList<>();
306 for (String key : keys) {
307 String value = UriUtils.encode(this.getValue(key).toString(), "UTF-8");
311 return Joiner.on("/").join(results);
315 public String preProcessKey (String key) {
317 String[] split = key.split("/");
319 for (i = split.length-1; i >= 0; i--) {
321 if (jaxbContext.getDynamicType(split[i]) != null) {
327 result = Joiner.on("/").join(Arrays.copyOfRange(split, 0, i));
334 public String marshal(MarshallerProperties properties) {
335 StringWriter result = new StringWriter();
337 Marshaller marshaller = jaxbContext.createMarshaller();
338 if (properties.getMediaType().equals(MediaType.APPLICATION_JSON_TYPE)) {
339 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.MEDIA_TYPE, "application/json");
340 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_INCLUDE_ROOT, properties.getIncludeRoot());
341 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_WRAPPER_AS_ARRAY_NAME, properties.getWrapperAsArrayName());
342 marshaller.setProperty(org.eclipse.persistence.jaxb.MarshallerProperties.JSON_MARSHAL_EMPTY_COLLECTIONS, false);
345 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, properties.getFormatted());
346 marshaller.marshal(this.internalObject, result);
347 } catch (JAXBException e) {
348 LOGGER.warn("Encountered an jaxb exception during marshalling ", LogFormatTools.getStackTop(e));
351 return result.toString();
355 public ModelType getModelType() {
356 return ModelType.MOXY;
359 private String removeXPathDescriptor(String name) {
361 return name.replaceAll("/text\\(\\)", "");
365 public String getMetadata(ObjectMetadata name) {
367 return (String)cd.getProperty(name.toString());
371 public SchemaVersion getVersion() {