blob: 8ba5649ff8d9310d6c7ac8a40ee331f18be0a059 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2014 - 2018 Orange.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* Contributors:
* BAREAU Cyrille <cyrille.bareau@orange.com>,
* BONNARDEL Gregory <gbonnardel.ext@orange.com>,
*******************************************************************************/
package org.eclipse.om2m.persistence.mongodb.resource;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map.Entry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.om2m.commons.constants.ResourceType;
import org.eclipse.om2m.commons.entities.AccessControlPolicyEntity;
import org.eclipse.om2m.commons.entities.AeAnncEntity;
import org.eclipse.om2m.commons.entities.AeEntity;
import org.eclipse.om2m.commons.entities.CSEBaseEntity;
import org.eclipse.om2m.commons.entities.ContainerEntity;
import org.eclipse.om2m.commons.entities.ContentInstanceEntity;
import org.eclipse.om2m.commons.entities.DynamicAuthorizationConsultationEntity;
import org.eclipse.om2m.commons.entities.FlexContainerAnncEntity;
import org.eclipse.om2m.commons.entities.FlexContainerEntity;
import org.eclipse.om2m.commons.entities.MgmtObjAnncEntity;
import org.eclipse.om2m.commons.entities.MgmtObjEntity;
import org.eclipse.om2m.commons.entities.NodeAnncEntity;
import org.eclipse.om2m.commons.entities.NodeEntity;
import org.eclipse.om2m.commons.entities.RemoteCSEEntity;
import org.eclipse.om2m.commons.entities.ResourceEntity;
import org.eclipse.om2m.persistence.mongodb.Constants;
import com.google.gson.JsonArray;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;
@SuppressWarnings("unchecked")
public class ResourceSerializerDeserializer<T extends ResourceEntity>
implements Constants, JsonSerializer<T>, JsonDeserializer<T> {
private static final Log LOGGER = LogFactory.getLog(ResourceSerializerDeserializer.class);
private static final String GET = "get";
private static final String IS = "is";
private static final String SET = "set";
@Override
public JsonElement serialize(T entity, Type xxx, JsonSerializationContext ctxt) {
LOGGER.debug(" * IN * serialize " + entity);
JsonObject json = new JsonObject();
for (Method method : entity.getClass().getMethods()) {
if (!(method.getName().startsWith(GET) || method.getName().startsWith(IS))
|| method.getName().equals("getClass")) {
continue;
}
// at this point, the selected method is a getter
String propertyName = method.getName().startsWith(GET)
? method.getName().substring(3)
: method.getName().substring(2); // method name starts with "is"
// check if the return type is primitive
boolean isPrimitive = isSuperPrimitive(method.getReturnType());
LOGGER.debug("serialize (method=" + method.getName() + ") - returnType="
+ method.getReturnType() + " - isPrimitive=" + isPrimitive);
if (isPrimitive) {
try {
Object result = method.invoke(entity, new Object[0]);
LOGGER.debug("serialize (method=" + method.getName() + ") - invoke result=" + result);
json.add(propertyName, ctxt.serialize(result));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
LOGGER.warn("", e);
}
} else if (ResourceEntity.class.isAssignableFrom(method.getReturnType())) {
LOGGER.debug("Directly assignable to ResourceEntity " + method.getName());
} else if (List.class.equals(method.getReturnType())) {
// list
try {
List<?> result = (List<?>) method.invoke(entity, new Object[0]);
JsonArray jsonArray = new JsonArray();
LOGGER.debug("List serialize (method=" + method.getName()
+ ") - invoke result=" + result);
Type type = method.getGenericReturnType();
if (! ParameterizedType.class.isAssignableFrom(type.getClass())) {
continue;
}
ParameterizedType pt = (ParameterizedType) type;
if (pt.getActualTypeArguments().length == 0) {
continue;
}
if (ResourceEntity.class.isAssignableFrom((Class<?>) pt.getActualTypeArguments()[0])) {
LOGGER.debug("ComponentType =" + pt.getActualTypeArguments()[0]);
// continue;
if (result != null) {
for (Object obj : result) {
if (obj != null) {
ResourceEntity resourceEntity = (ResourceEntity) obj;
JsonObject jsonObject = new JsonObject();
jsonObject.add(RES_ID, new JsonPrimitive(resourceEntity.getResourceID()));
jsonObject.add(RES_TYPE, new JsonPrimitive(resourceEntity.getResourceType()));
if (obj instanceof MgmtObjEntity) {
jsonObject.add(MGMT_DEF,
new JsonPrimitive(((MgmtObjEntity)obj).getMgmtDefinition()));
} else if (obj instanceof MgmtObjAnncEntity) {
jsonObject.add(MGMT_DEF,
new JsonPrimitive(((MgmtObjAnncEntity)obj).getMgmtDefinition()));
}
jsonArray.add(jsonObject);
}
}
}
propertyName = "#" + propertyName;
} else {
jsonArray = (JsonArray) ctxt.serialize(result);
}
json.add(propertyName, jsonArray);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
LOGGER.warn("", e);
}
}
}
LOGGER.debug(" * OUT * serialize " + json);
return json;
}
private static boolean isSuperPrimitive(Class<?> clazz) {
return clazz.isPrimitive() || clazz.getName().startsWith("java.lang.")
|| clazz.getName().startsWith("java.math.");
}
@Override
public T deserialize(JsonElement obj, Type xxx, JsonDeserializationContext ctxt)
throws JsonParseException {
LOGGER.debug(" * IN * deserialize " + obj);
// we are sure obj is a Json object
JsonObject jsonObject = (JsonObject) obj;
// retrieve resource type
T entity = create(jsonObject);
if (entity == null) {
return null;
}
entity.setResourceType(jsonObject.get(RES_TYPE).getAsBigInteger());
for (Entry<String, JsonElement> entry : jsonObject.entrySet()) {
String propertyName = entry.getKey();
JsonElement value = entry.getValue();
if (propertyName.equals(RES_TYPE)) {
continue;
}
if (value.isJsonPrimitive()) {
JsonPrimitive jsonPrimitive = (JsonPrimitive) value;
Object param = null;
Method setterMethod = getSetter(propertyName, entity.getClass());
// identify setter
if (setterMethod == null) {
LOGGER.debug("Setter not found for " + propertyName);
} else {
if (jsonPrimitive.isBoolean()) {
param = jsonPrimitive.getAsBoolean();
} else if (jsonPrimitive.isString()) {
param = jsonPrimitive.getAsString();
} else if (jsonPrimitive.isNumber()) {
// valueObject = jsonPrimitive.getAsNumber();
param = ctxt.deserialize(jsonPrimitive,
setterMethod.getGenericParameterTypes()[0]);
}
try {
setterMethod.invoke(entity, new Object[] { param });
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
LOGGER.info("Exception setter=" + setterMethod.getName() + " - "
+ setterMethod.getParameterTypes()[0] + "- valueObject.getClass:"
+ param.getClass(), e);
}
}
} else if (value.isJsonArray()) {
// list case
JsonArray jsonArray = (JsonArray) value;
List<?> params = new ArrayList<>();
String initialPropertyName = propertyName;
if (initialPropertyName.startsWith("#")) {
initialPropertyName = initialPropertyName.substring(1);
}
Method setterMethod = getSetter(initialPropertyName, entity.getClass());
if (setterMethod == null) {
LOGGER.debug("Setter not found for " + propertyName);
} else {
if (jsonArray.size() > 0) {
if (propertyName.startsWith("#")) {
// need load them through
MongoChildLoader<T> m = new MongoChildLoader<>();
params = (List<?>) m.loadChildren(entity, jsonArray);
} else {
// inner object
params = (List<?>) ctxt.deserialize(jsonArray,
setterMethod.getGenericParameterTypes()[0]);
LOGGER.debug("jsonArray=" + jsonArray.toString() + " -> subObject=" + params);
}
}
try {
setterMethod.invoke(entity, new Object[] { params });
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
LOGGER.warn("", e);
}
}
}
}
LOGGER.debug(" * OUT * deserialize " + entity);
return entity;
}
private static Method getSetter(String propertyName, Class<?> clazz) {
String setterName = SET + propertyName;
for (Method method : clazz.getMethods()) {
if (setterName.equals(method.getName())) {
return method;
}
}
return null;
}
private final T create(JsonObject jsonObject) {
BigInteger type = jsonObject.get(RES_TYPE).getAsBigInteger();
switch (type.intValue()) {
case ResourceType.AE:
return (T) new AeEntity();
case ResourceType.CSE_BASE:
return (T) new CSEBaseEntity();
case ResourceType.ACCESS_CONTROL_POLICY:
return (T) new AccessControlPolicyEntity();
case ResourceType.FLEXCONTAINER:
return (T) new FlexContainerEntity();
case ResourceType.CONTAINER:
return (T) new ContainerEntity();
case ResourceType.CONTENT_INSTANCE:
return (T) new ContentInstanceEntity();
case ResourceType.REMOTE_CSE:
return (T) new RemoteCSEEntity();
case ResourceType.AE_ANNC:
return (T) new AeAnncEntity();
case ResourceType.FLEXCONTAINER_ANNC:
return (T) new FlexContainerAnncEntity();
case ResourceType.DYNAMIC_AUTHORIZATION_CONSULTATION:
return (T) new DynamicAuthorizationConsultationEntity();
case ResourceType.NODE:
return (T) new NodeEntity();
case ResourceType.NODE_ANNC:
return (T) new NodeAnncEntity();
case ResourceType.MGMT_OBJ:
return (T) MgmtObjEntity.create(jsonObject.get(MGMT_DEF).getAsBigInteger());
case ResourceType.MGMT_OBJ_ANNC:
return (T) MgmtObjAnncEntity.create(jsonObject.get(MGMT_DEF).getAsBigInteger());
}
LOGGER.warn("Cannot create entity for " + type);
return null;
}
}