package io.cattle.platform.object.postinit; import static io.cattle.platform.object.util.DataUtils.*; import io.cattle.platform.json.JsonMapper; import io.cattle.platform.util.type.Priority; import java.beans.PropertyDescriptor; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.HashMap; import java.util.Map; import java.util.TreeMap; import javax.inject.Inject; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.PropertyUtils; public class ObjectDataPostInstantiationHandler implements ObjectPostInstantiationHandler, Priority { JsonMapper jsonMapper; @Override public <T> T postProcess(T obj, Class<T> clz, Map<String, Object> properties) { if (!hasDataField(obj)) return obj; try { Map<String, Object> data = getData(obj, properties); setData(obj, data); return obj; } catch (IOException e) { throw new IllegalStateException("Failed to handle object data for [" + obj + "] and properties [" + properties + "]", e); } } protected boolean hasDataField(Object obj) { PropertyDescriptor desc; try { desc = PropertyUtils.getPropertyDescriptor(obj, "data"); } catch (IllegalAccessException e) { return false; } catch (InvocationTargetException e) { return false; } catch (NoSuchMethodException e) { return false; } if (desc == null || desc.getReadMethod() == null || desc.getPropertyType() != Map.class) { return false; } return true; } protected void setData(Object instance, Map<String, Object> data) throws IOException { try { BeanUtils.setProperty(instance, DATA, data); } catch (IllegalAccessException e) { throw new IllegalStateException("Failed to set data [" + data + "] on [" + instance + "]", e); } catch (InvocationTargetException e) { throw new IllegalStateException("Failed to set data [" + data + "] on [" + instance + "]", e); } } @SuppressWarnings("unchecked") protected Map<String, Object> getData(Object instance, Map<String, Object> properties) throws IOException { Map<String, Object> objectData = null; Map<String, Object> inputData = getMap(properties.get(DATA)); try { objectData = (Map<String, Object>) PropertyUtils.getProperty(instance, DATA); } catch (IllegalAccessException e) { } catch (InvocationTargetException e) { } catch (NoSuchMethodException e) { } Map<String, Object> finalData = new TreeMap<String, Object>(); if (objectData != null) { finalData.putAll(objectData); } finalData.putAll(inputData); overlay(finalData, OPTIONS, getMap(inputData.get(OPTIONS))); overlay(finalData, FIELDS, getFieldData(instance, properties)); return finalData; } protected Map<String, Object> getFieldData(Object instance, Map<String, Object> properties) { Map<String, Object> fields = new HashMap<String, Object>(); for (String name : properties.keySet()) { try { if (PropertyUtils.getPropertyDescriptor(instance, name) != null) continue; } catch (IllegalAccessException e) { continue; } catch (InvocationTargetException e) { continue; } catch (NoSuchMethodException e) { // This exception would be okay, but it never seems to happen } fields.put(name, properties.get(name)); } return fields; } protected void overlay(Map<String, Object> data, String key, Map<String, Object> overlay) { Map<String, Object> existing = getMap(data.get(key)); existing.putAll(overlay); if (existing.size() == 0) { data.remove(key); } else { data.put(key, existing); } } @SuppressWarnings("unchecked") protected Map<String, Object> getMap(Object obj) { if (obj instanceof Map) { return (Map<String, Object>) obj; } return new HashMap<String, Object>(); } public JsonMapper getJsonMapper() { return jsonMapper; } @Inject public void setJsonMapper(JsonMapper jsonMapper) { this.jsonMapper = jsonMapper; } @Override public int getPriority() { return Priority.DEFAULT; } }