/*
* SIP Communicator, the OpenSource Java VoIP and Instant Messaging client.
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package net.java.sip.communicator.impl.protocol.jabber;
import java.util.*;
import org.jivesoftware.smack.util.StringUtils;
import net.java.sip.communicator.impl.protocol.jabber.extensions.caps.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
/**
* Represents an OperationSet to query the OperationSets
* supported for a specific Jabber Contact. The OperationSets
* reported as supported for a specific Jabber Contact are considered
* by the associated protocol provider to be capabilities possessed by the
* Jabber Contact in question.
*
* @author Lubomir Marinov
*/
public class OperationSetContactCapabilitiesJabberImpl
extends AbstractOperationSetContactCapabilities
implements UserCapsNodeListener
{
/**
* The Logger used by the
* OperationSetContactCapabilitiesJabberImpl class and its
* instances for logging output.
*/
private static final Logger logger
= Logger.getLogger(OperationSetContactCapabilitiesJabberImpl.class);
/**
* The list of OperationSet capabilities presumed to be supported
* by a Contact when it is offline.
*/
private static final Set>
OFFLINE_OPERATION_SETS
= new HashSet>();
/**
* The Map which associates specific OperationSet classes
* with the features to be supported by a Contact in order to
* consider the Contact to possess the respective
* OperationSet capability.
*/
private static final Map, String[]>
OPERATION_SETS_TO_FEATURES
= new HashMap, String[]>();
static
{
OFFLINE_OPERATION_SETS.add(OperationSetBasicInstantMessaging.class);
OPERATION_SETS_TO_FEATURES.put(
OperationSetBasicTelephony.class,
new String[]
{
ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE,
ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RTP,
ProtocolProviderServiceJabberImpl.URN_XMPP_JINGLE_RTP_AUDIO
});
}
/**
* The EntityCapsManager associated with the
* discoveryManager of {@link #parentProvider}.
*/
private EntityCapsManager capsManager;
/**
* Initializes a new OperationSetContactCapabilitiesJabberImpl
* instance which is to be provided by a specific
* ProtocolProviderServiceJabberImpl.
*
* @param parentProvider the ProtocolProviderServiceJabberImpl
* which will provide the new instance
*/
public OperationSetContactCapabilitiesJabberImpl(
ProtocolProviderServiceJabberImpl parentProvider)
{
super(parentProvider);
}
/**
* Gets the OperationSet corresponding to the specified
* Class and supported by the specified Contact. If the
* returned value is non-null, it indicates that the
* Contact is considered by the associated protocol provider to
* possess the opsetClass capability. Otherwise, the associated
* protocol provider considers contact to not have the
* opsetClass capability.
*
* @param the type extending OperationSet for which the
* specified contact is to be checked whether it possesses it as a
* capability
* @param contact the Contact for which the opsetClass
* capability is to be queried
* @param opsetClass the OperationSet Class for which the
* specified contact is to be checked whether it possesses it as a
* capability
* @param online true if contact is online; otherwise,
* false
* @return the OperationSet corresponding to the specified
* opsetClass which is considered by the associated protocol
* provider to be possessed as a capability by the specified
* contact; otherwise, null
* @see AbstractOperationSetContactCapabilities#getOperationSet(Contact,
* Class)
*/
@Override
protected U getOperationSet(
Contact contact,
Class opsetClass,
boolean online)
{
U opset = parentProvider.getOperationSet(opsetClass);
if (opset == null)
return null;
/*
* If the specified contact is offline, don't query its features (they
* should fail anyway).
*/
if (!online)
{
if (OFFLINE_OPERATION_SETS.contains(opsetClass))
return opset;
else
return null;
}
/*
* If we know the features required for the support of opsetClass, check
* whether the contact supports them. Otherwise, presume the contact
* possesses the opsetClass capability in light of the fact that we miss
* any knowledge of the opsetClass whatsoever.
*/
if (OPERATION_SETS_TO_FEATURES.containsKey(opsetClass))
{
String[] features = OPERATION_SETS_TO_FEATURES.get(opsetClass);
/*
* Either we've completely disabled the opsetClass capability by
* mapping it to the null list of features or we've mapped it to an
* actual list of features which are to be checked whether the
* contact supports them.
*/
if ((features == null)
|| ((features.length != 0)
&& !parentProvider.isFeatureListSupported(
parentProvider.getFullJid(contact),
features)))
opset = null;
}
return opset;
}
/**
* Gets the OperationSets supported by a specific Contact.
* The returned OperationSets are considered by the associated
* protocol provider to capabilities possessed by the specified
* contact.
*
* @param contact the Contact for which the supported
* OperationSet capabilities are to be retrieved
* @param online true if contact is online; otherwise,
* false
* @return a Map listing the OperationSets considered by
* the associated protocol provider to be supported by the specified
* contact (i.e. to be possessed as capabilities). Each supported
* OperationSet capability is represented by a Map.Entry
* with key equal to the OperationSet class name and value equal to
* the respective OperationSet instance
* @see AbstractOperationSetContactCapabilities#getSupportedOperationSets(
* Contact)
*/
@Override
@SuppressWarnings("unchecked")
protected Map getSupportedOperationSets(
Contact contact,
boolean online)
{
Map supportedOperationSets
= super.getSupportedOperationSets(contact, online);
int supportedOperationSetCount = supportedOperationSets.size();
Map contactSupportedOperationSets
= new HashMap(supportedOperationSetCount);
if (supportedOperationSetCount != 0)
{
for (Map.Entry supportedOperationSetEntry
: supportedOperationSets.entrySet())
{
String opsetClassName = supportedOperationSetEntry.getKey();
Class extends OperationSet> opsetClass;
try
{
opsetClass
= (Class extends OperationSet>)
Class.forName(opsetClassName);
}
catch (ClassNotFoundException cnfex)
{
opsetClass = null;
logger.error(
"Failed to get OperationSet class for name: "
+ opsetClassName,
cnfex);
}
if (opsetClass != null)
{
OperationSet opset
= getOperationSet(contact, opsetClass, online);
if (opset != null)
{
contactSupportedOperationSets.put(
opsetClassName,
opset);
}
}
}
}
return contactSupportedOperationSets;
}
/**
* Sets the EntityCapsManager which is associated with the
* discoveryManager of {@link #parentProvider}.
*
* @param capsManager the EntityCapsManager which is associated
* with the discoveryManager of {@link #parentProvider}
*/
private void setCapsManager(EntityCapsManager capsManager)
{
if (this.capsManager != capsManager)
{
if (this.capsManager != null)
this.capsManager.removeUserCapsNodeListener(this);
this.capsManager = capsManager;
if (this.capsManager != null)
this.capsManager.addUserCapsNodeListener(this);
}
}
/**
* Sets the ScServiceDiscoveryManager which is the
* discoveryManager of {@link #parentProvider}.
*
* @param discoveryManager the ScServiceDiscoveryManager which is
* the discoveryManager of {@link #parentProvider}
*/
void setDiscoveryManager(ScServiceDiscoveryManager discoveryManager)
{
setCapsManager(
(discoveryManager == null)
? null
: discoveryManager.getCapsManager());
}
/**
* Notifies this listener that an EntityCapsManager has added a
* record for a specific user about the caps node the user has.
*
* @param user the user (full JID)
* @param node the entity caps node#ver
* @see UserCapsNodeListener#userCapsNodeAdded(String, String)
*/
public void userCapsNodeAdded(String user, String node)
{
/*
* It doesn't matter to us whether a caps node has been added or removed
* for the specified user because we report all changes.
*/
userCapsNodeRemoved(user, node);
}
/**
* Notifies this listener that an EntityCapsManager has removed a
* record for a specific user about the caps node the user has.
*
* @param user the user (full JID)
* @param node the entity caps node#ver
* @see UserCapsNodeListener#userCapsNodeRemoved(String, String)
*/
public void userCapsNodeRemoved(String user, String node)
{
OperationSetPresence opsetPresence
= parentProvider.getOperationSet(OperationSetPresence.class);
if (opsetPresence != null)
{
String jid = StringUtils.parseBareAddress(user);
Contact contact = opsetPresence.findContactByID(jid);
if (contact != null)
{
fireContactCapabilitiesEvent(
contact,
ContactCapabilitiesEvent.SUPPORTED_OPERATION_SETS_CHANGED);
}
}
}
}