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;
}
}