package com.voxeo.moho.presence.xmpp.impl;
import java.io.IOException;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.xml.parsers.DocumentBuilderFactory;
import org.apache.log4j.Logger;
import org.w3c.dom.Element;
import com.voxeo.moho.presence.Resource;
import com.voxeo.moho.presence.StoreRetrieveListener;
import com.voxeo.moho.presence.impl.StoreHolder;
import com.voxeo.moho.presence.impl.xmpp.XMPPPresenceStore;
import com.voxeo.moho.presence.impl.xmpp.memory.XMPPMemoryPresenceStore;
import com.voxeo.moho.presence.xmpp.Roster;
import com.voxeo.moho.presence.xmpp.RosterService;
import com.voxeo.moho.presence.xmpp.XMPPPresenceResource;
import com.voxeo.moho.presence.xmpp.XMPPPresenceService;
import com.voxeo.moho.presence.xmpp.XmppPendingNotification;
import com.voxeo.moho.spi.ExecutionContext;
import com.voxeo.moho.xmpp.RosterEvent.Ask;
import com.voxeo.moho.xmpp.RosterEvent.RosterItem;
import com.voxeo.moho.xmpp.RosterEvent.XmppSubscription;
import com.voxeo.moho.xmpp.RosterGet;
import com.voxeo.moho.xmpp.RosterSet;
import com.voxeo.moho.xmpp.XMPPAcceptableEvent.Reason;
import com.voxeo.moho.xmpp.XMPPEndpoint;
import com.voxeo.moho.xmpp.XMPPIQEvent;
import com.voxeo.moho.xmpp.XMPPMessageEvent;
import com.voxeo.moho.xmpp.XMPPPresenceEvent;
import com.voxeo.servlet.xmpp.JID;
import com.voxeo.servlet.xmpp.PresenceMessage;
import com.voxeo.servlet.xmpp.XmppFactory;
import com.voxeo.servlet.xmpp.XmppServlet;
import com.voxeo.servlet.xmpp.XmppSession;
import com.voxeo.servlet.xmpp.XmppSessionsUtil;
/**
* TODO 8.1. General Considerations(http://tools.ietf.org/html/rfc6121#page-78)
*/
public class XMPPPresenceServiceImpl implements XMPPPresenceService {
private static final Logger LOG = Logger.getLogger(XMPPPresenceServiceImpl.class);
private ExecutionContext _context;
private RosterService _rosterService;
private XMPPPresenceStore _store;
private XmppSessionsUtil _sessionUtil;
private XmppFactory _xmppFactory;
@Override
public void init(ExecutionContext context, Map<String, String> properties) throws Exception {
_rosterService = new RosterServiceImpl(this);
_context = context;
_sessionUtil = (XmppSessionsUtil) _context.getServletContext().getAttribute(XmppServlet.SESSIONUTIL);
_xmppFactory = context.getXmppFactory();
String storeImpl = properties.get(STORE_IMPL);
if (storeImpl == null) {
storeImpl = XMPPMemoryPresenceStore.class.getName();
}
try {
_store = (XMPPPresenceStore) Class.forName(storeImpl).newInstance();
_store.init(properties);
_store.addRetrieveListener(XmppPendingNotification.class, new StoreRetrieveListener<XmppPendingNotification>() {
@Override
public void onRetrieve(XmppPendingNotification resource) {
resource.setExecutionContext(_context);
}
});
_store.addRetrieveListener(Resource.class, new StoreRetrieveListener<Resource>() {
@Override
public void onRetrieve(Resource resource) {
resource.setExecutionContext(_context);
}
});
}
catch (Exception e) {
throw new IllegalArgumentException("Invalidate Presence Store implementation: " + e);
}
XmppPresenceServiceRegistrar.registerService(this);
}
@Override
public void destroy() {
_rosterService = null;
_store.destroy();
_store = null;
}
@Override
public String getName() {
return XMPPPresenceService.class.getName();
}
@Override
public void doPresence(XMPPPresenceEvent event) {
String type = event.getXmppRequest().getType();
try {
StoreHolder.setPresenceStore(_store);
// presence publish
if (isEmpty(type) || XMPPPresenceEvent.TYPE_UNAVAILABLE.equals(type)) {
doPresencePublish(event);
return;
}
// subscription
JID to = event.getXmppRequest().getTo();
if (isOutbound(event)) {
doOutboundSubscription(to, event);
}
else {
if (XMPPPresenceEvent.TYPE_PROBE.equals(event.getType())) {
doInboundPresenceProbe(event);
}
else {
doInboundSubscription(to, event);
}
}
}
catch (Exception e) {
LOG.error("Error handling " + event, e);
}
finally {
StoreHolder.setPresenceStore(null);
}
}
/**
* Check if the given string is empty.
*
* @param string
* String to check
* @return True if string is empty
*/
public static boolean isEmpty(final String string) {
if (string == null || string.trim().length() == 0 || string.equals(EMPTY)) {
return true;
}
return false;
}
public static final String EMPTY = "";
private void doPresencePublish(XMPPPresenceEvent event) throws IOException, ServletException {
JID from = event.getXmppRequest().getFrom();
XMPPPresenceResource resource = getResource(from);
if (!resource.isAvailable() && isEmpty(event.getType())) {
// After a connected resource
// sends initial presence (see Section 4.2), it is referred to as an
// "available resource".
resource.setAvailable(true);
Roster roster = _rosterService.getRoster(from.getBareJID());
// send presence probe to all subscribees
if (roster != null) {
for (RosterItem itm : roster.getItems()) {
if (itm.getSubscription() == XmppSubscription.BOTH || itm.getSubscription() == XmppSubscription.TO) {
try {
sendPresenceProbe(from, _xmppFactory.createJID(itm.getJID()));
}
catch (Exception e) {
LOG.warn("Error sending presence probe from " + from + " to " + itm.getJID(), e);
}
}
}
}
}
else if (resource.isAvailable() && event.getType().equalsIgnoreCase(XMPPPresenceEvent.TYPE_UNAVAILABLE)) {
resource.setAvailable(false);
resource.setInterested(false);
}
if (isOutbound(event)) {
Roster roster = _rosterService.getRoster(from.getBareJID());
// broadcast to all subscribers
if (roster != null) {
for (RosterItem itm : roster.getItems()) {
if (itm.getSubscription() == XmppSubscription.BOTH || itm.getSubscription() == XmppSubscription.FROM) {
sendPresence(from, _xmppFactory.createJID(itm.getJID()), event.getType(), event.getContent());
}
}
}
// //broadcast to all of the user's available
// resources, including the resource that generated the presence
// notification in the first place
sendPresence(from, from, event.getType(), event.getContent());
}
else {
sendPresence(from, event.getMessageTo(), event.getType(), event.getContent());
}
}
public void sendPresenceProbe(JID from, JID to) throws ServletException, IOException {
PresenceMessage probePresence = _xmppFactory.createPresence(from, to, XMPPPresenceEvent.TYPE_PROBE, (Element[]) null);
probePresence.send();
}
public XmppSessionsUtil getSessionUtil() {
return _sessionUtil;
}
public XmppFactory getXmppFactory() {
return _xmppFactory;
}
private void doInboundPresenceProbe(XMPPPresenceEvent event) throws IOException, ServletException {
JID contact = event.getMessageTo();
Roster roster = _rosterService.getRoster(contact);
RosterItem item = roster.getItem(event.getMessageTo().toString());
if (!isUserExist(contact)
|| (item.getSubscription() != XmppSubscription.BOTH && item.getSubscription() != XmppSubscription.FROM)) {
event.getXmppRequest().getSession().createPresence(null, XMPPPresenceEvent.TYPE_UNSUBSCRIBED, (Element[]) null).send();
}
else if (isUserMoved(contact)) {
// handle contact has moved temporarily or permanently to
// another address
}
else if (!isUserAvailable(contact)) {
sendPresence(contact.getBareJID(), event.getMessageFrom(), XMPPPresenceEvent.TYPE_UNAVAILABLE, null);
}
else {
sendPresence(contact, event.getMessageFrom(), null, null);
}
}
private boolean isUserMoved(JID contact) {
return false;
}
private void doOutboundSubscription(JID to, XMPPPresenceEvent event) throws ServletException, IOException {
// subscribe
if (XMPPPresenceEvent.TYPE_SUBSCRIBE.equalsIgnoreCase(event.getType())) {
if (to.getResource() != null) {
event.getXmppRequest().setTo(to.getBareJID());
}
if (event.getMessageFrom().getResource() != null) {
event.getXmppRequest().setFrom(event.getMessageFrom().getBareJID());
}
if (isUserInHost(to)) {
doInboundSubscription(to, event);
}
else {
routeOutboundPresence(event);
}
// ask='subscribe'
// jid='juliet@example.com'
// subscription='none'
RosterItem rosterItem = _rosterService.getRosterItem(event.getMessageFrom().toString(), to.toString());
if (rosterItem == null) {
rosterItem = _rosterService.createRosterItem(to.toString());
}
rosterItem.setAsk(Ask.SUBSCRIBE);
_rosterService.addRosterItem(event.getMessageFrom(), rosterItem);
}
// approval(from contact to user on contact's server)
else if (XMPPPresenceEvent.TYPE_SUBSCRIBED.equalsIgnoreCase(event.getType())) {
if (event.getMessageFrom().getResource() != null) {
event.getXmppRequest().setFrom(event.getMessageFrom().getBareJID());
}
if (isUserInHost(to)) {
doInboundSubscription(to, event);
}
else {
routeOutboundPresence(event);
}
// to contact's interested resources
RosterItem rosterItem = _rosterService.getRosterItem(event.getMessageFrom(), to);
if (rosterItem == null) {
rosterItem = _rosterService.createRosterItem(to);
rosterItem.setSubscription(XmppSubscription.FROM);
}
else {
if (isSubscriptionExist(to.toString(), event.getMessageFrom().toString())) {
rosterItem.setSubscription(XmppSubscription.BOTH);
}
else {
rosterItem.setSubscription(XmppSubscription.FROM);
}
}
rosterItem.setAsk(Ask.NONE);
_rosterService.addRosterItem(event.getMessageFrom(), rosterItem);
sendPresence(event.getMessageFrom(), _xmppFactory.createJID(rosterItem.getJID()), null, null);
cancelPendingNotification(to, event.getMessageFrom(), XMPPPresenceEvent.TYPE_SUBSCRIBE);
}
// cancellation
else if (XMPPPresenceEvent.TYPE_UNSUBSCRIBED.equalsIgnoreCase(event.getType())) {
// get contact's roster
Roster roster = _rosterService.getRoster(event.getMessageFrom().getBareJID());
RosterItem rosterItem = roster.getItem(event.getMessageTo().toString());
if (rosterItem == null
|| (rosterItem.getSubscription() == XmppSubscription.NONE && (rosterItem.getAsk() == Ask.NONE || rosterItem
.getAsk() == Ask.SUBSCRIBE)) || rosterItem.getSubscription() == XmppSubscription.TO) {
// do not deliver presence or presence notifications
}
else if (((rosterItem.getSubscription() == XmppSubscription.NONE && (rosterItem.getAsk() == Ask.NONE || rosterItem
.getAsk() == Ask.SUBSCRIBE)) || rosterItem.getSubscription() == XmppSubscription.TO)
&& isApproved(event.getMessageFrom(), event.getMessageTo())) {
// remove pre-approval
}
else {
// route or deliver both presence notifications of type
// "unavailable" and presence stanzas of type "unsubscribed" to the
// user and MUST send a roster push to the contact.
sendPresence(event.getMessageFrom().getBareJID(), event.getMessageTo(), XMPPPresenceEvent.TYPE_UNAVAILABLE, null);
sendPresence(event.getMessageFrom().getBareJID(), event.getMessageTo(), XMPPPresenceEvent.TYPE_UNSUBSCRIBED, null);
if (rosterItem.getSubscription() == XmppSubscription.BOTH) {
rosterItem.setSubscription(XmppSubscription.TO);
}
else {
rosterItem.setSubscription(XmppSubscription.NONE);
}
_rosterService.addRosterItem(to, rosterItem);
}
cancelPendingNotification(to, event.getMessageFrom(), XMPPPresenceEvent.TYPE_SUBSCRIBE);
}
// unsubscribe
else if (XMPPPresenceEvent.TYPE_UNSUBSCRIBE.equalsIgnoreCase(event.getType())) {
if (event.getMessageFrom().getResource() != null) {
event.getXmppRequest().setFrom(event.getMessageFrom().getBareJID());
}
// bare from and to
if (isUserInHost(to)) {
doInboundSubscription(to, event);
}
else {
routeOutboundPresence(event);
}
Roster roster = _rosterService.getRoster(event.getMessageFrom());
RosterItem rosterItem = roster.getItem(event.getMessageTo().toString());
// The user's server then MUST send a roster push with the updated
// roster item to all of the user's interested resources, where the
// subscription state is now either "none" or "from"
if (rosterItem.getSubscription() == XmppSubscription.BOTH) {
rosterItem.setSubscription(XmppSubscription.FROM);
}
else {
rosterItem.setSubscription(XmppSubscription.NONE);
}
_rosterService.addRosterItem(event.getMessageFrom(), rosterItem);
}
}
private boolean isApproved(JID messageFrom, JID messageTo) {
return false;
}
private void routeOutboundPresence(XMPPPresenceEvent event) throws ServletException, IOException {
List<Element> contents = event.getXmppRequest().getElements();
sendPresence(event.getMessageFrom(), event.getMessageTo(), event.getType(), contents);
// TODO
/*
* If a remote contact does not approve or deny the subscription request
* within some configurable amount of time, the user's server SHOULD resend
* the subscription request to the contact based on an
* implementation-specific algorithm (e.g., whenever a new resource becomes
* available for the user, or after a certain amount of time has elapsed);
* this helps to recover from transient, silent errors that might have
* occurred when the original subscription request was routed to the remote
* domain. When doing so, it is RECOMMENDED for the server to include an
* 'id' attribute so that it can track responses to the resent subscription
* request.
*/
}
private boolean isUserInHost(JID jid) {
return jid.getDomain().equals("voxeo.com");
}
private boolean isOutbound(XMPPPresenceEvent event) {
if (event.getMessageFrom().getDomain().equalsIgnoreCase("voxeo.com")) {
return true;
}
else {
return false;
}
}
private void doInboundSubscription(JID to, XMPPPresenceEvent event) throws IOException, ServletException {
if (XMPPPresenceEvent.TYPE_SUBSCRIBE.equalsIgnoreCase(event.getType())) {
// TODO check pre-approve
if (isUserExist(to)) {
if (isSubscriptionExist(event.getMessageFrom().toString(), to.toString())) {
sendPresence(event.getMessageFrom().getBareJID(), to.getBareJID(), XMPPPresenceEvent.TYPE_SUBSCRIBED, null);
}
else {
if (isUserAvailable(to)) {
sendPresence(event.getMessageFrom(), to, event.getType(), null);
}
else {
// save this subscription and trigger send when any contact is
// available until the contact either approves or denies
// the request
pendingNotification(event);
}
}
}
else {
LOG.error("Can't find user[" + to + "] for subscription from " + event.getMessageFrom());
}
}
// approval
else if (XMPPPresenceEvent.TYPE_SUBSCRIBED.equalsIgnoreCase(event.getType())) {
Roster roster = _rosterService.getRoster(event.getMessageTo());
if (roster != null && roster.getItem(event.getMessageFrom().toString()) != null) {
RosterItem rosterItem = roster.getItem(event.getMessageFrom().toString());
if (rosterItem.getSubscription() == XmppSubscription.NONE || (rosterItem.getSubscription() == XmppSubscription.FROM && rosterItem.getAsk() == Ask.SUBSCRIBE)) {
// Deliver the inbound subscription approval to all of the user's
// interested resources
try {
List<XmppSession> sessions = _sessionUtil.getSessions(event.getMessageTo().getBareJID());
for (XmppSession session : sessions) {
if (isResourceInterested(session.getRemoteJID())) {
session.createPresence(event.getMessageFrom().toString(), event.getType(), (Element[]) null).send();
}
}
}
catch (Exception e) {
LOG.error("Error do roster push", e);
}
// roster push to all of the user's interested resources
// 'subscription' attribute set to a value of "to" (if the
// subscription state was "None + Pending Out" or "None + Pending
// Out+In") or "both" (if the subscription state was "From + Pending
// Out").
if (rosterItem.getSubscription().equals(XmppSubscription.NONE)) {
rosterItem.setSubscription(XmppSubscription.TO);
}
else {
rosterItem.setSubscription(XmppSubscription.BOTH);
}
rosterItem.setAsk(Ask.NONE);
_rosterService.addRosterItem(event.getMessageTo(), rosterItem);
// deliver the available presence stanza
// received from each of the contact's available resources to each
// of the user's available resources.
JID fromJID = _xmppFactory.createJID(rosterItem.getJID());
if (isUserAvailable(to)) {
sendPresence(fromJID, to, null, null);
}
//save notification if no available resources for user and deliver it
// later
else {
pendingNotification(event);
}
}
}
else {
// silent ignore
}
}
// cancellation
else if (XMPPPresenceEvent.TYPE_UNSUBSCRIBED.equalsIgnoreCase(event.getType())) {
// user's roster
Roster roster = _rosterService.getRoster(event.getMessageTo());
if (roster != null) {
RosterItem rosterItem = roster.getItem(event.getMessageFrom().toString());
if (rosterItem != null
&& (rosterItem.getSubscription() == XmppSubscription.BOTH || rosterItem.getSubscription() == XmppSubscription.TO)) {
if (isUserAvailable(event.getMessageTo())) {
sendPresence(event.getMessageFrom(), event.getMessageTo(), event.getType(), null);
sendPresence(event.getMessageFrom(), event.getMessageTo(), XMPPPresenceEvent.TYPE_UNAVAILABLE, null);
// Initiate a roster push to all of the user's interested resources
if (rosterItem.getSubscription() == XmppSubscription.BOTH) {
rosterItem.setSubscription(XmppSubscription.FROM);
}
else {
rosterItem.setSubscription(XmppSubscription.NONE);
}
_rosterService.addRosterItem(event.getMessageTo(), rosterItem);
}
// save notification if no available resources for user and
// deliver it later
else {
pendingNotification(event);
}
}
}
else {
// silent ignore
}
}
// unsubscribe
else if (XMPPPresenceEvent.TYPE_UNSUBSCRIBE.equalsIgnoreCase(event.getType())) {
// get contact's roster
Roster roster = _rosterService.getRoster(event.getMessageTo());
RosterItem rosterItem = roster.getItem(event.getMessageFrom());
if (rosterItem.getSubscription() == XmppSubscription.BOTH
|| rosterItem.getSubscription() == XmppSubscription.FROM) {
routeOutboundPresence(event);
// Initiate a roster push to all of the contact's interested
// resources, containing an updated roster item for the user with
// the 'subscription' attribute set to a value of "none" (if the
// subscription state was "From" or "From + Pending Out") or "to"
// (if the subscription state was "Both").
if(rosterItem.getSubscription() == XmppSubscription.BOTH){
rosterItem.setSubscription(XmppSubscription.TO);
}
else if (rosterItem.getSubscription() == XmppSubscription.FROM){
rosterItem.setSubscription(XmppSubscription.NONE);
}
_rosterService.addRosterItem(to, rosterItem);
if (isUserAvailable(to)) {
sendPresence(event.getMessageFrom(), to, XMPPPresenceEvent.TYPE_UNAVAILABLE, null);
}
else {
pendingNotification(event);
}
}
else {
// If the contact's
// server is keeping track of an inbound presence subscription request
// from the user to the contact but the user is not yet in the contact's
// roster (functionally equivalent to a subscription state of "None +
// Pending In" where the contact never added the user to the contact's
// roster), then the contact's server MUST simply remove any record of
// the inbound presence subscription request (it cannot remove the user
// from the contact's roster because the user was never added to the
// contact's roster).
}
}
}
private void pendingNotification(XMPPPresenceEvent event) {
pendingNotification(event.getMessageFrom().toString(), event.getMessageTo().toString(), event.getType(), event.getContent());
}
private void pendingNotification(String from, String to, String type, List<Element> content) {
XmppPendingNotification notification = getNotification(from, to);
notification.setPresenceStanza(content);
notification.setType(to);
_store.addNotification(notification);
}
private void cancelPendingNotification(JID from, JID to, String typeSubscribe) {
XmppPendingNotification notify = (XmppPendingNotification) _store.getNotification(from.toString(), to.toString());
if (notify != null && typeSubscribe.equals(notify.getType())) {
_store.removeNotification(notify);
}
}
private void sendPresence(JID from, JID to, String type, List<Element> contents) throws ServletException, IOException {
if (isResourceAvailable(to) || XMPPPresenceEvent.TYPE_UNAVAILABLE.equalsIgnoreCase(type)) {
_xmppFactory.createPresence(from.getBareJID(), to, type,
contents == null ? null : contents.toArray(new Element[contents.size()])).send();
}
}
private void sendPresence(String from, String to, String type, List<Element> contents) throws ServletException, IOException {
sendPresence(_xmppFactory.createJID(from), _xmppFactory.createJID(to), type, contents);
}
@Override
public void doIQ(XMPPIQEvent event) {
// simply accept session request
if (event.getElement("session") != null) {
Element resElement = null;
try {
resElement = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument()
.createElementNS("urn:ietf:params:xml:ns:xmpp-session", "session");
}
catch (Exception e) {
event.reject(Reason.INTERNAL_SERVER_ERROR, e.getMessage());
return;
}
event.accept(resElement);
return;
}
try {
StoreHolder.setPresenceStore(_store);
// roster get
if (RosterGet.class.isAssignableFrom(event.getClass())) {
doRosterGet((RosterGet) event);
}
// roster set
else if (RosterSet.class.isAssignableFrom(event.getClass())) {
doRosterSet((RosterSet) event);
}
//
else {
event.reject(Reason.FEATURE_NOT_IMPLEMENTED, "Unsupported event " + event);
}
}
catch (Throwable e) {
LOG.error("Error handling " + event, e);
}
finally {
StoreHolder.setPresenceStore(null);
}
}
public void doMessage(XMPPMessageEvent event) {
try {
((XMPPEndpoint) (event.getTo())).sendRichContent(event.getFrom(), event.getContent());
}
catch (IOException e) {
LOG.error("Send message error " + event.getXmppRequest(), e);
}
}
private void doRosterSet(RosterSet event) {
if (event.getItems().size() != 1) {
event.reject(Reason.BAD_REQUEST, "Item size can't be " + event.getItems().size());
return;
}
RosterItem item = event.getItems().iterator().next();
// remove roster item
if (item.getSubscription() == XmppSubscription.REMOVE) {
Roster roster = _rosterService.getRoster(event.getMessageFrom().getBareJID());
if (roster == null || roster.getItem(item.getJID()) == null) {
event.reject(Reason.ITEM_NOT_FOUND);
return;
}
RosterItem oldItem = roster.getItem(item.getJID());
_rosterService.removeRosterItem(event.getMessageFrom().getBareJID().toString(), item);
try {
if (oldItem.getSubscription() == XmppSubscription.BOTH || oldItem.getSubscription() == XmppSubscription.TO) {
if (isUserAvailable(oldItem.getJID())) {
sendPresence(event.getMessageFrom().toString(), oldItem.getJID(), XMPPPresenceEvent.TYPE_UNSUBSCRIBE, null);
}
else {
pendingNotification(event.getMessageFrom().toString(), oldItem.getJID(), XMPPPresenceEvent.TYPE_UNSUBSCRIBE, null);
}
}
if (oldItem.getSubscription() == XmppSubscription.BOTH || oldItem.getSubscription() == XmppSubscription.FROM) {
if (isUserAvailable(event.getMessageFrom())) {
sendPresence(oldItem.getJID(), event.getMessageFrom().toString(), XMPPPresenceEvent.TYPE_UNSUBSCRIBED, null);
}
else {
pendingNotification(oldItem.getJID(), event.getMessageFrom().toString(), XMPPPresenceEvent.TYPE_UNSUBSCRIBED, null);
}
}
}
catch (Exception e) {
LOG.error("Error do presence unsubscribed send due to roster remove", e);
}
}
else {
_rosterService.addRosterItem(event.getMessageFrom().getBareJID().toString(), item);
}
event.accept();
}
private XmppPendingNotification createNotification(String from, String to) {
return new XmppPendingNotificationImpl(_context, from, to);
}
private XmppPendingNotification getNotification(String from, String to) {
XmppPendingNotification subscription = (XmppPendingNotification) _store.getNotification(from, to);
if (subscription == null) {
subscription = createNotification(from, to);
}
return subscription;
}
public boolean isSubscriptionExist(String from, String to) {
Roster roster = _rosterService.getRoster(from);
if (roster != null) {
RosterItem item = roster.getItem(to);
if (item != null
&& (item.getSubscription() == XmppSubscription.BOTH || item.getSubscription() == XmppSubscription.TO)) {
return true;
}
}
roster = _rosterService.getRoster(to);
if (roster != null) {
RosterItem item = roster.getItem(from);
if (item != null
&& (item.getSubscription() == XmppSubscription.BOTH || item.getSubscription() == XmppSubscription.FROM)) {
return true;
}
}
return false;
}
public boolean isSubscriptionExists(JID from, JID to) {
return isSubscriptionExist(from.toString(), to.toString());
}
//whether has available resources for this user
private boolean isUserAvailable(JID to) {
return isResourceAvailable(to.getBareJID());
}
private boolean isUserAvailable(String to) {
return isUserAvailable(_xmppFactory.createJID(to));
}
private boolean isUserExist(JID to) {
return true;
}
public boolean isResourceAvailable(JID jid) {
if (jid.getResource() == null) {
List<XMPPPresenceResource> resources = _store.getResourceByBareID(jid.toString());
for (XMPPPresenceResource res : resources) {
if (res.isAvailable()) {
return true;
}
}
}
XMPPPresenceResource resource = getResource(jid);
if (resource != null) {
return resource.isAvailable();
}
return false;
}
public boolean isResourceInterested(JID jid) {
if (jid.getResource() == null) {
List<XMPPPresenceResource> resources = _store.getResourceByBareID(jid.toString());
for (XMPPPresenceResource res : resources) {
if (res.isInterested()) {
return true;
}
}
}
XMPPPresenceResource resource = getResource(jid);
if (resource != null) {
return resource.isInterested();
}
return false;
}
private XMPPPresenceResource getResource(JID jid) {
XMPPPresenceResource resource = _store.getResource(jid.toString());
if (resource == null) {
resource = new XMPPPresenceResourceImpl(_context, jid);
}
return resource;
}
private void doRosterGet(RosterGet event) {
if (event.getItems().size() != 0) {
event.reject(Reason.BAD_REQUEST, "roster get should not contain items");
}
try {
Roster roster = _rosterService.getRoster(event.getMessageFrom().getBareJID());
if (roster != null) {
Element results = _rosterService.createRosterItemElement(roster == null ? new RosterItem[] {} : roster.getItems().toArray(
new RosterItem[roster.getItems().size()]));
event.accept(results);
}
else {
event.reject(Reason.ITEM_NOT_FOUND, "Can't find roster for " + event.getMessageFrom());
}
// If a connected resource or available resource
// requests the roster, it is referred to as an "interested resource".
XMPPPresenceResource resource = getResource(event.getMessageFrom());
if (!resource.isInterested()) {
resource.setInterested(true);
}
}
catch (Exception e) {
LOG.error("", e);
event.reject(Reason.INTERNAL_SERVER_ERROR, e.getMessage());
}
}
public RosterService getRosterService() {
return _rosterService;
}
public XMPPPresenceStore getStore() {
return _store;
}
}