package com.dubture.getcomposer.core.entities;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.dubture.getcomposer.core.annotation.Name;
import com.dubture.getcomposer.json.JsonFormatter;
import com.dubture.getcomposer.json.JsonParser;
import com.dubture.getcomposer.json.ParseException;
public abstract class JsonEntity extends Entity {
private transient Set<String> listening = new HashSet<String>();
@SuppressWarnings("rawtypes")
private transient Map<Class, Map<String, Field>> fieldNameCache = new HashMap<Class, Map<String, Field>>();
private transient Log log = LogFactory.getLog(JsonEntity.class);
protected transient LinkedList<String> sortOrder = new LinkedList<String>();
public JsonEntity() {
listen();
initialize();
}
// can be filled by subclasses
protected void initialize() {
}
protected void listen() {
try {
for (Field field : getFields(this.getClass())) {
if (JsonCollection.class.isAssignableFrom(field.getType())) {
final String prop = getFieldName(field);
final JsonEntity sender = this;
if (listening.contains(prop)) {
continue;
}
field.setAccessible(true);
JsonEntity obj = (JsonEntity)field.get(this);
if (obj != null) {
obj.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
firePropertyChange(prop + "." + e.getPropertyName(),
e.getOldValue(), e.getNewValue());
// append to sort order - use reflection
if (sender instanceof AbstractJsonObject) {
try {
Method mtd = JsonEntity.class.getDeclaredMethod("appendSortOrder", String.class);
mtd.setAccessible(true);
mtd.invoke(sender, prop);
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
});
listening.add(prop);
}
}
}
} catch (Exception e) {
log.error(e);
}
}
@SuppressWarnings("rawtypes")
protected ArrayList<Field> getFields(Class entity) {
ArrayList<Field> fields = new ArrayList<Field>();
Class superClass = entity;
while (superClass != null) {
for (Field field : superClass.getDeclaredFields()) {
if (!((field.getModifiers() & Modifier.TRANSIENT) == Modifier.TRANSIENT)) {
fields.add(field);
}
}
superClass = superClass.getSuperclass();
}
return fields;
}
protected String getFieldName(Field field) {
String name = field.getName();
for (Annotation anno : field.getAnnotations()) {
if (anno.annotationType() == Name.class) {
name = ((Name) anno).value();
}
}
return name;
}
@SuppressWarnings("rawtypes")
protected List<String> getFieldNames(Class entity) {
ArrayList<String> names = new ArrayList<String>();
for (Field field : getFields(entity)) {
names.add(getFieldName(field));
}
return names;
}
@SuppressWarnings("rawtypes")
protected Field getFieldByName(Class entity, String fieldName) {
// create cache
if (!fieldNameCache.containsKey(entity)) {
Map<String, Field> mapping = new HashMap<String, Field>();
for (Field field : getFields(entity)) {
mapping.put(getFieldName(field), field);
}
fieldNameCache.put(entity, mapping);
}
Map<String, Field> mapping = fieldNameCache.get(entity);
if (mapping.containsKey(fieldName)) {
return mapping.get(fieldName);
}
return null;
}
protected void appendSortOrder(String name) {
if (!sortOrder.contains(name)) {
sortOrder.add(name);
}
}
protected Object getJsonValue(Object value) {
if (value instanceof JsonValue) {
return ((JsonValue)value).toJsonValue();
} else if (value instanceof JsonCollection) {
JsonCollection coll = (JsonCollection) value;
if (coll.size() > 0) {
// call buildJson - use reflection
try {
Method mtd = JsonEntity.class.getDeclaredMethod("buildJson");
return mtd.invoke(coll);
} catch (Exception e) {
e.printStackTrace();
}
}
} else {
return value;
}
return null;
}
protected abstract void doParse(Object obj);
private void parse(String json) throws ParseException {
JsonParser parser = new JsonParser();
doParse(parser.parse(json));
}
private void parse(Reader reader) throws IOException, ParseException {
JsonParser parser = new JsonParser();
doParse(parser.parse(reader));
}
public void fromJson(Object json) {
doParse(json);
}
public void fromJson(String json) throws ParseException {
parse(json);
}
public void fromJson(File file) throws IOException, ParseException {
if (file.length() > 0) {
fromJson(new FileReader(file));
}
}
public void fromJson(Reader reader) throws IOException, ParseException {
parse(reader);
}
protected abstract Object buildJson();
public String toJson() {
return JsonFormatter.format(buildJson());
}
}