/* ************************************************************************
#
# 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.bus;
import divconq.bus.Message;
import divconq.bus.net.StreamMessage;
import divconq.lang.op.OperationResult;
import divconq.struct.ListStruct;
import divconq.struct.RecordStruct;
import divconq.struct.Struct;
import divconq.work.TaskRun;
public class MessageUtil {
static public Message success(String... flds) {
Message m = new Message();
if (flds.length > 0) {
RecordStruct body = new RecordStruct();
String name = null;
for (String o : flds) {
if (o == null)
continue;
if (name != null) {
body.setField(name, o);
name = null;
}
else {
name = o;
}
}
m.setField("Body", body);
}
return m;
}
public static Message success(Struct body) {
Message m = new Message();
m.setField("Body", body);
return m;
}
// TODO discourage use of these following - use OC .toLogMessage(); instead
static public Message error(int code, String msg) {
OperationResult or = new OperationResult();
or.error(code, msg);
return or.toLogMessage();
}
static public Message errorTr(int code, Object... params) {
OperationResult or = new OperationResult();
or.errorTr(code, params);
return or.toLogMessage();
}
static public Message fromRecord(RecordStruct msg) {
Message m = new Message();
m.copyFields(msg);
return m;
}
static boolean addressReply(Message msg, RecordStruct original) {
if ((msg == null) || original.isFieldEmpty("RespondTo"))
return false;
msg.setField("ToHub", original.getFieldAsString("FromHub"));
msg.setField("Service", original.getFieldAsString("RespondTo"));
msg.setField("Feature", "Reply");
msg.setField("Op", "Deliver");
msg.setField("Tag", original.getFieldAsString("RespondTag"));
return true;
}
static public StreamMessage streamError(int code, String msg) {
OperationResult or = new OperationResult();
or.error(code, msg);
return MessageUtil.streamMessages(or);
}
static public StreamMessage streamErrorTr(int code, Object... params) {
OperationResult or = new OperationResult();
or.errorTr(code, params);
return MessageUtil.streamMessages(or);
}
static public StreamMessage streamMessages(OperationResult ri) {
StreamMessage m = new StreamMessage();
if (ri != null)
m.setField("Messages", ri.getMessages());
return m;
}
static public StreamMessage streamFromRecord(RecordStruct msg) {
StreamMessage m = new StreamMessage();
m.copyFields(msg);
return m;
}
static public void streamAddressReply(RecordStruct msg, RecordStruct original) {
if (msg == null)
return;
msg.setField("ToHub", original.getFieldAsString("Hub"));
msg.setField("ToSession", original.getFieldAsString("Session"));
msg.setField("ToChannel", original.getFieldAsString("Channel"));
}
// assumes body will be in StreamMessage format
static public void streamAddressReply(Message msg, RecordStruct original) {
if (msg == null)
return;
msg.withToHub(original.getFieldAsString("Hub"));
RecordStruct body = msg.getFieldAsRecord("Body");
if (body == null) {
body = new RecordStruct();
msg.setField("Body", body);
}
body.setField("ToHub", original.getFieldAsString("Hub"));
body.setField("ToSession", original.getFieldAsString("Session"));
body.setField("ToChannel", original.getFieldAsString("Channel"));
}
public static StreamMessage streamFinal() {
return new StreamMessage("Final");
}
public static Message message(TaskRun request) {
return (Message) request.getTask().getParams();
}
public static RecordStruct bodyAsRecord(TaskRun request) {
Message msg = (Message) request.getTask().getParams();
return msg.getFieldAsRecord("Body");
}
public static ListStruct bodyAsList(TaskRun request) {
Message msg = (Message) request.getTask().getParams();
return msg.getFieldAsList("Body");
}
// search backward through log to find an error, if we hit a message with an Exit tag then
// stop, as Exit resets Error (unless it is an error itself)
// similar to findExitEntry but stops after last Error as we don't need to loop through all
static public boolean hasErrors(RecordStruct rec) {
ListStruct msgs = rec.getFieldAsList("Messages");
if (msgs == null)
return false;
for (int i = msgs.getSize() - 1; i >= 0; i--) {
RecordStruct msg = (RecordStruct) msgs.getItem(i);
if ("Error".equals(msg.getFieldAsString("Level")))
return true;
if (msg.hasField("Tags")) {
ListStruct tags = msg.getFieldAsList("Tags");
if (tags.stringStream().anyMatch(tag -> tag.equals("Exit")))
break;
}
}
return false;
}
static public long getCode(RecordStruct rec) {
RecordStruct entry = MessageUtil.findExitEntry(rec);
if (entry == null)
return 0;
return entry.getFieldAsInteger("Code", 0);
}
static public String getMessage(RecordStruct rec) {
RecordStruct entry = MessageUtil.findExitEntry(rec);
if (entry == null)
return null;
return entry.getFieldAsString("Message");
}
static public RecordStruct findExitEntry(RecordStruct rec) {
return MessageUtil.findExitEntry(rec, 0, -1);
}
// search backward through log to find an exit, if we hit a message with an Exit tag then
// stop, as Exit resets Error. now return the first error after Exit. if no errors after
// then return Exit
static public RecordStruct findExitEntry(RecordStruct rec, int msgStart, int msgEnd) {
ListStruct msgs = rec.getFieldAsList("Messages");
if (msgs == null)
return null;
if (msgEnd == -1)
msgEnd = msgs.getSize();
RecordStruct firsterror = null;
for (int i = msgEnd - 1; i >= msgStart; i--) {
RecordStruct msg = (RecordStruct) msgs.getItem(i);
if ("Error".equals(msg.getFieldAsString("Level")))
firsterror = msg;
if (msg.hasField("Tags")) {
ListStruct tags = msg.getFieldAsList("Tags");
if (tags.stringStream().anyMatch(tag -> tag.equals("Exit")))
return (firsterror != null) ? firsterror : msg;
}
}
return firsterror;
}
}