package http.resource;
import static com.google.common.base.Preconditions.checkNotNull;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintStream;
import java.io.Reader;
import java.io.Writer;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import javax.servlet.http.HttpServletRequest;
import nebula.data.Broker;
import nebula.data.Classificator;
import nebula.data.DataStore;
import nebula.data.DataWatcher;
import nebula.data.Entity;
import nebula.data.json.DataHelper;
import nebula.lang.Field;
import nebula.lang.Reference;
import nebula.lang.Type;
import org.eclipse.jetty.util.URIUtil;
import util.FileUtil;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.Lists;
public class EntityListResouce extends AbstractResouce {
private final DataHelper<Entity, Reader, Writer> jsonHolder;
private final DataStore<Entity> datastoreHolder;
final LoadingCache<String, DataHolder> dataCache;
class TreeDataHolder implements DataHolder {
String parentFieldName;
String value;
public TreeDataHolder(String parentFieldName, String value) {
this.parentFieldName = parentFieldName;
this.value = checkNotNull(value);
}
public byte[] get() {
List<Entity> dataList = datastoreHolder.listAll();
List<Entity> to = Lists.newArrayList();
for (Entity entity : dataList) {
if (value.equals(entity.getID())) {
to.add(entity);
addChildren(entity, dataList, to);
}
}
return buildFrom(to);
}
private List<Entity> addChildren(Entity root, List<Entity> from, List<Entity> to) {
String id = (String) root.getID();
for (Entity e : from) {
if (id.equals(e.get(parentFieldName))) {
to.add(e);
addChildren(e, from, to);
}
}
return to;
}
}
interface DataHolder {
byte[] get();
}
class DataHolderClassificator implements DataHolder {
Classificator<String, Entity> classificator;
String value;
public DataHolderClassificator(Classificator<String, Entity> classificator, String value) {
this.classificator = checkNotNull(classificator);
this.value = checkNotNull(value);
}
public byte[] get() {
List<Entity> dataList = classificator.getData(value);
return buildFrom(dataList);
}
}
private byte[] buildFrom(List<Entity> dataList) {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
PrintStream out = new PrintStream(bout);
boolean start = true;
out.append('[');
for (Entity data : dataList) {
if (!start) {
out.append(',');
} else {
start = false;
}
jsonHolder.stringifyTo(data, new OutputStreamWriter(out));
}
out.append(']');
out.flush();
out.close();
return bout.toByteArray();
}
public EntityListResouce(final Type typeBroker, DataHelper<Entity, Reader, Writer> json, DataStore<Entity> datas) {
super("text/json", 0, 1000);
this.jsonHolder = json;
this.datastoreHolder = datas;
this.dataCache = CacheBuilder.newBuilder().maximumSize(1000).build(new CacheLoader<String, DataHolder>() {
public DataHolder load(String query) {
String[] params = query.split("&");
DataStore<Entity> dataStore = datastoreHolder;
Map<String, Classificator<String, Entity>> classificatores = dataStore.getClassificatores();
String cKey = null;
String cValue = null;
for (String keyvalue : params) {
String[] kv = keyvalue.split("=");
String key = kv[0];
String value = kv[1];
if ("root".equals(key)) {
Field c = null;
for (Field f : typeBroker.getDeclaredFields()) {
if (f.getRefer() == Reference.Cascade) {
c = f;
}
}
return new TreeDataHolder(c.getName() + typeBroker.getKeyField().getName(), value);
} else if (classificatores.containsKey(key)) {
cKey = key;
cValue = value;
return new DataHolderClassificator(classificatores.get(checkNotNull(cKey)), cValue);
}
}
return null;
}
});
Broker.brokerOf(json).addWatcher(new DataWatcher<DataHelper<Entity, Reader, Writer>>() {
@Override
public boolean onUpdate(DataHelper<Entity, Reader, Writer> newData, DataHelper<Entity, Reader, Writer> oldData) {
dataCache.cleanUp();
return false;
}
});
}
protected void get(HttpServletRequest req) {
try {
String query = URIUtil.decodePath(req.getQueryString());
List<Entity> dataList;
if (query == null || query.length() == 0) {
dataList = datastoreHolder.listAll();
this.cache = buildFrom(dataList);
} else {
this.cache = dataCache.get(query).get();
}
this.lastModified = System.currentTimeMillis();
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
}
@Override
protected String post(HttpServletRequest req) throws IOException {
DataStore<Entity> store = datastoreHolder;
InputStream in = req.getInputStream();
if (log.isTraceEnabled()) {
in = FileUtil.print(in);
}
Entity inData = jsonHolder.readFrom(null, new InputStreamReader(in));
store.add(inData);
store.flush();
return req.getPathInfo() + inData.getID();
}
}