package io.cattle.platform.object.util;
import io.cattle.platform.json.JsonMapper;
import io.cattle.platform.util.type.CollectionUtils;
import io.cattle.platform.util.type.UnmodifiableMap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.beanutils.ConvertUtils;
public class DataAccessor {
Object source;
Object defaultValue;
Map<String, Object> sourceMap;
String key;
Class<?> scope;
String scopeKey;
public static DataAccessor fromDataFieldOf(Object obj) {
DataAccessor accessor = new DataAccessor();
accessor.source = obj;
return accessor;
}
public static DataAccessor fromMap(Object obj) {
DataAccessor accessor = new DataAccessor();
accessor.sourceMap = CollectionUtils.toMap(obj);
return accessor;
}
public static DataAccessor fields(Object obj) {
DataAccessor accessor = fromDataFieldOf(obj);
accessor.scopeKey = DataUtils.FIELDS;
return accessor;
}
public static void setField(Object obj, String field, Object fieldValue) {
DataAccessor.fields(obj).withKey(field).set(fieldValue);
}
public static String fieldString(Object obj, String key) {
return fields(obj).withKey(key).as(String.class);
}
public static Map<String, Object> fieldMap(Object obj, String key) {
Object list = fields(obj).withKey(key).getForWrite();
return CollectionUtils.toMap(list);
}
public static List<String> fieldStringList(Object obj, String key) {
List<String> result = new ArrayList<String>();
Object list = fields(obj).withKey(key).getForWrite();
if (list == null || !(list instanceof List)) {
return result;
}
for (Object item : (List<?>) list) {
result.add(org.apache.commons.lang3.ObjectUtils.toString(item, null));
}
return result;
}
public static List<String> appendToFieldStringList(Object obj, String key, String value) {
List<String> list = fieldStringList(obj, key);
if (!list.contains(value)) {
list.add(value);
}
DataAccessor.setField(obj, key, list);
return list;
}
public static Long fieldLong(Object obj, String key) {
return fields(obj).withKey(key).as(Long.class);
}
public static <T> List<T> fieldObjectList(Object obj, String name, Class<T> clz, JsonMapper jsonMapper) {
Object field = DataAccessor.field(obj, name, Object.class);
if (field == null) {
return Collections.emptyList();
}
return jsonMapper.convertCollectionValue(field, ArrayList.class, clz);
}
public static List<Long> fieldLongList(Object obj, String key) {
List<Long> result = new ArrayList<Long>();
Object list = fields(obj).withKey(key).getForWrite();
if (list == null || !(list instanceof List)) {
return result;
}
for (Object item : (List<?>) list) {
if (item == null) {
result.add(null);
} else if (item instanceof Number) {
result.add(((Number) item).longValue());
} else {
result.add(Long.parseLong(item.toString()));
}
}
return result;
}
public static Integer fieldInteger(Object obj, String key) {
return fields(obj).withKey(key).as(Integer.class);
}
public static Boolean fieldBoolean(Object obj, String key) {
return fields(obj).withKey(key).as(Boolean.class);
}
public static boolean fieldBool(Object obj, String key) {
return fields(obj).withKey(key).withDefault(false).as(Boolean.class);
}
public static Date fieldDate(Object obj, String key) {
Object val = fields(obj).withKey(key).get();
if (val instanceof Date) {
return (Date)val;
} else if (val instanceof Number) {
return new Date(((Number) val).longValue());
}
return null;
}
public static <T> T field(Object obj, String name, JsonMapper mapper, Class<T> type) {
return fields(obj).withKey(name).as(mapper, type);
}
public static <T> T field(Object obj, String name, Class<T> type) {
return fields(obj).withKey(name).as(type);
}
public DataAccessor withScope(Class<?> scope) {
this.scope = scope;
return this;
}
public DataAccessor withScopeKey(String scopeKey) {
this.scopeKey = scopeKey;
return this;
}
public DataAccessor withKey(String key) {
this.key = key;
return this;
}
public DataAccessor withDefault(Object defaultValue) {
this.defaultValue = defaultValue;
return this;
}
public <T> T as(JsonMapper mapper, Class<T> clz) {
return mapper.convertValue(get(), clz);
}
@SuppressWarnings("rawtypes")
public <T> T asCollection(JsonMapper mapper, Class<? extends Collection> collectionClass, Class<?> elementsClass) {
return mapper.convertCollectionValue(get(), collectionClass, elementsClass);
}
public <T> List<? extends T> asList(JsonMapper mapper, Class<T> elementsClass) {
return asCollection(mapper, List.class, elementsClass);
}
@SuppressWarnings("unchecked")
public <T> T as(Class<T> clz) {
return (T) ConvertUtils.convert(get(), clz);
}
public Object get() {
Map<String, Object> map = getTargetMap(false, true);
Object result = key == null ? null : map.get(key);
return result == null ? defaultValue : result;
}
public Object getForWrite() {
Map<String, Object> map = getTargetMap(false, false);
Object result = key == null ? null : map.get(key);
return result == null ? defaultValue : result;
}
public void set(Object value) {
Map<String, Object> map = getTargetMap(true, false);
if (key != null) {
map.put(key, value);
}
}
public void remove() {
Map<String, Object> map = getTargetMap(true, false);
if (key != null) {
map.remove(key);
}
}
protected Map<String, Object> getTargetMap(boolean addContainer, boolean read) {
Map<String, Object> sourceMap = this.sourceMap;
if (sourceMap == null && source != null) {
sourceMap = getData(source, read);
}
if (sourceMap == null) {
if (!addContainer) {
throw new IllegalStateException("Can not set a value on a null target");
}
return null;
}
Map<String, Object> map = sourceMap;
if (isScopeSet()) {
Object scopedMap = sourceMap.get(getScope());
if (scopedMap == null && addContainer) {
scopedMap = new HashMap<String, Object>();
sourceMap.put(getScope(), scopedMap);
}
map = CollectionUtils.toMap(scopedMap);
}
return map;
}
protected static Map<String, Object> getData(Object obj, boolean read) {
@SuppressWarnings("unchecked")
Map<String, Object> map = (Map<String, Object>) ObjectUtils.getPropertyIgnoreErrors(obj, DataUtils.DATA);
if (read) {
return map == null ? Collections.<String, Object> emptyMap() : Collections.unmodifiableMap(map);
} else if (map instanceof UnmodifiableMap<?, ?>) {
map = ((UnmodifiableMap<String, Object>) map).getModifiableCopy();
} else if (map == null) {
map = new HashMap<String, Object>();
}
ObjectUtils.setProperty(obj, DataUtils.DATA, map);
return map;
}
protected boolean isScopeSet() {
return scope != null || scopeKey != null;
}
protected String getScope() {
return scope == null ? scopeKey : scope.getName();
}
}