/* * 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 opsetClass; try { opsetClass = (Class) 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); } } } }