package eu.hgross.blaubot.admin; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; import eu.hgross.blaubot.core.BlaubotConstants; import eu.hgross.blaubot.core.State; import eu.hgross.blaubot.messaging.BlaubotMessage; /** * Informs about devices and their roles (states) in the kingdom. * * TODO: use json for the map * * The status message is sent as one String in this form: * DeviceId|StateString;Device2Id|StateString; ... * * @author Henning Gross {@literal (mail.to@henning-gross.de)} * */ public class CensusMessage extends AbstractAdminMessage { private volatile Map<String, State> deviceStates; public CensusMessage(Map<String, State> deviceStates) { super(CLASSIFIER_CENSUS_MESSAGE); this.deviceStates = deviceStates; } public CensusMessage(BlaubotMessage rawMessage) { super(rawMessage); } private static String mapToString(Map<String, State> deviceStates) { StringBuffer sb = new StringBuffer(); for(Entry<String, State> entry : deviceStates.entrySet()) { sb.append(entry.getKey()); // uniqueId sb.append("|"); sb.append(entry.getValue().name()); // state sb.append(";"); } return new String(sb); } private static Map<String, State> stringToMap(String s) { Map<String, State> map = new HashMap<String, State>(); for(String data : s.split(";")) { String[] k_v = data.split("\\|"); if(k_v.length <= 1) break; String deviceUniqueId = k_v[0], stateStr = k_v[1]; map.put(deviceUniqueId, State.valueOf(stateStr)); } return map; } public static void main(String args[]) { Map<String ,State> m = new HashMap<String, State>(); m.put("test1", State.Peasant); m.put("test2", State.Prince); final CensusMessage cm = new CensusMessage(m); System.out.println(cm+""); System.out.println(m+""); System.out.println(mapToString(m)); System.out.println(stringToMap(mapToString(m))); System.out.println(new CensusMessage(cm.toBlaubotMessage())+""); for(int i=0; i<10;i++) { final int il = i; new Thread(new Runnable() { @Override public void run() { while(true) { if(il % 2 == 0) { for(Entry<String, State> e : cm.getDeviceStates().entrySet()) { System.out.println(e); }; } else { System.out.println(cm.toString()); } } } }).start(); } } @Override protected byte[] payloadToBytes() { String strToSend = mapToString(deviceStates); return strToSend.getBytes(BlaubotConstants.STRING_CHARSET); } @Override protected void setUpFromBytes(ByteBuffer messagePayloadAsBytes) { byte[] stringBytes = new byte[messagePayloadAsBytes.remaining()]; messagePayloadAsBytes.get(stringBytes); String readString = new String(stringBytes, BlaubotConstants.STRING_CHARSET); deviceStates = stringToMap(readString); } public Map<String, State> getDeviceStates() { return deviceStates; } /** * Extracts the prince's unique id from the device state map (if possible) * @return the prince's unique id string or null, if no prince */ public String extractPrinceUniqueId() { for(Entry<String, State> entry : deviceStates.entrySet()) { if(entry.getValue().equals(State.Prince)) { return entry.getKey(); } } return null; } /** * Extracts the king's unique id from the device state map * @return the king's unique id or null, if the message was empty */ public String extractKingUniqueId() { for(Entry<String, State> entry : deviceStates.entrySet()) { if(entry.getValue().equals(State.King)) { return entry.getKey(); } } if(deviceStates.size() > 0) { throw new IllegalStateException("A network needs to have exactly one king but no king was part of the census message: " + deviceStates); } return null; } @Override public String toString() { return "CensusMessage [deviceStates=" + deviceStates + "]"; } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); result = prime * result + ((deviceStates == null) ? 0 : deviceStates.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (!super.equals(obj)) return false; if (getClass() != obj.getClass()) return false; CensusMessage other = (CensusMessage) obj; if (deviceStates == null) { if (other.deviceStates != null) return false; } else if (!deviceStates.equals(other.deviceStates)) return false; return true; } }