in server/core/src/main/java/org/apache/vysper/xmpp/modules/core/im/handler/PresenceAvailabilityHandler.java [233:330]
private PresenceStanza handleOutboundAvailable(PresenceStanza presenceStanza,
ServerRuntimeContext serverRuntimeContext, SessionContext sessionContext, RosterManager rosterManager,
Entity user, ResourceRegistry registry, StanzaBroker stanzaBroker) {
boolean hasTo = presenceStanza.getCoreVerifier().attributePresent("to");
if (hasTo)
return handleOutboundDirectedPresence(presenceStanza, sessionContext, rosterManager, registry, false,
stanzaBroker);
if (!user.isResourceSet())
throw new RuntimeException("resource id not available");
String resourceId = user.getResource();
ResourceState resourceState = registry.getResourceState(resourceId);
boolean isPresenceUpdate = resourceState != null && ResourceState.isAvailable(resourceState);
// TODO in case of !isPresenceUpdate, should we check for resourceState !=
// ResourceState.AVAILABLE_INTERESTED ?
// RFC3921bis-04#4.2.2 Initial Presence
// RFC3921bis-04#4.4.2 Initial Presence
updateLatestPresence(sessionContext, user, presenceStanza);
if (!isPresenceUpdate) {
// things to be done for initial presence
// set resource state
ResourceState currentState = registry.getResourceState(resourceId);
// set to AVAILABLE, but do not override AVAILABLE_INTERESTED
registry.setResourceState(resourceId, ResourceState.makeAvailable(currentState));
}
// the presence priority is optional, but if contained, it might become relevant
// for
// message delivery (see RFC3921bis-05#8.3.1.1)
registry.setResourcePriority(resourceId, presenceStanza.getPrioritySafe());
// check for pending offline stored stanzas, and send them out
OfflineStorageProvider offlineProvider = serverRuntimeContext.getStorageProvider(OfflineStorageProvider.class);
if (offlineProvider == null) {
logger.warn("No Offline Storage Provider configured");
} else {
Collection<Stanza> offlineStanzas = offlineProvider.getStanzasFor(user);
for (Stanza stanza : offlineStanzas) {
logger.debug("Sending out delayed offline stanza");
stanzaBroker.writeToSession(stanza);
}
}
List<Entity> contacts = new ArrayList<Entity>();
Map<SubscriptionType, List<RosterItem>> itemMap = RosterUtils.getRosterItemsByState(rosterManager, user);
List<RosterItem> item_FROM = itemMap.get(SubscriptionType.FROM);
List<RosterItem> item_TO = itemMap.get(SubscriptionType.TO);
List<RosterItem> item_BOTH = itemMap.get(SubscriptionType.BOTH);
// broadcast presence from full JID to contacts
// in roster with 'subscription' either 'from' or 'both'
// TODO: ...and user is not blocking outbound presence notifications above
// TODO (for pres updates): ...and last presence stanza received from the
// contact during the user's
// presence session was not of type "error" or "unsubscribe".
List<RosterItem> rosterContacts_FROM = new ArrayList<RosterItem>();
rosterContacts_FROM.addAll(item_FROM);
rosterContacts_FROM.addAll(item_BOTH);
for (RosterItem rosterContact : rosterContacts_FROM) {
contacts.add(rosterContact.getJid());
}
// broadcast presence notification to all resources of
// current entity.
List<String> resources = registry.getAvailableResources(user);
for (String resource : resources) {
Entity otherResource = new EntityImpl(user, resource);
contacts.add(otherResource);
}
// and send them out
relayTo(user, contacts, presenceStanza, stanzaBroker);
if (!isPresenceUpdate) {
// initial presence only:
// send probes to all contacts of the current jid where
// 'subscription' is either 'to' or 'both'
// TODO: ...and jid is not blocking inbound presence notification
// TODO: optimize: don't send server-local probes when contact's presence is
// known locally
List<RosterItem> rosterContacts_TO = new ArrayList<RosterItem>();
rosterContacts_TO.addAll(item_TO);
rosterContacts_TO.addAll(item_BOTH);
for (RosterItem rosterItem : rosterContacts_TO) {
Entity contact_TO = rosterItem.getJid();
Stanza probeStanza = buildPresenceStanza(user, contact_TO, PresenceStanzaType.PROBE, null);
relayStanza(contact_TO, probeStanza, stanzaBroker);
}
}
return null;
}