package water.api;
import org.reflections.Reflections;
import water.H2O;
import water.Key;
import water.api.schemas3.*;
import water.api.schemas3.RapidsHelpV3.RapidsExpressionV3;
import water.api.schemas4.InputSchemaV4;
import water.api.schemas4.SessionIdV4;
import water.exceptions.H2OIllegalArgumentException;
import water.rapids.ast.AstRoot;
import water.rapids.Rapids;
import water.rapids.Session;
import water.rapids.Val;
import water.util.Log;
import water.util.StringUtils;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
public class RapidsHandler extends Handler {
public RapidsSchemaV3 exec(int version, RapidsSchemaV3 rapids) {
if (rapids == null) return null;
if (!StringUtils.isNullOrEmpty(rapids.id))
throw new H2OIllegalArgumentException("Field RapidsSchemaV3.id is deprecated and should not be set " + rapids.id);
if (StringUtils.isNullOrEmpty(rapids.ast)) return rapids;
if (StringUtils.isNullOrEmpty(rapids.session_id))
rapids.session_id = "_specialSess";
Session ses = RapidsHandler.SESSIONS.get(rapids.session_id);
if (ses == null) {
ses = new Session(rapids.session_id);
RapidsHandler.SESSIONS.put(rapids.session_id, ses);
}
Val val;
try {
// This call is synchronized on the session instance
val = Rapids.exec(rapids.ast, ses);
} catch (IllegalArgumentException e) {
throw e;
} catch (Throwable e) {
Log.err(e);
e.printStackTrace();
throw e;
}
switch (val.type()) {
case Val.NUM: return new RapidsNumberV3(val.getNum());
case Val.NUMS: return new RapidsNumbersV3(val.getNums());
case Val.ROW: return new RapidsNumbersV3(val.getRow());
case Val.STR: return new RapidsStringV3(val.getStr());
case Val.STRS: return new RapidsStringsV3(val.getStrs());
case Val.FRM: return new RapidsFrameV3(val.getFrame());
case Val.FUN: return new RapidsFunctionV3(val.getFun().toString());
default: throw H2O.fail();
}
}
public RapidsHelpV3 genHelp(int version, SchemaV3 noschema) {
Reflections reflections = new Reflections("water.rapids");
RapidsHelpV3 res = new RapidsHelpV3();
res.syntax = processAstClass(AstRoot.class, reflections);
return res;
}
private RapidsExpressionV3 processAstClass(Class<? extends AstRoot> clz, Reflections refl) {
ArrayList<RapidsExpressionV3> subs = new ArrayList<>();
for (Class<? extends AstRoot> subclass : refl.getSubTypesOf(clz))
if (subclass.getSuperclass() == clz)
subs.add(processAstClass(subclass, refl));
RapidsExpressionV3 target = new RapidsExpressionV3();
target.name = clz.getSimpleName();
target.is_abstract = Modifier.isAbstract(clz.getModifiers());
if (!target.is_abstract) {
try {
AstRoot m = clz.newInstance();
target.pattern = m.example();
target.description = m.description();
}
catch (IllegalAccessException e) { throw H2O.fail("A"); }
catch (InstantiationException e) { throw H2O.fail("B"); }
}
target.sub = subs.toArray(new RapidsExpressionV3[subs.size()]);
return target;
}
/** Map of session-id (sent by the client) to the actual session instance. */
public static HashMap<String, Session> SESSIONS = new HashMap<>();
@SuppressWarnings("unused") // called through reflection by RequestServer
public InitIDV3 startSession(int version, InitIDV3 p) {
p.session_key = "_sid" + Key.make().toString().substring(0,5);
return p;
}
@SuppressWarnings("unused") // called through reflection by RequestServer
public InitIDV3 endSession(int version, InitIDV3 p) {
if (SESSIONS.get(p.session_key) != null) {
try {
SESSIONS.get(p.session_key).end(null);
SESSIONS.remove(p.session_key);
} catch (Throwable ex) {
throw SESSIONS.get(p.session_key).endQuietly(ex);
}
}
return p;
}
public static class StartSession4 extends RestApiHandler<InputSchemaV4, SessionIdV4> {
@Override public String name() {
return "newSession4";
}
@Override public String help() {
return "Start a new Rapids session, and return the session id.";
}
@Override
public SessionIdV4 exec(int ignored, InputSchemaV4 input) {
SessionIdV4 out = new SessionIdV4();
out.session_key = "_sid" + Key.make().toString().substring(0, 5);
return out;
}
}
}