/* ************************************************************************
#
# DivConq
#
# http://divconq.com/
#
# Copyright:
# Copyright 2014 eTimeline, LLC. All rights reserved.
#
# License:
# See the license.txt file in the project's top-level directory for details.
#
# Authors:
# * Andy White
#
************************************************************************ */
package divconq.web;
import divconq.bus.Message;
import divconq.bus.MessageUtil;
import divconq.bus.ServiceResult;
import divconq.lang.Memory;
import divconq.lang.op.FuncResult;
import divconq.lang.op.OperationResult;
import divconq.log.Logger;
import divconq.struct.CompositeParser;
import divconq.struct.CompositeStruct;
import divconq.struct.RecordStruct;
public class RpcHandler implements IBodyCallback {
protected HttpContext context = null;
public RpcHandler(HttpContext ctx) {
this.context = ctx;
}
@Override
public void fail() {
this.context.sendRequestBad();
}
@Override
public void ready(Memory mem) {
FuncResult<CompositeStruct> pres = CompositeParser.parseJson(mem);
if (pres.hasErrors()) {
this.context.sendRequestBad();
return;
}
CompositeStruct croot = pres.getResult();
if ((croot == null) || !(croot instanceof RecordStruct)) {
this.context.sendRequestBad();
return;
}
this.context.session.useContext(this.context.session.allocateContextBuilder());
RecordStruct mrec = (RecordStruct) croot;
// check that the request conforms to the schema for RpcMessage
OperationResult rootres = mrec.validate("RpcMessage");
if (rootres.hasErrors()) {
this.context.sendRequestBad();
return;
}
// if so convert the Record into a Message for transport over our bus
Message msg = MessageUtil.fromRecord(mrec);
//System.out.println("got rpc message: " + msg);
String sessionid = msg.getFieldAsString("Session");
msg.removeField("Session");
// for SendForget don't wait for a callback, just return success
if ("SendForget".equals(msg.getFieldAsString("RespondTag"))) {
// send to bus
this.context.getSession().sendMessage(msg);
Message rmsg = MessageUtil.success();
String currsessid = RpcHandler.this.context.getSession().getId();
rmsg.setField("Session", currsessid);
if ((sessionid != null) && !currsessid.equals(sessionid))
rmsg.setField("SessionChanged", true);
// TODO pickup from mailbox
// reply to client, don't wait for response
this.context.send(rmsg);
return;
}
this.context.getSession().sendMessageWait(msg, new ServiceResult() {
@Override
public void callback() {
try {
// if we did not get an official reply to the request then
// it may have been a timeout. regardless, collect messages
// and prepare to return any payload
Message rmsg = this.toLogMessage();
// add the body (payload) if any
Message reply = this.getResult();
if (reply != null) {
if (reply.hasField("Service"))
rmsg.setField("Service", reply.getField("Service"));
if (reply.hasField("Feature"))
rmsg.setField("Feature", reply.getField("Feature"));
if (reply.hasField("Op"))
rmsg.setField("Op", reply.getField("Op"));
if (reply.hasField("Tag"))
rmsg.setField("Tag", reply.getField("Tag"));
if (reply.hasField("FromHub"))
rmsg.setField("FromHub", reply.getField("FromHub"));
//if (reply.hasField("Body")) - always even if null
rmsg.setField("Body", reply.getField("Body"));
}
String currsessid = RpcHandler.this.context.getSession().getId();
rmsg.setField("Session", currsessid);
if ((sessionid != null) && !currsessid.equals(sessionid))
rmsg.setField("SessionChanged", true);
//System.out.println("outgoing rpc: " + rmsg);
RpcHandler.this.context.send(rmsg);
}
catch (Exception x) {
Logger.info("Error replying to RPC request: " + x);
RpcHandler.this.context.sendInternalError();
}
}
});
}
}