package io.cattle.platform.object.impl;
import io.cattle.platform.object.ObjectManager;
import io.cattle.platform.object.lifecycle.ObjectLifeCycleHandler;
import io.cattle.platform.object.lifecycle.ObjectLifeCycleHandler.LifeCycleEvent;
import io.cattle.platform.object.meta.MapRelationship;
import io.cattle.platform.object.meta.ObjectMetaDataManager;
import io.cattle.platform.object.meta.Relationship;
import io.cattle.platform.object.meta.Relationship.RelationshipType;
import io.cattle.platform.object.postinit.ObjectPostInstantiationHandler;
import io.cattle.platform.object.util.ObjectUtils;
import io.cattle.platform.util.type.CollectionUtils;
import io.github.ibuildthecloud.gdapi.factory.SchemaFactory;
import io.github.ibuildthecloud.gdapi.model.Schema;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
public abstract class AbstractObjectManager implements ObjectManager {
SchemaFactory schemaFactory;
List<ObjectPostInstantiationHandler> postInitHandlers;
List<ObjectLifeCycleHandler> lifeCycleHandlers;
ObjectMetaDataManager metaDataManager;
@Override
public <T> T create(T instance) {
return create(instance, new HashMap<String, Object>());
}
@Override
public <T> T create(T instance, Object key, Object... valueKeyValue) {
Map<Object, Object> properties = CollectionUtils.asMap(key, valueKeyValue);
return create(instance, convertToPropertiesFor(instance, properties));
}
@Override
public <T> T create(T instance, Map<String, Object> properties) {
@SuppressWarnings("unchecked")
Class<T> clz = (Class<T>) instance.getClass();
for (ObjectPostInstantiationHandler handler : postInitHandlers) {
instance = handler.postProcess(instance, clz, properties);
}
instance = insert(instance, clz, properties);
instance = callLifeCycleHandlers(LifeCycleEvent.CREATE, instance, clz, properties);
return instance;
}
@Override
public <T> T create(Class<T> clz, Map<String, Object> properties) {
T instance = construct(clz, properties);
instance = insert(instance, clz, properties);
instance = callLifeCycleHandlers(LifeCycleEvent.CREATE, instance, clz, properties);
return instance;
}
@Override
public <T> T create(Class<T> clz, Object key, Object... valueKeyValue) {
Map<Object, Object> properties = CollectionUtils.asMap(key, valueKeyValue);
return create(clz, convertToPropertiesFor(clz, properties));
}
protected <T> T construct(Class<T> clz, Map<String, Object> properties) {
T instance = instantiate(clz, properties);
for (ObjectPostInstantiationHandler handler : postInitHandlers) {
instance = handler.postProcess(instance, clz, properties);
}
return instance;
}
protected <T> T callLifeCycleHandlers(LifeCycleEvent event, T instance, Class<T> clz, Map<String, Object> properties) {
if (lifeCycleHandlers == null) {
return instance;
}
for (ObjectLifeCycleHandler handler : lifeCycleHandlers) {
instance = handler.onEvent(event, instance, clz, properties);
}
return instance;
}
protected abstract <T> T instantiate(Class<T> clz, Map<String, Object> properties);
protected abstract <T> T insert(T instance, Class<T> clz, Map<String, Object> properties);
@Override
public String getType(Object obj) {
if (obj == null) {
return null;
}
Schema schema = null;
if (obj instanceof Class<?>) {
schema = schemaFactory.getSchema((Class<?>) obj);
} else {
schema = schemaFactory.getSchema(obj.getClass());
}
if (schema == null) {
return null;
}
return schema.getParent() == null ? schema.getId() : schemaFactory.getBaseType(schema.getId());
}
protected String getPossibleSubType(Object obj) {
Object kind = ObjectUtils.getPropertyIgnoreErrors(obj, ObjectMetaDataManager.KIND_FIELD);
if (kind != null) {
String kindString = kind.toString();
String baseType = schemaFactory.getBaseType(kindString);
Class<?> clz = schemaFactory.getSchemaClass(baseType);
if (kind != null && clz != null && clz.isAssignableFrom(obj.getClass())) {
return kindString;
}
}
return getType(obj);
}
@Override
public <T> T setFields(Object obj, Object key, Object... valueKeyValue) {
Map<Object, Object> values = CollectionUtils.asMap(key, valueKeyValue);
return setFields(obj, convertToPropertiesFor(obj, values));
}
@SuppressWarnings("unchecked")
protected Map<Object, Object> toObjectsToWrite(Object obj, Map<String, Object> values) {
String type = getType(obj);
Map<String, Relationship> relationships = null;
Map<Object, Object> objValues = new LinkedHashMap<Object, Object>();
for (Map.Entry<String, Object> entry : values.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof Map<?, ?>) {
if (relationships == null) {
relationships = metaDataManager.getLinkRelationships(schemaFactory, type);
}
Relationship rel = relationships.get(key.toLowerCase());
if (rel != null && rel.getRelationshipType() != Relationship.RelationshipType.REFERENCE) {
rel = null;
}
if (rel == null) {
objValues.put(key, value);
} else {
value = toObjectsToWrite(rel.getObjectType(), (Map<String, Object>) value);
objValues.put(rel, value);
}
} else {
objValues.put(key, value);
}
}
return objValues;
}
@SuppressWarnings("unchecked")
@Override
public <T> List<T> getListByRelationship(Object obj, Relationship rel) {
if (rel == null || obj == null) {
return Collections.emptyList();
}
if (!rel.isListResult()) {
throw new IllegalArgumentException("Relationation arguement is not a list result");
}
if (rel.getRelationshipType() == RelationshipType.CHILD) {
return (List<T>) children(obj, rel.getObjectType(), rel.getPropertyName());
} else if (rel.getRelationshipType() == RelationshipType.MAP) {
return getListByRelationshipMap(obj, (MapRelationship) rel);
}
return Collections.emptyList();
}
protected abstract <T> List<T> getListByRelationshipMap(Object obj, MapRelationship rel);
@SuppressWarnings("unchecked")
@Override
public <T> T getObjectByRelationship(Object obj, Relationship rel) {
if (rel == null || obj == null) {
return null;
}
if (rel.isListResult()) {
throw new IllegalArgumentException("Relationation arguement is not a singular result");
}
Object id = ObjectUtils.getProperty(obj, rel.getPropertyName());
return id == null ? null : (T) loadResource(rel.getObjectType(), id.toString());
}
@Override
public boolean isKind(Object obj, String kind) {
if (obj == null) {
return false;
}
Object kindField = ObjectUtils.getPropertyIgnoreErrors(obj, ObjectMetaDataManager.KIND_FIELD);
/* At some point should check hierarchies... */
return kindField != null && kindField.equals(kind);
}
@Override
public SchemaFactory getSchemaFactory() {
return schemaFactory;
}
public void setSchemaFactory(SchemaFactory schemaFactory) {
this.schemaFactory = schemaFactory;
}
public List<ObjectPostInstantiationHandler> getPostInitHandlers() {
return postInitHandlers;
}
@Inject
public void setPostInitHandlers(List<ObjectPostInstantiationHandler> postInitHandlers) {
this.postInitHandlers = CollectionUtils.orderList(ObjectPostInstantiationHandler.class, postInitHandlers);
}
public List<ObjectLifeCycleHandler> getLifeCycleHandlers() {
return lifeCycleHandlers;
}
public void setLifeCycleHandlers(List<ObjectLifeCycleHandler> lifeCycleHandlers) {
this.lifeCycleHandlers = lifeCycleHandlers;
}
public ObjectMetaDataManager getMetaDataManager() {
return metaDataManager;
}
@Inject
public void setMetaDataManager(ObjectMetaDataManager metaDataManager) {
this.metaDataManager = metaDataManager;
}
}