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.DataRepos;
import nebula.data.DataStore;
import nebula.data.DataWatcher;
import nebula.data.Entity;
import nebula.data.impl.EditableEntity;
import nebula.data.json.DataHelper;
import nebula.data.json.JsonHelperProvider;
import nebula.flow.FlowEngine;
import nebula.lang.Flow;
import nebula.lang.Flow.Step;
import nebula.lang.RuntimeContext;
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;
public class FlowListResouce extends AbstractResouce {
private final DataHelper<Entity, Reader, Writer> jsonHolder;
private final DataHelper<Entity, Reader, Writer> jsonStepBegin;
private final DataStore<Entity> datastoreHolder;
final LoadingCache<String, DataHolder> dataCache;
final Type type;
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();
}
final DataRepos dataRepos;
public FlowListResouce(final DataRepos dataRepos, DataHelper<Entity, Reader, Writer> json, DataStore<Entity> datas, Type type) {
super("text/json", 0, 1000);
this.dataRepos = dataRepos;
this.jsonHolder = json;
this.datastoreHolder = datas;
this.type = type;
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 (classificatores.containsKey(key)) {
cKey = key;
cValue = value;
return new DataHolderClassificator(classificatores.get(checkNotNull(cKey)), cValue);
}
}
return null;
}
});
Broker.brokerOf(type).addWatcher(new DataWatcher<Type>() {
@Override
public boolean onUpdate(Type newData, Type oldData) {
dataCache.cleanUp();
return false;
}
});
Flow flow = (Flow)Broker.valueOf(type);
jsonStepBegin = JsonHelperProvider.getFlowHelper(type, flow.getSteps().get(Step.Begin).getType());
}
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);
}
FlowEngine engine = new FlowEngine(dataRepos, (Flow) Broker.valueOf(type));
RuntimeContext context = new RuntimeContext();
EditableEntity data = engine.start(context);
List<Entity> steps = data.get("steps");
Entity currentStepEntity = steps.get(steps.size() - 1);
data.put(Flow.Field_CurrrentStepEntity, currentStepEntity);
jsonStepBegin.readFrom(data, new InputStreamReader(req.getInputStream()));
String action = req.getParameter("$action");
if (action != null) {
engine.stepSubmit(context, action, (EditableEntity) data);
}else{
engine.stepSubmit(context, (EditableEntity) data);
}
return req.getPathInfo() + data.getID();
}
}