| package org.jivesoftware.smackx; |
| |
| 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.PacketCollector; |
| import org.jivesoftware.smack.PacketListener; |
| import org.jivesoftware.smack.Roster; |
| import org.jivesoftware.smack.RosterEntry; |
| import org.jivesoftware.smack.SmackConfiguration; |
| import org.jivesoftware.smack.XMPPException; |
| import org.jivesoftware.smack.filter.PacketIDFilter; |
| import org.jivesoftware.smack.filter.PacketTypeFilter; |
| import org.jivesoftware.smack.packet.IQ; |
| import org.jivesoftware.smack.packet.Packet; |
| import org.jivesoftware.smack.packet.Presence; |
| import org.jivesoftware.smack.packet.Registration; |
| import org.jivesoftware.smack.util.StringUtils; |
| import org.jivesoftware.smackx.packet.DiscoverInfo; |
| import org.jivesoftware.smackx.packet.DiscoverInfo.Identity; |
| |
| /** |
| * This class provides an abstract view to gateways/transports. This class handles all |
| * actions regarding gateways and transports. |
| * @author Till Klocke |
| * |
| */ |
| public class Gateway { |
| |
| private Connection connection; |
| private ServiceDiscoveryManager sdManager; |
| private Roster roster; |
| private String entityJID; |
| private Registration registerInfo; |
| private Identity identity; |
| private DiscoverInfo info; |
| |
| Gateway(Connection connection, String entityJID){ |
| this.connection = connection; |
| this.roster = connection.getRoster(); |
| this.sdManager = ServiceDiscoveryManager.getInstanceFor(connection); |
| this.entityJID = entityJID; |
| } |
| |
| Gateway(Connection connection, String entityJID, DiscoverInfo info, Identity identity){ |
| this(connection, entityJID); |
| this.info = info; |
| this.identity = identity; |
| } |
| |
| private void discoverInfo() throws XMPPException{ |
| info = sdManager.discoverInfo(entityJID); |
| Iterator<Identity> iterator = info.getIdentities(); |
| while(iterator.hasNext()){ |
| Identity temp = iterator.next(); |
| if(temp.getCategory().equalsIgnoreCase("gateway")){ |
| this.identity = temp; |
| break; |
| } |
| } |
| } |
| |
| private Identity getIdentity() throws XMPPException{ |
| if(identity==null){ |
| discoverInfo(); |
| } |
| return identity; |
| } |
| |
| private Registration getRegisterInfo(){ |
| if(registerInfo==null){ |
| refreshRegisterInfo(); |
| } |
| return registerInfo; |
| } |
| |
| private void refreshRegisterInfo(){ |
| Registration packet = new Registration(); |
| packet.setFrom(connection.getUser()); |
| packet.setType(IQ.Type.GET); |
| packet.setTo(entityJID); |
| PacketCollector collector = |
| connection.createPacketCollector(new PacketIDFilter(packet.getPacketID())); |
| connection.sendPacket(packet); |
| Packet result = collector.nextResult(SmackConfiguration.getPacketReplyTimeout()); |
| collector.cancel(); |
| if(result instanceof Registration && result.getError()==null){ |
| Registration register = (Registration)result; |
| this.registerInfo = register; |
| } |
| } |
| |
| /** |
| * Checks if this gateway supports In-Band registration |
| * @return true if In-Band registration is supported |
| * @throws XMPPException |
| */ |
| public boolean canRegister() throws XMPPException{ |
| if(info==null){ |
| discoverInfo(); |
| } |
| return info.containsFeature("jabber:iq:register"); |
| } |
| |
| /** |
| * Returns all fields that are required to register to this gateway |
| * @return a list of required fields |
| */ |
| public List<String> getRequiredFields(){ |
| return getRegisterInfo().getRequiredFields(); |
| } |
| |
| /** |
| * Returns the name as proposed in this gateways identity discovered via service |
| * discovery |
| * @return a String of its name |
| * @throws XMPPException |
| */ |
| public String getName() throws XMPPException{ |
| if(identity==null){ |
| discoverInfo(); |
| } |
| return identity.getName(); |
| } |
| |
| /** |
| * Returns the type as proposed in this gateways identity discovered via service |
| * discovery. See {@link http://xmpp.org/registrar/disco-categories.html} for |
| * possible types |
| * @return a String describing the type |
| * @throws XMPPException |
| */ |
| public String getType() throws XMPPException{ |
| if(identity==null){ |
| discoverInfo(); |
| } |
| return identity.getType(); |
| } |
| |
| /** |
| * Returns true if the registration informations indicates that you are already |
| * registered with this gateway |
| * @return true if already registered |
| * @throws XMPPException |
| */ |
| public boolean isRegistered() throws XMPPException{ |
| return getRegisterInfo().isRegistered(); |
| } |
| |
| /** |
| * Returns the value of specific field of the registration information. Can be used |
| * to retrieve for example to retrieve username/password used on an already registered |
| * gateway. |
| * @param fieldName name of the field |
| * @return a String containing the value of the field or null |
| */ |
| public String getField(String fieldName){ |
| return getRegisterInfo().getField(fieldName); |
| } |
| |
| /** |
| * Returns a List of Strings of all field names which contain values. |
| * @return a List of field names |
| */ |
| public List<String> getFieldNames(){ |
| return getRegisterInfo().getFieldNames(); |
| } |
| |
| /** |
| * A convenience method for retrieving the username of an existing account |
| * @return String describing the username |
| */ |
| public String getUsername(){ |
| return getField("username"); |
| } |
| |
| /** |
| * A convenience method for retrieving the password of an existing accoung |
| * @return String describing the password |
| */ |
| public String getPassword(){ |
| return getField("password"); |
| } |
| |
| /** |
| * Returns instructions for registering with this gateway |
| * @return String containing instructions |
| */ |
| public String getInstructions(){ |
| return getRegisterInfo().getInstructions(); |
| } |
| |
| /** |
| * With this method you can register with this gateway or modify an existing registration |
| * @param username String describing the username |
| * @param password String describing the password |
| * @param fields additional fields like email. |
| * @throws XMPPException |
| */ |
| public void register(String username, String password, Map<String,String> fields)throws XMPPException{ |
| if(getRegisterInfo().isRegistered()) { |
| throw new IllegalStateException("You are already registered with this gateway"); |
| } |
| Registration register = new Registration(); |
| register.setFrom(connection.getUser()); |
| register.setTo(entityJID); |
| register.setType(IQ.Type.SET); |
| register.setUsername(username); |
| register.setPassword(password); |
| for(String s : fields.keySet()){ |
| register.addAttribute(s, fields.get(s)); |
| } |
| PacketCollector resultCollector = |
| connection.createPacketCollector(new PacketIDFilter(register.getPacketID())); |
| connection.sendPacket(register); |
| Packet result = |
| resultCollector.nextResult(SmackConfiguration.getPacketReplyTimeout()); |
| resultCollector.cancel(); |
| if(result!=null && result instanceof IQ){ |
| IQ resultIQ = (IQ)result; |
| if(resultIQ.getError()!=null){ |
| throw new XMPPException(resultIQ.getError()); |
| } |
| if(resultIQ.getType()==IQ.Type.ERROR){ |
| throw new XMPPException(resultIQ.getError()); |
| } |
| connection.addPacketListener(new GatewayPresenceListener(), |
| new PacketTypeFilter(Presence.class)); |
| roster.createEntry(entityJID, getIdentity().getName(), new String[]{}); |
| } |
| else{ |
| throw new XMPPException("Packet reply timeout"); |
| } |
| } |
| |
| /** |
| * A convenience method for registering or modifying an account on this gateway without |
| * additional fields |
| * @param username String describing the username |
| * @param password String describing the password |
| * @throws XMPPException |
| */ |
| public void register(String username, String password) throws XMPPException{ |
| register(username, password,new HashMap<String,String>()); |
| } |
| |
| /** |
| * This method removes an existing registration from this gateway |
| * @throws XMPPException |
| */ |
| public void unregister() throws XMPPException{ |
| Registration register = new Registration(); |
| register.setFrom(connection.getUser()); |
| register.setTo(entityJID); |
| register.setType(IQ.Type.SET); |
| register.setRemove(true); |
| PacketCollector resultCollector = |
| connection.createPacketCollector(new PacketIDFilter(register.getPacketID())); |
| connection.sendPacket(register); |
| Packet result = resultCollector.nextResult(SmackConfiguration.getPacketReplyTimeout()); |
| resultCollector.cancel(); |
| if(result!=null && result instanceof IQ){ |
| IQ resultIQ = (IQ)result; |
| if(resultIQ.getError()!=null){ |
| throw new XMPPException(resultIQ.getError()); |
| } |
| if(resultIQ.getType()==IQ.Type.ERROR){ |
| throw new XMPPException(resultIQ.getError()); |
| } |
| RosterEntry gatewayEntry = roster.getEntry(entityJID); |
| roster.removeEntry(gatewayEntry); |
| } |
| else{ |
| throw new XMPPException("Packet reply timeout"); |
| } |
| } |
| |
| /** |
| * Lets you login manually in this gateway. Normally a gateway logins you when it |
| * receives the first presence broadcasted by your server. But it is possible to |
| * manually login and logout by sending a directed presence. This method sends an |
| * empty available presence direct to the gateway. |
| */ |
| public void login(){ |
| Presence presence = new Presence(Presence.Type.available); |
| login(presence); |
| } |
| |
| /** |
| * This method lets you send the presence direct to the gateway. Type, To and From |
| * are modified. |
| * @param presence the presence used to login to gateway |
| */ |
| public void login(Presence presence){ |
| presence.setType(Presence.Type.available); |
| presence.setTo(entityJID); |
| presence.setFrom(connection.getUser()); |
| connection.sendPacket(presence); |
| } |
| |
| /** |
| * This method logs you out from this gateway by sending an unavailable presence |
| * to directly to this gateway. |
| */ |
| public void logout(){ |
| Presence presence = new Presence(Presence.Type.unavailable); |
| presence.setTo(entityJID); |
| presence.setFrom(connection.getUser()); |
| connection.sendPacket(presence); |
| } |
| |
| private class GatewayPresenceListener implements PacketListener{ |
| |
| public void processPacket(Packet packet) { |
| if(packet instanceof Presence){ |
| Presence presence = (Presence)packet; |
| if(entityJID.equals(presence.getFrom()) && |
| roster.contains(presence.getFrom()) && |
| presence.getType().equals(Presence.Type.subscribe)){ |
| Presence response = new Presence(Presence.Type.subscribed); |
| response.setTo(presence.getFrom()); |
| response.setFrom(StringUtils.parseBareAddress(connection.getUser())); |
| connection.sendPacket(response); |
| } |
| } |
| |
| } |
| } |
| |
| } |