package com.sap.core.odata.processor.core.jpa.access.data;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import com.sap.core.odata.api.edm.EdmAssociationEnd;
import com.sap.core.odata.api.edm.EdmException;
import com.sap.core.odata.api.edm.EdmMapping;
import com.sap.core.odata.api.edm.EdmNavigationProperty;
import com.sap.core.odata.api.edm.EdmProperty;
import com.sap.core.odata.api.edm.EdmStructuralType;
import com.sap.core.odata.api.edm.EdmTypeKind;
import com.sap.core.odata.processor.api.jpa.exception.ODataJPARuntimeException;
import com.sap.core.odata.processor.api.jpa.model.JPAEdmMapping;
public final class JPAEntityParser {
/*
* List of buffers used by the Parser
*/
private static short MAX_SIZE = 10;
public static final String ACCESS_MODIFIER_GET = "get";
public static final String ACCESS_MODIFIER_SET = "set";
private HashMap<String, HashMap<String, Method>> jpaEntityAccessMap = null;
private HashMap<String, HashMap<String, String>> jpaEmbeddableKeyMap = null;
public JPAEntityParser() {
jpaEntityAccessMap = new HashMap<String, HashMap<String, Method>>(
MAX_SIZE);
jpaEmbeddableKeyMap = new HashMap<String, HashMap<String, String>>();
};
public HashMap<String, Method> getJPAEntityAccessMap(final String jpaEntityName) {
return jpaEntityAccessMap.get(jpaEntityName);
}
public HashMap<String, String> getJPAEmbeddableKeyMap(final String jpaEntityName) {
return jpaEmbeddableKeyMap.get(jpaEntityName);
}
/**
* The method returns a Hash Map of Properties and values for selected
* properties of an EdmEntity Type
*
* @param jpaEntity
* @param selectedItems
* @return a Hash Map of Properties and values for given selected properties
* of an EdmEntity Type
* @throws ODataJPARuntimeException
*/
public final HashMap<String, Object> parse2EdmPropertyValueMap(
final Object jpaEntity, final List<EdmProperty> selectPropertyList)
throws ODataJPARuntimeException {
HashMap<String, Object> edmEntity = new HashMap<String, Object>();
String methodName = null;
Method method = null;
for (int i = 0; i < selectPropertyList.size(); i++) {
String key = null;
Object propertyValue = null;
EdmProperty property = null;
property = selectPropertyList.get(i);
try {
methodName = getAccessModifierName(property.getName(),
property.getMapping(), ACCESS_MODIFIER_GET);
String[] nameParts = methodName.split("\\.");
if (nameParts.length > 1) {
Object propertyVal = new Object();
propertyVal = jpaEntity;
for (String namePart : nameParts) {
method = propertyVal.getClass().getMethod(
namePart, (Class<?>[]) null);
method.setAccessible(true);
propertyVal = method.invoke(propertyVal);
}
edmEntity.put(property.getName(), propertyVal);
} else {
method = jpaEntity.getClass().getMethod(methodName,
(Class<?>[]) null);
method.setAccessible(true);
propertyValue = method.invoke(jpaEntity);
key = property.getName();
if (property.getType().getKind()
.equals(EdmTypeKind.COMPLEX)) {
try {
propertyValue = parse2EdmPropertyValueMap(
propertyValue,
(EdmStructuralType) property.getType());
} catch (ODataJPARuntimeException e) {
throw e;
}
}
edmEntity.put(key, propertyValue);
}
} catch (EdmException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL.addContent(e
.getMessage()), e);
} catch (SecurityException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL.addContent(e
.getMessage()), e);
} catch (NoSuchMethodException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL.addContent(e
.getMessage()), e);
} catch (IllegalArgumentException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL.addContent(e
.getMessage()), e);
} catch (IllegalAccessException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL.addContent(e
.getMessage()), e);
} catch (InvocationTargetException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL.addContent(e
.getMessage()), e);
}
}
return edmEntity;
}
/**
* The method returns a Hash Map of Properties and values for an EdmEntity
* Type The method uses reflection on object jpaEntity to get the list of
* accessModifier method. Then uses the accessModifier method to extract the value from
* JPAEntity.
*
* @param jpaEntity
* @param structuralType
* @return a Hash Map of Properties and values for given EdmEntity Type
* @throws ODataJPARuntimeException
*/
public final HashMap<String, Object> parse2EdmPropertyValueMap(
final Object jpaEntity, final EdmStructuralType structuralType)
throws ODataJPARuntimeException {
if (jpaEntity == null || structuralType == null) {
return null;
}
String jpaEntityAccessKey = jpaEntity.getClass().getName();
if (!jpaEntityAccessMap.containsKey(jpaEntityAccessKey)) {
jpaEntityAccessMap.put(jpaEntityAccessKey,
getAccessModifiers(jpaEntity, structuralType, ACCESS_MODIFIER_GET));
}
HashMap<String, Object> edmEntity = new HashMap<String, Object>();
HashMap<String, Method> getters = jpaEntityAccessMap
.get(jpaEntityAccessKey);
HashMap<String, String> embeddableKeys = jpaEmbeddableKeyMap
.get(jpaEntityAccessKey);
try {
for (String key : getters.keySet()) {
EdmProperty property = (EdmProperty) structuralType
.getProperty(key);
Method method = getters.get(key);
Object propertyValue = null;
if (method != null) {
getters.get(key).setAccessible(true);
propertyValue = getters.get(key).invoke(jpaEntity);
}
if (property.getType().getKind().equals(EdmTypeKind.COMPLEX)) {
propertyValue = parse2EdmPropertyValueMap(propertyValue,
(EdmStructuralType) property.getType());
}
edmEntity.put(key, propertyValue);
}
if (embeddableKeys != null) {
for (String key : embeddableKeys.keySet()) {
String name = embeddableKeys.get(key);
String[] nameParts = name.split("\\.");
Object propertyValue = jpaEntity;
Method method = null;
for (String namePart : nameParts) {
method = propertyValue.getClass().getMethod(
namePart, (Class<?>[]) null);
method.setAccessible(true);
propertyValue = method.invoke(propertyValue);
}
edmEntity.put(key, propertyValue);
}
}
} catch (EdmException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
} catch (SecurityException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
} catch (NoSuchMethodException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
} catch (IllegalArgumentException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
} catch (IllegalAccessException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
} catch (InvocationTargetException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
}
return edmEntity;
}
// This method appends the associated entities as a java list to an expanded
// map of a source entity
public final HashMap<String, Object> parse2EdmNavigationValueMap(
final Object jpaEntity, final List<EdmNavigationProperty> navigationPropertyList)
throws ODataJPARuntimeException {
Object result = null;
String methodName = null;
HashMap<String, Object> navigationMap = new HashMap<String, Object>();
if (navigationPropertyList != null
&& navigationPropertyList.size() != 0) {
try {
for (EdmNavigationProperty navigationProperty : navigationPropertyList) {
methodName = getAccessModifierName(navigationProperty.getName(),
navigationProperty.getMapping(), ACCESS_MODIFIER_GET);
Method getterMethod = jpaEntity.getClass()
.getDeclaredMethod(methodName, (Class<?>[]) null);
getterMethod.setAccessible(true);
result = getterMethod.invoke(jpaEntity);
navigationMap.put(navigationProperty.getName(), result);
}
} catch (IllegalArgumentException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL.addContent(e
.getMessage()), e);
} catch (IllegalAccessException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL.addContent(e
.getMessage()), e);
} catch (InvocationTargetException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL.addContent(e
.getMessage()), e);
} catch (EdmException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL.addContent(e
.getMessage()), e);
} catch (SecurityException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL.addContent(e
.getMessage()), e);
} catch (NoSuchMethodException e) {
throw ODataJPARuntimeException.throwException(
ODataJPARuntimeException.GENERAL.addContent(e
.getMessage()), e);
}
}
return navigationMap;
}
public Method getAccessModifierSet(final Object jpaEntity, final String methodName) throws ODataJPARuntimeException {
Class<?> jpaType = jpaEntity.getClass();
String methodNameGet = ACCESS_MODIFIER_GET + methodName.substring(3);
Method method = null;
try {
method = jpaType.getMethod(methodNameGet, (Class<?>[]) null);
Class<?> parameterType = method.getReturnType();
method = jpaType.getMethod(methodName, new Class<?>[] { parameterType });
} catch (NoSuchMethodException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
} catch (SecurityException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
}
return method;
}
public HashMap<String, Method> getAccessModifiers(final Object jpaEntity,
final EdmStructuralType structuralType, final String accessModifier) throws ODataJPARuntimeException {
HashMap<String, Method> accessModifierMap = new HashMap<String, Method>();
HashMap<String, String> embeddableKey = new HashMap<String, String>();
try {
for (String propertyName : structuralType.getPropertyNames()) {
EdmProperty property = (EdmProperty) structuralType
.getProperty(propertyName);
String name = getAccessModifierName(property.getName(),
property.getMapping(), accessModifier);
String[] nameParts = name.split("\\.");
if (nameParts.length > 1) {
embeddableKey.put(propertyName, name);
} else {
if (accessModifier.equals(ACCESS_MODIFIER_SET)) {
JPAEdmMapping jpaEdmMapping = (JPAEdmMapping) property.getMapping();
accessModifierMap.put(
propertyName,
jpaEntity.getClass().getMethod(name, new Class<?>[] { jpaEdmMapping.getJPAType() }));
} else {
accessModifierMap.put(
propertyName,
jpaEntity.getClass().getMethod(name,
(Class<?>[]) null));
}
}
}
} catch (NoSuchMethodException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
} catch (SecurityException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
} catch (EdmException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
}
if (!embeddableKey.isEmpty()) {
jpaEmbeddableKeyMap.put(jpaEntity.getClass().getName(),
embeddableKey);
}
return accessModifierMap;
}
public static String getAccessModifierName(final String propertyName, final EdmMapping mapping, final String accessModifier)
throws ODataJPARuntimeException {
String name = null;
StringBuilder builder = new StringBuilder();
String[] nameParts = {};
if (mapping == null || mapping.getInternalName() == null) {
name = propertyName;
} else {
name = mapping.getInternalName();
}
if (name != null) {
nameParts = name.split("\\.");
}
if (nameParts.length == 1) {
if (name != null) {
char c = Character.toUpperCase(name.charAt(0));
builder.append(accessModifier).append(c).append(name.substring(1))
.toString();
}
} else if (nameParts.length > 1) {
for (int i = 0; i < nameParts.length; i++) {
name = nameParts[i];
char c = Character.toUpperCase(name.charAt(0));
if (i == 0) {
builder.append(accessModifier).append(c).append(name.substring(1));
} else {
builder.append(".").append(accessModifier).append(c)
.append(name.substring(1));
}
}
} else {
return null;
}
if (builder.length() > 0) {
return builder.toString();
} else {
return null;
}
}
public Method getAccessModifier(final Object jpaEntity, final EdmNavigationProperty navigationProperty, final String accessModifier)
throws ODataJPARuntimeException {
try {
String name = getAccessModifierName(navigationProperty.getName(),
navigationProperty.getMapping(), accessModifier);
Class<?>[] params = null;
if (accessModifier.equals(ACCESS_MODIFIER_SET)) {
EdmAssociationEnd end = navigationProperty.getRelationship().getEnd(navigationProperty.getToRole());
switch (end.getMultiplicity()) {
case MANY:
params = new Class<?>[] { List.class };
break;
case ONE:
params = new Class<?>[] { ((JPAEdmMapping) end.getEntityType().getMapping()).getJPAType() };
default:
break;
}
}
return jpaEntity.getClass().getMethod(name,
params);
} catch (NoSuchMethodException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
} catch (SecurityException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
} catch (EdmException e) {
throw ODataJPARuntimeException
.throwException(ODataJPARuntimeException.GENERAL
.addContent(e.getMessage()), e);
}
}
}