package org.jivesoftware.smackx; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.jivesoftware.smack.Connection; import org.jivesoftware.smack.Roster; import org.jivesoftware.smack.RosterEntry; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smackx.packet.DiscoverInfo; import org.jivesoftware.smackx.packet.DiscoverItems; import org.jivesoftware.smackx.packet.DiscoverInfo.Identity; import org.jivesoftware.smackx.packet.DiscoverItems.Item; /** * This class is the general entry point to gateway interaction (XEP-0100). * This class discovers available gateways on the users servers, and * can give you also a list of gateways the you user is registered with which * are not on his server. All actual interaction with a gateway is handled in the * class {@see Gateway}. * @author Till Klocke * */ public class GatewayManager { private static Map<Connection,GatewayManager> instances = new HashMap<Connection,GatewayManager>(); private ServiceDiscoveryManager sdManager; private Map<String,Gateway> localGateways = new HashMap<String,Gateway>(); private Map<String,Gateway> nonLocalGateways = new HashMap<String,Gateway>(); private Map<String,Gateway> gateways = new HashMap<String,Gateway>(); private Connection connection; private Roster roster; private GatewayManager(){ } /** * Creates a new instance of GatewayManager * @param connection * @throws XMPPException */ private GatewayManager(Connection connection) throws XMPPException{ this.connection = connection; this.roster = connection.getRoster(); sdManager = ServiceDiscoveryManager.getInstanceFor(connection); } /** * Loads all gateways the users server offers * @throws XMPPException */ private void loadLocalGateways() throws XMPPException{ DiscoverItems items = sdManager.discoverItems(connection.getHost()); Iterator<Item> iter = items.getItems(); while(iter.hasNext()){ String itemJID = iter.next().getEntityID(); discoverGateway(itemJID); } } /** * Discovers {@link DiscoveryInfo} and {@link DiscoveryInfo.Identity} of a gateway * and creates a {@link Gateway} object representing this gateway. * @param itemJID * @throws XMPPException */ private void discoverGateway(String itemJID) throws XMPPException{ DiscoverInfo info = sdManager.discoverInfo(itemJID); Iterator<Identity> i = info.getIdentities(); while(i.hasNext()){ Identity identity = i.next(); String category = identity.getCategory(); if(category.toLowerCase().equals("gateway")){ gateways.put(itemJID, new Gateway(connection,itemJID)); if(itemJID.contains(connection.getHost())){ localGateways.put(itemJID, new Gateway(connection,itemJID,info,identity)); } else{ nonLocalGateways.put(itemJID, new Gateway(connection,itemJID,info,identity)); } break; } } } /** * Loads all getways which are in the users roster, but are not supplied by the * users server * @throws XMPPException */ private void loadNonLocalGateways() throws XMPPException{ if(roster!=null){ for(RosterEntry entry : roster.getEntries()){ if(entry.getUser().equalsIgnoreCase(StringUtils.parseServer(entry.getUser())) && !entry.getUser().contains(connection.getHost())){ discoverGateway(entry.getUser()); } } } } /** * Returns an instance of GatewayManager for the given connection. If no instance for * this connection exists a new one is created and stored in a Map. * @param connection * @return an instance of GatewayManager * @throws XMPPException */ public GatewayManager getInstanceFor(Connection connection) throws XMPPException{ synchronized(instances){ if(instances.containsKey(connection)){ return instances.get(connection); } GatewayManager instance = new GatewayManager(connection); instances.put(connection, instance); return instance; } } /** * Returns a list of gateways which are offered by the users server, wether the * user is registered to them or not. * @return a List of Gateways * @throws XMPPException */ public List<Gateway> getLocalGateways() throws XMPPException{ if(localGateways.size()==0){ loadLocalGateways(); } return new ArrayList<Gateway>(localGateways.values()); } /** * Returns a list of gateways the user has in his roster, but which are offered by * remote servers. But note that this list isn't automatically refreshed. You have to * refresh is manually if needed. * @return a list of gateways * @throws XMPPException */ public List<Gateway> getNonLocalGateways() throws XMPPException{ if(nonLocalGateways.size()==0){ loadNonLocalGateways(); } return new ArrayList<Gateway>(nonLocalGateways.values()); } /** * Refreshes the list of gateways offered by remote servers. * @throws XMPPException */ public void refreshNonLocalGateways() throws XMPPException{ loadNonLocalGateways(); } /** * Returns a Gateway object for a given JID. Please note that it is not checked if * the JID belongs to valid gateway. If this JID doesn't belong to valid gateway * all operations on this Gateway object should fail with a XMPPException. But there is * no guarantee for that. * @param entityJID * @return a Gateway object */ public Gateway getGateway(String entityJID){ if(localGateways.containsKey(entityJID)){ return localGateways.get(entityJID); } if(nonLocalGateways.containsKey(entityJID)){ return nonLocalGateways.get(entityJID); } if(gateways.containsKey(entityJID)){ return gateways.get(entityJID); } Gateway gateway = new Gateway(connection,entityJID); if(entityJID.contains(connection.getHost())){ localGateways.put(entityJID, gateway); } else{ nonLocalGateways.put(entityJID, gateway); } gateways.put(entityJID, gateway); return gateway; } }