package com.workshare.msnos.core; import java.math.BigInteger; import java.security.SecureRandom; import java.util.UUID; import com.workshare.msnos.core.payloads.NullPayload; import com.workshare.msnos.core.payloads.PongPayload; import com.workshare.msnos.core.payloads.TracePayload; import com.workshare.msnos.soup.json.Json; import com.workshare.msnos.soup.time.SystemTime; public class Message { public interface Payload { public Payload[] split(); public boolean process(Message message, Cloud.Internal internal); } public enum Status { UNKNOWN, PENDING, DELIVERED, FAILED } public enum Type { APP, PRS, DSC, PIN, PON, ACK, ENQ, FLT, QNE, HCK, TRC, CRT } private final Version version = Version.V1_0; private final UUID uuid; private final Type type; private final Iden from; private final Iden to; private final int hops; private final boolean reliable; private final long when; private final Payload data; private final String gateName; private final String sig; private final String rnd; private static final SecureRandom random = new SecureRandom(); Message(Type type, Iden from, Iden to, int hops, boolean reliable, Payload data, UUID uuid, String sig, String rnd, long when, String gate) { if (reliable && to.getType() == Iden.Type.CLD) { throw new IllegalArgumentException("Cannot create a reliable message to the whole cloud!"); } this.uuid = uuid == null ? UUID.randomUUID() : uuid; this.type = type; this.when = (when == 0 ? SystemTime.asMillis() : when); this.from = from; this.to = to; this.hops = hops; this.reliable = reliable; this.sig = sig; this.rnd = (sig == null ? null : (rnd == null ? new BigInteger(130, random).toString(32) : rnd)); this.gateName = gate; // FIXME refactor this // TODO this can be achieved in a much better way (i.e. // type.getPayload(this) here or in the builder) if (data == null) { if (type == Type.TRC) this.data = new TracePayload(from); else if (type == Type.PON) this.data = new PongPayload(); else this.data = NullPayload.INSTANCE; } else { this.data = data; } } public UUID getUuid() { return uuid; } public Version getVersion() { return version; } public Type getType() { return type; } public Iden getFrom() { return from; } public Iden getTo() { return to; } public String getSig() { return sig; } public Payload getData() { return data; } public int getHops() { return hops; } public String getRnd() { return rnd; } public boolean isReliable() { return reliable; } public long getWhen() { return when; } public String getReceivingGate() { return gateName; } @Override public String toString() { return Json.toJsonString(this); } @Override public boolean equals(Object o) { try { String jsonThis = Json.toJsonString(this); String jsonThat = Json.toJsonString(o); return jsonThis.equals(jsonThat); } catch (Exception any) { return false; } } @Override public int hashCode() { int result = uuid != null ? uuid.hashCode() : 0; result = 31 * result + (type != null ? type.hashCode() : 0); result = 31 * result + (from != null ? from.hashCode() : 0); result = 31 * result + (to != null ? to.hashCode() : 0); result = 31 * result + (sig != null ? sig.hashCode() : 0); result = 31 * result + (rnd != null ? rnd.hashCode() : 0); return result; } public Message data(Payload load) { return new Message(type, from, to, hops, reliable, load, uuid, sig, rnd, when, gateName); } public Message hopped() { return new Message(type, from, to, hops - 1, reliable, data, uuid, sig, rnd, when, gateName); } public Message withHops(int hops) { if (hops == this.hops) return this; else return new Message(type, from, to, hops, reliable, data, uuid, sig, rnd, when, gateName); } public Message signed(String keyId, String signature) { String sign = keyId + ":" + signature; return new Message(type, from, to, hops, reliable, data, uuid, sign, rnd, when, gateName); } public Message fromGate(String newGateName) { if (newGateName != null || gateName != null) { return new Message(type, from, to, hops - 1, reliable, data, uuid, sig, rnd, when, newGateName); } else { return this; } } }