Replace deprecated methods in aai-common
[aai/aai-common.git] / aai-core / src / main / java / org / onap / aai / introspection / Introspector.java
index f6609bf..87983d8 100644 (file)
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * org.onap.aai
  * ================================================================================
- * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
+ * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  * ============LICENSE_END=========================================================
- *
- * ECOMP is a trademark and service mark of AT&T Intellectual Property.
  */
+
 package org.onap.aai.introspection;
 
-import com.att.eelf.configuration.EELFLogger;
-import com.att.eelf.configuration.EELFManager;
 import com.google.common.base.CaseFormat;
-import org.apache.commons.lang.ClassUtils;
+
+import java.io.UnsupportedEncodingException;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import org.apache.commons.lang3.ClassUtils;
 import org.eclipse.persistence.exceptions.DynamicException;
+import org.onap.aai.config.SpringContextAware;
 import org.onap.aai.introspection.exceptions.AAIUnknownObjectException;
 import org.onap.aai.logging.ErrorLogHelper;
+import org.onap.aai.logging.LogFormatTools;
+import org.onap.aai.nodes.CaseFormatStore;
+import org.onap.aai.nodes.NodeIngestor;
 import org.onap.aai.restcore.MediaType;
 import org.onap.aai.schema.enums.ObjectMetadata;
 import org.onap.aai.schema.enums.PropertyMetadata;
+import org.onap.aai.setup.SchemaVersion;
 import org.onap.aai.workarounds.NamingExceptions;
-
-import java.io.UnsupportedEncodingException;
-import java.lang.reflect.InvocationTargetException;
-import java.util.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 public abstract class Introspector implements Cloneable {
 
-       private static final EELFLogger LOGGER = EELFManager.getInstance().getLogger(Introspector.class);
-
-       protected String className;
-       protected String uriChain = "";
-       protected Loader loader;
-       protected final NamingExceptions namingException = NamingExceptions.getInstance();
-       private Set<String> uniqueProperties = null;
-       private Set<String> indexedProperties = null;
-       private Set<String> allKeys = null;
-       protected Introspector(Object obj) {
-       }
-
-       public abstract boolean hasProperty(String name);
-
-       protected String convertPropertyName (String name) {
-               return CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, name);
-       }
-       
-       protected abstract Object get(String name);
-       protected abstract void set(String name, Object value);
-       /**
-        * 
-        * @param name the property name you'd like to retrieve the value for
-        * @return the value of the property
-        */
-       public <T> T getValue(String name) {
-               String convertedName = convertPropertyName(name);
-               Object result = null;
-               
-               if (this.hasProperty(name)) {
-                       result = this.get(convertedName);
-               } else {
-                       /* property not found - slightly ambiguous */
-                       return null;
-               }
-               
-               Class<?> clazz = this.getClass(name);
-               if (this.isListType(name) && result == null) {
-                       try {
-                               this.set(convertedName, clazz.newInstance());
-                               result = this.get(convertedName);
-                       } catch (DynamicException | InstantiationException | IllegalAccessException e) {
-                               
-                       }
-               }
-
-               return (T)result;
-       }
-       
-       public Introspector getWrappedValue(String name) {
-               String convertedName = convertPropertyName(name);
-               Object value = null;
-               
-               if (this.hasProperty(name)) {
-                       value = this.get(convertedName);
-               } else {
-                       /* property not found - slightly ambiguous */
-                       return null;
-               }
-               
-               Class<?> clazz = this.getClass(name);
-               if (this.isListType(name) && value == null) {
-                       try {
-                               this.set(convertedName, clazz.newInstance());
-                               value = this.get(convertedName);
-                       } catch (DynamicException | InstantiationException | IllegalAccessException e) {
-                               
-                       }
-               }
-               if (value != null) {
-                       return IntrospectorFactory.newInstance(this.getModelType(), value);
-               } else {
-                       //no value
-                       return null;
-               }
-               
-       }
-       
-       public List<Introspector> getWrappedListValue(String name) {
-               String convertedName = convertPropertyName(name);
-               Object value = null;
-               List<Introspector> resultList = new ArrayList<>();
-               if (this.hasProperty(name)) {
-                       value = this.get(convertedName);
-               } else {
-                       /* property not found - slightly ambiguous */
-                       return null;
-               }
-               boolean isListType = this.isListType(name);
-               if (!this.isListType(name)) {
-                       return null;
-               }
-               Class<?> clazz = this.getClass(name);
-               if (isListType && value == null) {
-                       try {
-                               this.set(convertedName, clazz.newInstance());
-                               value = this.get(convertedName);
-                       } catch (DynamicException | InstantiationException | IllegalAccessException e) {
-                               
-                       }
-               }
-               
-               List<Object> valueList = (List<Object>)value;
-               
-               for (Object item : valueList) {
-                       resultList.add(IntrospectorFactory.newInstance(this.getModelType(), item));
-               }
-               
-               return resultList;
-               
-       }
-       
-       public Object castValueAccordingToSchema(String name, Object obj) {
-               Object result = obj;
-               Class<?> nameClass = this.getClass(name);
-               if (nameClass == null) {
-                       throw new IllegalArgumentException("property: " + name + " does not exist on " + this.getDbName());
-               }
-               if (obj != null) {
-       
-                       try {
-                               if (!obj.getClass().getName().equals(nameClass.getName())) {
-                                       if (nameClass.isPrimitive()) {
-                                               nameClass = ClassUtils.primitiveToWrapper(nameClass);   
-                                               result = nameClass.getConstructor(String.class).newInstance(obj.toString());
-                                       }
-                                       if (obj instanceof String) {
-                                               result = nameClass.getConstructor(String.class).newInstance(obj);
-                                       } else if (!this.isListType(name) && !this.isComplexType(name)){
-                                               //box = obj.toString();
-                                               result = nameClass.getConstructor(String.class).newInstance(obj.toString());
-                                       }
-                               }
-                       } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
-                                       | InvocationTargetException | NoSuchMethodException | SecurityException e) {
-                               ErrorLogHelper.logError("AAI_4017", e.getMessage());
-                       }
-               }
-               return result;
-       }
-       
-       public List<Object> castValueAccordingToSchema(String name, List<?> objs) {
-               List<Object> result = new ArrayList<>();
-               
-               for (Object item : objs) {
-                       result.add(this.castValueAccordingToSchema(name, item));
-               }
-               
-               return result;
-               
-       }
-       /**
-        * 
-        * @param name the property name you'd like to set the value of
-        * @param obj the value to be set
-        * @return
-        */
-       public void setValue(String name, Object obj) throws IllegalArgumentException {
-               Object box = this.castValueAccordingToSchema(name, obj);
-               
-               name = convertPropertyName(name);
-               this.set(name, box);
-       }
-       /**
-        * 
-        * @return a list of all the properties available on the object
-        */
-       public abstract Set<String> getProperties();
-       
-       public Set<String> getProperties(PropertyPredicate<Introspector, String> p) {
-               final Set<String> temp = new LinkedHashSet<>();
-               this.getProperties().stream().filter(item -> {
-                       return p.test(this, item);
-               }).forEach(item -> {
-                       temp.add(item);
-               });
-               final Set<String> result = Collections.unmodifiableSet(temp);
-               
-               return result;
-               
-       }
-       /**
-        * 
-        * @return a list of the required properties on the object
-        */
-       public abstract Set<String> getRequiredProperties();
-       /**
-        * 
-        * @return a list of the properties that can be used to query the object in the db
-        */
-       public abstract Set<String> getKeys();
-       /**
-        * 
-        * @return a list of the all key properties for this object
-        */
-       public Set<String> getAllKeys() {
-               Set<String> result = null;
-               if (this.allKeys == null) {
-                       Set<String> keys = this.getKeys();
-                       result = new LinkedHashSet<>();
-                       result.addAll(keys);
-                       String altKeys = this.getMetadata(ObjectMetadata.ALTERNATE_KEYS_1);
-                       if (altKeys != null) {
-                               String[] altKeysArray = altKeys.split(",");
-                               for (String altKey : altKeysArray) {
-                                       result.add(altKey);
-                               }
-                       }
-                       result = Collections.unmodifiableSet(result);
-                       this.allKeys = result;
-               }
-               result = this.allKeys;
-               return result;
-       }
-
-       public Set<String> getIndexedProperties() {
-               Set<String> result = null;
-
-               if (this.indexedProperties == null) {
-                       result = new LinkedHashSet<>();
-                       Set<String> keys = this.getKeys();
-                       result.addAll(keys);
-                       String altKeys = this.getMetadata(ObjectMetadata.INDEXED_PROPS);
-                       if (altKeys != null) {
-                               String[] altKeysArray = altKeys.split(",");
-                               for (String altKey : altKeysArray) {
-                                       result.add(altKey);
-                               }
-                       }
-                       this.indexedProperties = Collections.unmodifiableSet(result);
-               }
-               result = this.indexedProperties;
-               return result;
-       }
-       
-       public Set<String> getUniqueProperties() {
-               Set<String> result = null;
-               if (this.uniqueProperties == null) {
-                       String altKeys = this.getMetadata(ObjectMetadata.UNIQUE_PROPS);
-                       result = new LinkedHashSet<>();
-                       if (altKeys != null) {
-                               String[] altKeysArray = altKeys.split(",");
-                               for (String altKey : altKeysArray) {
-                                       result.add(altKey);
-                               }
-                       }
-                       this.uniqueProperties = Collections.unmodifiableSet(result);
-
-               }
-               result = this.uniqueProperties;
-               return result;
-       }
-       
-       public Set<String> getDependentOn() {
-               String dependentOn = this.getMetadata(ObjectMetadata.DEPENDENT_ON);
-               if (dependentOn == null) {
-                       return  new LinkedHashSet<>();
-               }
-               return new LinkedHashSet<>(Arrays.asList(dependentOn.split(",")));
-       }
-       /**
-        * 
-        * @param name
-        * @return the string name of the java class of the named property
-        */
-       public String getType(String name) {
-               Class<?> resultClass = this.getClass(name);
-               String result = "";
-               
-               if (resultClass != null) {
-                       result = resultClass.getName();
-                       if (result.equals("java.util.ArrayList")) {
-                               result = "java.util.List";
-                       }
-               }
-               
-               return result;
-       }
-       /**
-        * This will returned the generic parameterized type of the underlying
-        * object if it exists
-        * @param name
-        * @return the generic type of the java class of the underlying object
-        */
-       public String getGenericType(String name) {
-               Class<?> resultClass = this.getGenericTypeClass(name);
-               String result = "";
-               
-               if (resultClass != null) {
-                       result = resultClass.getName();
-               }
-               
-               return result;
-       }
-       /**
-        * 
-        * @return the string name of the java class of the underlying object
-        */
-       public abstract String getJavaClassName();
-       
-       /**
-        * 
-        * @param name the property name
-        * @return the Class object
-        */
-       public abstract Class<?> getClass(String name);
-       
-       public abstract Class<?> getGenericTypeClass(String name);
-
-       /**
-        * 
-        * @param name the property name
-        * @return a new instance of the underlying type of this property
-        * @throws AAIUnknownObjectException 
-        */
-       public Object newInstanceOfProperty(String name) throws AAIUnknownObjectException {
-               String type = this.getType(name);
-               return loader.objectFromName(type);
-       }
-
-       public Object newInstanceOfNestedProperty(String name) throws AAIUnknownObjectException {
-               String type = this.getGenericType(name);
-               return loader.objectFromName(type);
-       }
-       
-       
-       public Introspector newIntrospectorInstanceOfProperty(String name) throws AAIUnknownObjectException {
-       
-               Introspector result = IntrospectorFactory.newInstance(this.getModelType(), this.newInstanceOfProperty(name));
-               
-               return result;
-               
-       }
-       
-       public Introspector newIntrospectorInstanceOfNestedProperty(String name) throws AAIUnknownObjectException {
-       
-               Introspector result = IntrospectorFactory.newInstance(this.getModelType(), this.newInstanceOfNestedProperty(name));
-               
-               return result;
-               
-       }
-       /**
-        * Is this type not a Java String or primitive
-        * @param name
-        * @return
-        */
-       public boolean isComplexType(String name) {
-               String result = this.getType(name);
-               
-               if (result.contains("aai") || result.equals("java.lang.Object")) {
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-       
-       public boolean isComplexGenericType(String name) {
-               String result = this.getGenericType(name);
-               
-               if (result.contains("aai")) {
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-       
-       public boolean isSimpleType(String name) {
-               return !(this.isComplexType(name) || this.isListType(name));
-       }
-       
-       public boolean isSimpleGenericType(String name) {
-               return !this.isComplexGenericType(name);
-       }
-
-       public boolean isListType(String name) {
-               String result = this.getType(name);
-               
-               if (result.contains("java.util.List")) {
-                       return true;
-               } else {
-                       return false;
-               }
-       }
-       
-       public boolean isContainer() {
-               Set<String> props = this.getProperties();
-               boolean result = false;
-               if (props.size() == 1 && this.isListType(props.iterator().next())) {
-                       result = true;
-               }
-               
-               return result;
-       }
-       
-       public abstract String getChildName();
-       public String getChildDBName() {
-               String result = this.getChildName();
-               
-               result = namingException.getDBName(result);
-               return result;
-       }
-       public abstract String getName();
-
-       public String getDbName() {
-               String lowerHyphen = this.getName();
-
-               lowerHyphen = namingException.getDBName(lowerHyphen);
-               
-               return lowerHyphen;
-       }
-               
-       public abstract ModelType getModelType();
-
-       public boolean hasChild(Introspector child) {
-               boolean result = false;
-               //check all inheriting types for this child
-               if ("true".equals(this.getMetadata(ObjectMetadata.ABSTRACT))) {
-                       String[] inheritors = this.getMetadata(ObjectMetadata.INHERITORS).split(",");
-                       for (String inheritor : inheritors) {
-                               try {
-                                       Introspector temp = this.loader.introspectorFromName(inheritor);
-                                       result = temp.hasProperty(child.getName());
-                                       if (result) {
-                                               break;
-                                       }
-                               } catch (AAIUnknownObjectException e) {
-                                       LOGGER.warn("Skipping inheritor " + inheritor + " (Unknown Object)", e);
-                               }
-                       }
-               } else {
-                       result = this.hasProperty(child.getName());
-               }
-               return result;
-       }
-       
-       public void setURIChain(String uri) {
-               this.uriChain = uri;
-       }
-       public abstract String getObjectId() throws UnsupportedEncodingException;
-
-       public String getURI() throws UnsupportedEncodingException {
-               //String result = this.uriChain;
-               String result = "";
-               String namespace = this.getMetadata(ObjectMetadata.NAMESPACE);
-               String container = this.getMetadata(ObjectMetadata.CONTAINER);
-               if (this.isContainer()) {
-                        result += "/" + this.getName();
-               } else {
-                       
-                       if (container != null) {
-                               result += "/" + container;
-                       }
-                       result += "/" + this.getDbName() + "/" + this.findKey();
-                       
-                       if (namespace != null && !namespace.equals("")) {
-                               result = "/" + namespace + result;
-                       }
-               }
-               
-
-               return result;
-       }
-       
-       public String getGenericURI() {
-               String result = "";
-               if (this.isContainer()) {
-                        result += "/" + this.getName();
-               } else {
-                       result += "/" + this.getDbName();
-                       for (String key : this.getKeys()) {
-                               result += "/{" + this.getDbName() + "-" + key + "}";
-                       }
-               }
-               
-               return result;
-       }
-       
-       public String getFullGenericURI() {
-               String result = "";
-               String namespace = this.getMetadata(ObjectMetadata.NAMESPACE);
-               String container = this.getMetadata(ObjectMetadata.CONTAINER);
-               if (this.isContainer()) {
-                        result += "/" + this.getName();
-               } else {
-
-
-                       if (container != null) {
-                               result += "/" + container;
-                       }
-                       result += "/" + this.getDbName();
-
-                       for (String key : this.getKeys()) {
-                               result += "/{" + this.getDbName() + "-" + key + "}";
-                       }
-                       if (namespace != null && !namespace.equals("")) {
-                               result = "/" + namespace + result;
-                       }
-                       
-               }
-               
-               return result;
-       }
-
-       public abstract String preProcessKey(String key);
-       
-       protected abstract String findKey() throws UnsupportedEncodingException;
-       
-       public abstract String marshal(MarshallerProperties properties);
-       
-       public abstract Object clone();
-
-       public abstract Object getUnderlyingObject();
-       
-       public String marshal(boolean formatted) {
-               MarshallerProperties properties =
-                               new MarshallerProperties.Builder(MediaType.APPLICATION_JSON_TYPE).formatted(formatted).build();
-               
-               return marshal(properties);
-       }
-       public String makeSingular(String word) {
-               
-               String result = word;
-               result = result.replaceAll("(?:([ho])es|s)$", "");
-               
-               if (result.equals("ClassesOfService")) {
-                       result = "ClassOfService";
-               } else if (result.equals("CvlanTag")) {
-                       result = "CvlanTagEntry";
-               } else if (result.equals("Metadata")) {
-                       result = "Metadatum";
-               }
-               return result;
-       }
-       
-       protected String makePlural(String word) {
-               String result = word;
-               
-               if (result.equals("cvlan-tag-entry")) {
-                       return "cvlan-tags";
-               } else if (result.equals("class-of-service")) {
-                       return "classes-of-service";
-               } else if (result.equals("metadatum")) {
-                       return "metadata";
-               }
-               result = result.replaceAll("([a-z])$", "$1s");
-               result = result.replaceAll("([hox])s$", "$1es");
-               /*
-               if (result.equals("classes-of-services")) {
-                       result = "classes-of-service";
-               }*/
-               
-               return result;
-       }
-
-       public abstract String getMetadata(ObjectMetadata metadataName);
-       public abstract Map<PropertyMetadata, String> getPropertyMetadata(String propName);
-       public Optional<String> getPropertyMetadata(String propName, PropertyMetadata metadataName) {
-               final String resultValue = this.getPropertyMetadata(propName).getOrDefault(metadataName, "");
-               Optional<String> result = Optional.empty();
-               
-               if (!resultValue.isEmpty()) {
-                       result = Optional.of(resultValue);
-               }
-               return result;
-               
-       }
-
-       public abstract Version getVersion();
-       public Loader getLoader() {
-               return this.loader;
-       }
-       
-       public boolean isTopLevel() {
-               
-               return this.getMetadata(ObjectMetadata.NAMESPACE) != null;
-       }
+    private static final Logger LOGGER = LoggerFactory.getLogger(Introspector.class);
+
+    protected String className;
+    protected String uriChain = "";
+    protected Loader loader;
+    protected final NamingExceptions namingException = NamingExceptions.getInstance();
+    private Set<String> uniqueProperties = null;
+    private Set<String> indexedProperties = null;
+    private Set<String> allKeys = null;
+    private Set<String> dslStartNodeProperties = null;
+
+    protected CaseFormatStore caseFormatStore = null;
+    protected NodeIngestor nodeIngestor;
+
+    protected Introspector(Object obj) {
+        this.nodeIngestor = SpringContextAware.getBean(NodeIngestor.class);
+        this.caseFormatStore = nodeIngestor.getCaseFormatStore();
+    }
+
+    public abstract boolean hasProperty(String name);
+
+    protected String convertPropertyName(String name) {
+        return caseFormatStore.fromLowerHyphenToLowerCamel(name).orElseGet(() -> {
+            LOGGER.debug("Unable to find {} in the store from lower hyphen to lower camel", name);
+            return CaseFormat.LOWER_HYPHEN.to(CaseFormat.LOWER_CAMEL, name);
+        });
+    }
+
+    protected abstract Object get(String name);
+
+    protected abstract void set(String name, Object value);
+
+    /**
+     *
+     * @param name the property name you'd like to retrieve the value for
+     * @return the value of the property
+     */
+    public <T> T getValue(String name) {
+        String convertedName = convertPropertyName(name);
+        Object result = null;
+
+        if (this.hasProperty(name)) {
+            result = this.get(convertedName);
+        } else {
+            /* property not found - slightly ambiguous */
+            return null;
+        }
+
+        Class<?> clazz = this.getClass(name);
+        if (this.isListType(name) && result == null) {
+            try {
+                this.set(convertedName, clazz.getDeclaredConstructor().newInstance());
+                result = this.get(convertedName);
+            } catch (DynamicException | InstantiationException | IllegalAccessException | IllegalArgumentException
+                    | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+                LOGGER.warn(e.getMessage(), e);
+            }
+        }
+
+        return (T) result;
+    }
+
+    public Introspector getWrappedValue(String name) {
+        String convertedName = convertPropertyName(name);
+        Object value = null;
+
+        if (this.hasProperty(name)) {
+            value = this.get(convertedName);
+        } else {
+            /* property not found - slightly ambiguous */
+            return null;
+        }
+
+        Class<?> clazz = this.getClass(name);
+        if (this.isListType(name) && value == null) {
+            try {
+                this.set(convertedName, clazz.getDeclaredConstructor().newInstance());
+                value = this.get(convertedName);
+            } catch (DynamicException | InstantiationException | IllegalAccessException | IllegalArgumentException
+                    | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+                LOGGER.warn(e.getMessage(), e);
+            }
+        }
+        if (value != null) {
+            return IntrospectorFactory.newInstance(this.getModelType(), value);
+        } else {
+            // no value
+            return null;
+        }
+
+    }
+
+    public List<Introspector> getWrappedListValue(String name) {
+        String convertedName = convertPropertyName(name);
+        Object value = null;
+        List<Introspector> resultList = new ArrayList<>();
+        if (this.hasProperty(name)) {
+            value = this.get(convertedName);
+        } else {
+            /* property not found - slightly ambiguous */
+            return null;
+        }
+        boolean isListType = this.isListType(name);
+        if (!this.isListType(name)) {
+            return null;
+        }
+        Class<?> clazz = this.getClass(name);
+        if (isListType && value == null) {
+            try {
+                this.set(convertedName, clazz.getDeclaredConstructor().newInstance());
+                value = this.get(convertedName);
+            } catch (DynamicException | InstantiationException | IllegalAccessException | IllegalArgumentException
+                    | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+                LOGGER.warn(e.getMessage(), e);
+            }
+        }
+
+        List<Object> valueList = (List<Object>) value;
+
+        for (Object item : valueList) {
+            resultList.add(IntrospectorFactory.newInstance(this.getModelType(), item));
+        }
+
+        return resultList;
+
+    }
+
+    public Object castValueAccordingToSchema(String name, Object obj) {
+        Object result = obj;
+        Class<?> nameClass = this.getClass(name);
+        if (nameClass == null) {
+            throw new IllegalArgumentException("property: " + name + " does not exist on " + this.getDbName());
+        }
+        if (obj != null) {
+
+            try {
+                if (!(obj.getClass().getCanonicalName().equals(nameClass.getCanonicalName()))) {
+                    if (nameClass.isPrimitive()) {
+                        nameClass = ClassUtils.primitiveToWrapper(nameClass);
+                        result = nameClass.getConstructor(String.class).newInstance(obj.toString());
+                    }
+                    if (obj instanceof String) {
+                        result = nameClass.getConstructor(String.class).newInstance(obj);
+                    } else if (!this.isListType(name) && !this.isComplexType(name)) {
+                        // box = obj.toString();
+                        result = nameClass.getConstructor(String.class).newInstance(obj.toString());
+                    }
+                }
+            } catch (InstantiationException | IllegalAccessException | IllegalArgumentException
+                    | InvocationTargetException | NoSuchMethodException | SecurityException e) {
+                ErrorLogHelper.logError("AAI_4017", e.getMessage());
+            }
+        }
+        return result;
+    }
+
+    public List<Object> castValueAccordingToSchema(String name, List<?> objs) {
+        List<Object> result = new ArrayList<>();
+
+        for (Object item : objs) {
+            result.add(this.castValueAccordingToSchema(name, item));
+        }
+
+        return result;
+
+    }
+
+    /**
+     *
+     * @param name the property name you'd like to set the value of
+     * @param obj the value to be set
+     * @return
+     */
+    public void setValue(String name, Object obj) {
+        Object box = this.castValueAccordingToSchema(name, obj);
+
+        name = convertPropertyName(name);
+        this.set(name, box);
+    }
+
+    /**
+     *
+     * @return a list of all the properties available on the object
+     */
+    public abstract Set<String> getProperties();
+
+    public Set<String> getProperties(PropertyPredicate<Introspector, String> p) {
+        final Set<String> temp = new LinkedHashSet<>();
+        this.getProperties().stream().filter(item -> p.test(this, item)).forEach(temp::add);
+        return Collections.unmodifiableSet(temp);
+    }
+
+    public Set<String> getSimpleProperties(PropertyPredicate<Introspector, String> p) {
+        return this.getProperties().stream().filter(item -> p.test(this, item)).filter(this::isSimpleType)
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     *
+     * @return a list of the required properties on the object
+     */
+    public abstract Set<String> getRequiredProperties();
+
+    /**
+     *
+     * @return a list of the properties that can be used to query the object in the db
+     */
+    public abstract Set<String> getKeys();
+
+    /**
+     *
+     * @return a list of the all key properties for this object
+     */
+    public Set<String> getAllKeys() {
+        Set<String> result = null;
+        if (this.allKeys == null) {
+            Set<String> keys = this.getKeys();
+            result = new LinkedHashSet<>();
+            result.addAll(keys);
+            String altKeys = this.getMetadata(ObjectMetadata.ALTERNATE_KEYS_1);
+            if (altKeys != null) {
+                String[] altKeysArray = altKeys.split(",");
+                for (String altKey : altKeysArray) {
+                    result.add(altKey);
+                }
+            }
+            result = Collections.unmodifiableSet(result);
+            this.allKeys = result;
+        }
+        result = this.allKeys;
+        return result;
+    }
+
+    public Set<String> getIndexedProperties() {
+        Set<String> result = null;
+
+        if (this.indexedProperties == null) {
+            result = new LinkedHashSet<>();
+            Set<String> keys = this.getKeys();
+            result.addAll(keys);
+            String altKeys = this.getMetadata(ObjectMetadata.INDEXED_PROPS);
+            if (altKeys != null) {
+                String[] altKeysArray = altKeys.split(",");
+                for (String altKey : altKeysArray) {
+                    result.add(altKey);
+                }
+            }
+            this.indexedProperties = Collections.unmodifiableSet(result);
+        }
+        result = this.indexedProperties;
+        return result;
+    }
+
+    public Set<String> getDslStartNodeProperties() {
+        Set<String> result = null;
+
+        if (this.dslStartNodeProperties == null) {
+            /*
+             * The dslStartNodeProperties will have keys by default
+             * If dslStartNodeProps exist in the oxm use it
+             * if not use the indexedProps
+             */
+            result = new LinkedHashSet<>(this.getKeys());
+
+            String dslKeys = this.getMetadata(ObjectMetadata.DSL_START_NODE_PROPS);
+            String indexedKeys = this.getMetadata(ObjectMetadata.INDEXED_PROPS);
+            if (dslKeys != null) {
+                Arrays.stream(dslKeys.split(",")).forEach(result::add);
+            } else if (indexedKeys != null) {
+                Arrays.stream(indexedKeys.split(",")).forEach(result::add);
+            }
+            this.dslStartNodeProperties = Collections.unmodifiableSet(result);
+        }
+        result = this.dslStartNodeProperties;
+        return result;
+    }
+
+    public Set<String> getUniqueProperties() {
+        Set<String> result = null;
+        if (this.uniqueProperties == null) {
+            String altKeys = this.getMetadata(ObjectMetadata.UNIQUE_PROPS);
+            result = new LinkedHashSet<>();
+            if (altKeys != null) {
+                String[] altKeysArray = altKeys.split(",");
+                for (String altKey : altKeysArray) {
+                    result.add(altKey);
+                }
+            }
+            this.uniqueProperties = Collections.unmodifiableSet(result);
+
+        }
+        result = this.uniqueProperties;
+        return result;
+    }
+
+    public Set<String> getDependentOn() {
+        String dependentOn = this.getMetadata(ObjectMetadata.DEPENDENT_ON);
+        if (dependentOn == null) {
+            return new LinkedHashSet<>();
+        }
+        return new LinkedHashSet<>(Arrays.asList(dependentOn.split(",")));
+    }
+
+    /**
+     *
+     * @param name
+     * @return the string name of the java class of the named property
+     */
+    public String getType(String name) {
+        Class<?> resultClass = this.getClass(name);
+        String result = "";
+
+        if (resultClass != null) {
+            result = resultClass.getName();
+            if (result.equals("java.util.ArrayList")) {
+                result = "java.util.List";
+            }
+        }
+
+        return result;
+    }
+
+    /**
+     * This will returned the generic parameterized type of the underlying
+     * object if it exists
+     *
+     * @param name
+     * @return the generic type of the java class of the underlying object
+     */
+    public String getGenericType(String name) {
+        Class<?> resultClass = this.getGenericTypeClass(name);
+        String result = "";
+
+        if (resultClass != null) {
+            result = resultClass.getName();
+        }
+
+        return result;
+    }
+
+    /**
+     *
+     * @return the string name of the java class of the underlying object
+     */
+    public abstract String getJavaClassName();
+
+    /**
+     *
+     * @param name the property name
+     * @return the Class object
+     */
+    public abstract Class<?> getClass(String name);
+
+    public abstract Class<?> getGenericTypeClass(String name);
+
+    /**
+     *
+     * @param name the property name
+     * @return a new instance of the underlying type of this property
+     * @throws AAIUnknownObjectException
+     */
+    public Object newInstanceOfProperty(String name) throws AAIUnknownObjectException {
+        String type = this.getType(name);
+        return loader.objectFromName(type);
+    }
+
+    public Object newInstanceOfNestedProperty(String name) throws AAIUnknownObjectException {
+        String type = this.getGenericType(name);
+        return loader.objectFromName(type);
+    }
+
+    public Introspector newIntrospectorInstanceOfProperty(String name) throws AAIUnknownObjectException {
+
+        Introspector result = IntrospectorFactory.newInstance(this.getModelType(), this.newInstanceOfProperty(name));
+
+        return result;
+
+    }
+
+    public Introspector newIntrospectorInstanceOfNestedProperty(String name) throws AAIUnknownObjectException {
+
+        Introspector result =
+                IntrospectorFactory.newInstance(this.getModelType(), this.newInstanceOfNestedProperty(name));
+
+        return result;
+
+    }
+
+    /**
+     * Is this type not a Java String or primitive
+     *
+     * @param name
+     * @return
+     */
+    public boolean isComplexType(String name) {
+        String result = this.getType(name);
+
+        if (result.contains("aai") || result.equals("java.lang.Object")) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public boolean isComplexGenericType(String name) {
+        String result = this.getGenericType(name);
+
+        if (result.contains("aai")) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public boolean isSimpleType(String name) {
+        return !(this.isComplexType(name) || this.isListType(name));
+    }
+
+    public boolean isSimpleGenericType(String name) {
+        return !this.isComplexGenericType(name);
+    }
+
+    public boolean isListType(String name) {
+        String result = this.getType(name);
+
+        if (result.contains("java.util.List")) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    public boolean isContainer() {
+        Set<String> props = this.getProperties();
+        boolean result = false;
+        if (props.size() == 1 && this.isListType(props.iterator().next())) {
+            result = true;
+        }
+
+        return result;
+    }
+
+    public abstract String getChildName();
+
+    public String getChildDBName() {
+        String result = this.getChildName();
+
+        result = namingException.getDBName(result);
+        return result;
+    }
+
+    public abstract String getName();
+
+    public String getDbName() {
+        String lowerHyphen = this.getName();
+
+        lowerHyphen = namingException.getDBName(lowerHyphen);
+
+        return lowerHyphen;
+    }
+
+    public abstract ModelType getModelType();
+
+    public boolean hasChild(Introspector child) {
+        boolean result = false;
+        // check all inheriting types for this child
+        if ("true".equals(this.getMetadata(ObjectMetadata.ABSTRACT))) {
+            String[] inheritors = this.getMetadata(ObjectMetadata.INHERITORS).split(",");
+            for (String inheritor : inheritors) {
+                try {
+                    Introspector temp = this.loader.introspectorFromName(inheritor);
+                    result = temp.hasProperty(child.getName());
+                    if (result) {
+                        break;
+                    }
+                } catch (AAIUnknownObjectException e) {
+                    LOGGER.warn(
+                            "Skipping inheritor " + inheritor + " (Unknown Object) " + LogFormatTools.getStackTop(e));
+                }
+            }
+        } else {
+            result = this.hasProperty(child.getName());
+        }
+        return result;
+    }
+
+    public void setURIChain(String uri) {
+        this.uriChain = uri;
+    }
+
+    public abstract String getObjectId() throws UnsupportedEncodingException;
+
+    public String getURI() throws UnsupportedEncodingException {
+        // String result = this.uriChain;
+        String result = "";
+        String namespace = this.getMetadata(ObjectMetadata.NAMESPACE);
+        String container = this.getMetadata(ObjectMetadata.CONTAINER);
+        if (this.isContainer()) {
+            result += "/" + this.getName();
+        } else {
+
+            if (container != null) {
+                result += "/" + container;
+            }
+            result += "/" + this.getDbName() + "/" + this.findKey();
+
+            if (namespace != null && !namespace.equals("")) {
+                result = "/" + namespace + result;
+            }
+        }
+
+        return result;
+    }
+
+    public String getGenericURI() {
+        String result = "";
+        if (this.isContainer()) {
+            result += "/" + this.getName();
+        } else {
+            result += "/" + this.getDbName();
+            for (String key : this.getKeys()) {
+                result += "/{" + this.getDbName() + "-" + key + "}";
+            }
+        }
+
+        return result;
+    }
+
+    public String getFullGenericURI() {
+        String result = "";
+        String namespace = this.getMetadata(ObjectMetadata.NAMESPACE);
+        String container = this.getMetadata(ObjectMetadata.CONTAINER);
+        if (this.isContainer()) {
+            result += "/" + this.getName();
+        } else {
+
+            if (container != null) {
+                result += "/" + container;
+            }
+            result += "/" + this.getDbName();
+
+            for (String key : this.getKeys()) {
+                result += "/{" + this.getDbName() + "-" + key + "}";
+            }
+            if (namespace != null && !namespace.equals("")) {
+                result = "/" + namespace + result;
+            }
+
+        }
+
+        return result;
+    }
+
+    public abstract String preProcessKey(String key);
+
+    protected abstract String findKey() throws UnsupportedEncodingException;
+
+    public abstract String marshal(MarshallerProperties properties);
+
+    public abstract Object getUnderlyingObject();
+
+    public String marshal(boolean formatted) {
+        MarshallerProperties properties =
+                new MarshallerProperties.Builder(MediaType.APPLICATION_JSON_TYPE).formatted(formatted).build();
+
+        return marshal(properties);
+    }
+
+    public String makeSingular(String word) {
+
+        String result = word;
+        result = result.replaceAll("(?:([ho])es|s)$", "");
+
+        if (result.equals("ClassesOfService")) {
+            result = "ClassOfService";
+        } else if (result.equals("CvlanTag")) {
+            result = "CvlanTagEntry";
+        } else if (result.equals("Metadata")) {
+            result = "Metadatum";
+        }
+        return result;
+    }
+
+    protected String makePlural(String word) {
+        String result = word;
+
+        if (result.equals("cvlan-tag-entry")) {
+            return "cvlan-tags";
+        } else if (result.equals("class-of-service")) {
+            return "classes-of-service";
+        } else if (result.equals("metadatum")) {
+            return "metadata";
+        }
+        result = result.replaceAll("([a-z])$", "$1s");
+        result = result.replaceAll("([hox])s$", "$1es");
+        /*
+         * if (result.equals("classes-of-services")) {
+         * result = "classes-of-service";
+         * }
+         */
+
+        return result;
+    }
+
+    public abstract String getMetadata(ObjectMetadata metadataName);
+
+    public abstract Map<PropertyMetadata, String> getPropertyMetadata(String propName);
+
+    public Optional<String> getPropertyMetadata(String propName, PropertyMetadata metadataName) {
+        final String resultValue = this.getPropertyMetadata(propName).getOrDefault(metadataName, "");
+        Optional<String> result = Optional.empty();
+
+        if (!resultValue.isEmpty()) {
+            result = Optional.of(resultValue);
+        }
+        return result;
+
+    }
+
+    public abstract SchemaVersion getVersion();
+
+    public Loader getLoader() {
+        return this.loader;
+    }
+
+    public boolean isTopLevel() {
+
+        return this.getMetadata(ObjectMetadata.NAMESPACE) != null;
+    }
+
 }