package com.dubture.getcomposer.core.entities;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.dubture.getcomposer.core.collection.JsonArray;
import com.dubture.getcomposer.core.objects.JsonObject;
import com.dubture.getcomposer.httpclient.HttpAsyncClient;
public abstract class AbstractJsonObject<V> extends JsonEntity implements
JsonCollection {
private transient Map<String, PropertyChangeListener> listeners = new HashMap<String, PropertyChangeListener>();
protected transient Map<String, V> properties = new LinkedHashMap<String, V>();
private transient Log log = LogFactory.getLog(HttpAsyncClient.class);
@SuppressWarnings({ "unchecked", "rawtypes" })
protected void doParse(Object obj) {
clear();
if (obj instanceof LinkedHashMap) {
List<String> fields = getFieldNames(this.getClass());
LinkedHashMap json = (LinkedHashMap)obj;
for (Entry<String, Object> entry : ((Map<String, Object>) obj).entrySet()) {
String property = entry.getKey();
if (fields.contains(property)) {
parseField(json, property);
} else {
Object value = null;
if (json.containsKey(property)) {
value = json.get(property);
if (value instanceof LinkedList) {
value = new JsonArray(value);
} else if (value instanceof LinkedHashMap) {
value = new JsonObject(value);
}
}
set(property, value);
}
}
}
}
@SuppressWarnings("rawtypes")
protected void parseField(LinkedHashMap json, String property) {
if (json.containsKey(property)) {
Field field = getFieldByName(this.getClass(), property);
if (field != null && JsonEntity.class.isAssignableFrom(field.getType())) {
try {
field.setAccessible(true);
JsonEntity entity = (JsonEntity) field.get(this);
entity.fromJson(json.get(property));
} catch (Exception e) {
log.error(e);
}
}
}
}
@Override
protected Object buildJson() {
LinkedList<String> propsOrder = new LinkedList<String>(sortOrder);
// First: create an index to search for field names and add them to the props order
HashMap<String, Field> namedFields = new HashMap<String, Field>();
for (Field field : getFields(this.getClass())) {
field.setAccessible(true);
String fieldName = getFieldName(field);
namedFields.put(fieldName, field);
propsOrder.add(fieldName);
}
// add properties that aren't in the hashmap yet
for (Entry<String, V> entry : properties.entrySet()) {
propsOrder.add(entry.getKey());
}
// Second: find property contents (either field or property key)
LinkedHashMap<String, Object> out = new LinkedHashMap<String, Object>();
for (String entry : propsOrder) {
if (out.containsKey(entry)) {
continue;
}
Object value = null;
// search class fields first
if (namedFields.containsKey(entry)) {
try {
value = namedFields.get(entry).get(this);
} catch (Exception e) {
log.error(e);
}
}
// check properties
else if (properties.containsKey(entry)) {
value = properties.get(entry);
}
value = getJsonValue(value);
if (value == null || value.equals("")) {
continue;
}
// add to output
out.put(entry, value);
}
return out;
}
protected List<String> getOwnProperties() {
return new ArrayList<String>();
}
/*
* (non-Javadoc)
*
* @see com.dubture.getcomposer.core.entities.JsonCollection#size()
*/
public int size() {
return properties.size();
}
/*
* (non-Javadoc)
*
* @see com.dubture.getcomposer.core.entities.JsonCollection#clear()
*/
public void clear() {
// clear properties
List<String> ownProps = getOwnProperties();
for (String key : properties.keySet().toArray(new String[]{})) {
if (ownProps.contains(key)) {
Object value = properties.get(key);
if (value instanceof JsonCollection) {
JsonCollection entity = (JsonCollection)value;
entity.clear();
} else {
remove(key);
}
} else {
remove(key);
}
}
// clear fields
for (Field field : getFields(this.getClass())) {
if (field != null && JsonCollection.class.isAssignableFrom(field.getType())) {
try {
field.setAccessible(true);
JsonCollection entity = (JsonCollection) field.get(this);
entity.clear();
} catch (Exception e) {
log.error(e);
}
}
}
// clear sort order
sortOrder.clear();
}
/**
* Returns whether the given property is present.
*
* @param property
* the property to look for
* @return <ul>
* <li><code>true</code> property present</li>
* <li><code>false</code> property not present</li>
* </ul>
*/
public boolean has(String property) {
return properties.containsKey(property);
}
/**
* Returns the property value.
*
* @param property
* the property
* @return the value
*/
public V get(String property) {
return properties.get(property);
}
/**
* Sets a new value for the given property.
*
* @param property
* the property
* @param value
* the new value
*/
public void set(String property, Object value) {
set(property, value, true);
}
/**
* Sets a new value for the given property.
*
* @param property
* the property
* @param value
* the new value
* @param notify
* whether listeners should be notified about the change
*/
@SuppressWarnings("unchecked")
protected void set(String property, Object value, boolean notify) {
// remove listener on the current value if there is one yet
uninstallListener(property);
JsonEntity entity = null;
// install listener to be aware of changes
if (value instanceof JsonValue) {
entity = getEntity((JsonValue) value);
} else if (value instanceof JsonEntity) {
entity = (JsonEntity) value;
}
if (entity != null && !listeners.containsKey(property)) {
installListener(property, entity);
}
V oldValue = properties.get(property);
properties.put(property, (V) value);
appendSortOrder(property);
if (notify) {
firePropertyChange(property, oldValue, (V) value);
}
}
/**
* Removes the given property.
*
* @param property
* the property
*/
public void remove(String property) {
uninstallListener(property);
Object oldValue = get(property);
properties.remove(property);
firePropertyChange(property, oldValue, null);
}
private void installListener(final String property, JsonEntity entity) {
if (entity != null) {
listeners.put(property, new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange(property + "." + evt.getPropertyName(),
evt.getOldValue(), evt.getNewValue());
}
});
entity.addPropertyChangeListener(listeners.get(property));
}
}
private void uninstallListener(String property) {
if (listeners.containsKey(property)) {
if (has(property)) {
JsonEntity entity = getEntity(get(property));
if (entity != null) {
entity.removePropertyChangeListener(listeners.get(property));
}
}
listeners.remove(property);
}
}
private JsonEntity getEntity(Object value) {
JsonEntity entity = null;
if (value instanceof JsonValue) {
JsonValue val = (JsonValue) value;
if (val.isArray()) {
entity = val.getAsArray();
}
if (val.isObject()) {
entity = val.getAsObject();
}
}
return entity;
}
}