diff --git a/server/dist/OOCSI_server.jar b/server/dist/OOCSI_server.jar index 180ea3a..a1c0230 100644 Binary files a/server/dist/OOCSI_server.jar and b/server/dist/OOCSI_server.jar differ diff --git a/server/src/nl/tue/id/oocsi/server/model/Channel.java b/server/src/nl/tue/id/oocsi/server/model/Channel.java index 0177705..f60bf83 100644 --- a/server/src/nl/tue/id/oocsi/server/model/Channel.java +++ b/server/src/nl/tue/id/oocsi/server/model/Channel.java @@ -16,11 +16,14 @@ */ public class Channel { + private static final String RETAIN_MESSAGE = "_RETAIN"; + protected final Date created = new Date(); protected final ChangeListener presence; protected final Map subChannels = new ConcurrentHashMap(); protected String token; + protected Message retainedMessage; public Channel(String token, ChangeListener changeListener) { this.token = token; @@ -95,11 +98,25 @@ public void send(Message message) { if (!subChannel.isPrivate()) { if (!message.recipient.equals(subChannel.getName())) { OOCSIServer.logEvent(message.sender, message.recipient, subChannel.getName(), message.data, - message.timestamp); + message.timestamp); } } } + // new message erases always retained message + retainedMessage = null; + + // check for retained message flag and store message + if (message.data.containsKey(RETAIN_MESSAGE)) { + Object retainTimeoutRaw = message.data.getOrDefault(RETAIN_MESSAGE, "0"); + try { + long timeout = Long.parseLong(retainTimeoutRaw.toString()); + message.validUntil = new Date(System.currentTimeMillis() + timeout); + retainedMessage = message; + } catch (Exception e) { + // do nothing + } + } } /** @@ -156,10 +173,21 @@ public String getChannelList() { public void addChannel(Channel channel) { if (!getName().equals(channel.getName()) && !subChannels.containsKey(channel.getName())) { subChannels.put(channel.getName(), channel); + + // update presence information if (!channel.isPrivate()) { presence.join(this, channel); OOCSIServer.logConnection(getName(), channel.getName(), "added channel", new Date()); } + + // send out the retained message to new client + final Message retainedMessageCopy = retainedMessage; + if (retainedMessageCopy != null && retainedMessageCopy.isValid()) { + channel.send(retainedMessageCopy); + } else { + // clear invalid or null message + retainedMessage = null; + } } } diff --git a/server/src/nl/tue/id/oocsi/server/protocol/Message.java b/server/src/nl/tue/id/oocsi/server/protocol/Message.java index 9072d77..baab285 100644 --- a/server/src/nl/tue/id/oocsi/server/protocol/Message.java +++ b/server/src/nl/tue/id/oocsi/server/protocol/Message.java @@ -34,6 +34,10 @@ public class Message implements Serializable { * data payload of message */ public Map data; + /** + * until when the message is valid (used for retained messages) + */ + public Date validUntil; /** * create message from sender and recipient @@ -86,6 +90,15 @@ public Message addData(String key, Object value) { return this; } + /** + * check whether the message is still valid + * + * @return + */ + public boolean isValid() { + return validUntil == null || validUntil.after(new Date()); + } + /* * (non-Javadoc) * @@ -93,7 +106,7 @@ public Message addData(String key, Object value) { */ public String toString() { return "{sender: " + sender + ", recipient: " + recipient + ", timestamp: " + timestamp + ", data: " + data - + "}"; + + "}"; } }