/* * Copyright (c) 2010-2015, Isode Limited, London, England. * All rights reserved. */ package com.isode.stroke.presence; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; import com.isode.stroke.client.StanzaChannel; import com.isode.stroke.elements.Presence; import com.isode.stroke.elements.StatusShow; import com.isode.stroke.jid.JID; import com.isode.stroke.signals.Signal1; import com.isode.stroke.signals.SignalConnection; import com.isode.stroke.signals.Slot1; public class PresenceOracle { private final Map> entries_ = new HashMap>(); private final StanzaChannel stanzaChannel_; private final SignalConnection onPresenceReceivedSignal; private final SignalConnection onAvailableChangedSignal; public final Signal1 onPresenceChange = new Signal1(); public PresenceOracle(StanzaChannel stanzaChannel) { stanzaChannel_ = stanzaChannel; onPresenceReceivedSignal = stanzaChannel_.onPresenceReceived.connect(new Slot1() { @Override public void call(Presence p1) { handleIncomingPresence(p1); } }); onAvailableChangedSignal = stanzaChannel_.onAvailableChanged.connect(new Slot1() { @Override public void call(Boolean p1) { handleStanzaChannelAvailableChanged(p1); } }); } void delete() { onPresenceReceivedSignal.disconnect(); onAvailableChangedSignal.disconnect(); } void handleStanzaChannelAvailableChanged(boolean available) { if (available) { entries_.clear(); } } void handleIncomingPresence(Presence presence) { JID bareJID = presence.getFrom().toBare(); if (Presence.Type.Subscribe.equals(presence.getType())) { } else { Presence passedPresence = presence; if (presence.getType() == Presence.Type.Unsubscribe) { /* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */ passedPresence = new Presence(); passedPresence.setType(Presence.Type.Unavailable); passedPresence.setFrom(bareJID); passedPresence.setStatus(presence.getStatus()); } Map jidMap = entries_.get(bareJID); if (jidMap == null) jidMap = new HashMap(); if (passedPresence.getFrom().isBare() && Presence.Type.Unavailable.equals(presence.getType())) { /* Have a bare-JID only presence of offline */ jidMap.clear(); } else if (Presence.Type.Available.equals(passedPresence.getType())) { /* Don't have a bare-JID only offline presence once there are available presences */ jidMap.remove(bareJID); } if (Presence.Type.Unavailable.equals(passedPresence.getType()) && jidMap.size() > 1) { jidMap.remove(passedPresence.getFrom()); } else { jidMap.put(passedPresence.getFrom(), passedPresence); } entries_.put(bareJID, jidMap); onPresenceChange.emit(passedPresence); } } public Presence getLastPresence(final JID jid) { Map presenceMap = entries_.get(jid.toBare()); if (presenceMap == null) return null; Presence i = presenceMap.get(jid); if (i != null) { return i; } else { return null; } } public Collection getAllPresence(final JID bareJID) { Collection results = new ArrayList(); Map presenceMap = entries_.get(bareJID); if (presenceMap == null) return results; results.addAll(presenceMap.values()); return results; } public Presence getHighestPriorityPresence(final JID bareJID) { Map presenceMap = entries_.get(bareJID); if (presenceMap == null) return null; Presence highest = null; for (Presence current : presenceMap.values()) { if (highest == null || current.getPriority() > highest.getPriority() || (current.getPriority() == highest.getPriority() && StatusShow.typeToAvailabilityOrdering(current.getShow()) > StatusShow.typeToAvailabilityOrdering(highest.getShow()))) { highest = current; } } return highest; } }