xmpp连接黑莓java

Posted

技术标签:

【中文标题】xmpp连接黑莓java【英文标题】:xmpp connection blackberry java 【发布时间】:2014-07-01 12:45:10 【问题描述】:

我能够连接 xmpp 服务器并完成登录身份验证,但是当我发送名册时,输入流 is.read() 给了我 -1 并抛出了一个异常,我现在不知道该怎么办。请帮帮我。

我的 XMppCONnection 类:

package mypackage;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.Vector;

import javax.microedition.io.ConnectionNotFoundException
 import javax.microedition.io.SecureConnection;
 import javax.microedition.io.StreamConnection;
import net.rim.device.api.io.File;
import net.rim.device.api.io.FileInputStream;
import net.rim.device.api.io.FileOutputStream;


public class XMPPConnection extends XMPPThread 

private XmlReader reader;
private XmlWriter writer;
private InputStream is;
private OutputStream os;
      FileInputStream fis;
    FileOutputStream fos;
   File file;
/**
 * If you create this object all variables will be saved and the
 * method @link #run() is started to log in on jabber server and
 * listen to parse incomming xml stanzas. Use
 * @link #addListener(XmppListener xl) to listen to events of this object.
 */

// jid must in the form "username@host"
// to login Google Talk, set port to 5223 (NOT 5222 in their offical guide) 
public XMPPConnection(Connection connection) 
    super(connection);

    this.host = connection.getHost();
    this.port = connection.getPort();
    this.username = connection.getUsername();
    this.password = connection.getPassword();
    this.resource = "mobile";
    this.myjid = this.username + "@" + this.host;
    if (connection.getServer() == null)
        this.server = host;
    else
        this.server = connection.getServer();
    this.use_ssl = connection.isSSL();
    this.connectionMaskIndex = connection.getNetworkType();


/**
 * The <code>run</code> method is called when @link XMPPConnection object is
 * created. It sets up the reader and writer, calls @link #login()
 * methode and listens on the reader to parse incomming xml stanzas.
 */
public void run()      
    try 
        this.connect();
     catch (final IOException e) 
        e.printStackTrace();
        this.connectionFailed(e.getMessage());
        return;
     catch (Exception e) 
        e.printStackTrace();
        this.connectionFailed(e.getMessage());
        return;
    

    // connected
    try 
        boolean loginSuccess = this.login();
        if (loginSuccess) 
            this.parse();

                   
     catch (final Exception e) 
        // hier entsteht der connection failed bug (Network Down)
        java.lang.System.out.println(e);
        this.connectionFailed(e.toString());
    



protected void connect() throws IOException, Exception 
    if (!use_ssl)          
        //final StreamConnection connection = (StreamConnection) Connector.open("http://" + this.server + ":" + this.port+this.connectionMask, Connector.READ_WRITE);
        ConnectionFactory connectionFactory = new ConnectionFactory("socket://" + this.server + ":" + this.port, this.connectionMaskIndex);
        StreamConnection connection = null;

        try 
            connection = (StreamConnection) connectionFactory.getNextConnection();


         catch (NoMoreTransportsException e) 
            throw new Exception("Connection failed. No transport available.");

         catch (ConnectionNotFoundException e) 
            throw new Exception("ConnectionNotFoundException:" + e.getMessage());

         catch (IllegalArgumentException e) 
            throw new Exception("IllegalArgumentException: " + e.getMessage());

         catch (IOException e) 
            throw new Exception("IOException: " + e.getMessage());

        

        is = connection.openInputStream();
        os = connection.openOutputStream();

        this.reader = new XmlReader(is);
        this.writer = new XmlWriter(os);

     else 
        //final SecureConnection sc = (SecureConnection) Connector.open("ssl://" + this.server + ":" + this.port+this.connectionMask, Connector.READ_WRITE);
        ConnectionFactory connectionFactory = new ConnectionFactory("ssl://" + this.server + ":" + this.port, this.connectionMaskIndex);
        SecureConnection sc = null;
        try 
            sc = (SecureConnection) connectionFactory.getNextConnection();

         catch (NoMoreTransportsException e) 
            throw new Exception("Connection failed. No transport available.");

         catch (ConnectionNotFoundException e) 
            throw new Exception("ConnectionNotFoundException: " + e.getMessage());

         catch (IllegalArgumentException e) 
            throw new Exception("IllegalArgumentException: " + e.getMessage());

         catch (IOException e) 
            throw new Exception("IOException: " + e.getMessage());

        

        if (sc != null) 
            //sc.setSocketOption(SocketConnection.DELAY, 1);
            //sc.setSocketOption(SocketConnection.LINGER, 0);
            is = sc.openInputStream();
            os = sc.openOutputStream();
            this.reader = new XmlReader(is);
            this.writer = new XmlWriter(os);
        

    


/**
 * Opens the connection with a stream-tag, queries authentication type and
 * sends authentication data, which is username, password and resource.
 * @return 
 * @throws Exception 
 */
protected boolean login() throws Exception 
    String msg = "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='" + this.host + "' version='1.0'>";
    os.write(msg.getBytes());
    os.flush();


    do 

        reader.next();
        if (reader.getType() == XmlReader.START_TAG && reader.getName().equals("stream:features")) 
            this.packetParser.parseFeatures(reader);
                       
     while (!(reader.getType() == XmlReader.END_TAG && reader.getName().equals("stream:features")));


    boolean loginSuccess = this.doAuthentication();


    msg = "<stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' to='" + this.host + "' version='1.0'>";
    os.write(msg.getBytes());
    os.flush();
    reader.next();
    while (true) 
        if ((reader.getType() == XmlReader.END_TAG) && reader.getName().equals("stream:features")) 
            break;
        
        reader.next();
    


    if (resource == null) 
        msg = "<iq type='set' id='res_binding'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/></iq>";
     else 
        msg = "<iq type='set' id='res_binding'><bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'><resource>" + resource + "</resource></bind></iq>";
    
    os.write(msg.getBytes());
    os.flush();

    return loginSuccess;




protected void parse() throws IOException 
    while (true) 
        int nextTag = this.reader.next();
        switch (nextTag) 
        case XmlReader.START_TAG:
            final String tmp = this.reader.getName();
            if (tmp.equals("message")) 
                this.packetParser.parseMessage(this.reader);
             else if (tmp.equals("presence")) 
                this.packetParser.parsePresence(this.reader);
             else if (tmp.equals("iq")) 
                this.packetParser.parseIq(this.reader, this.writer);
             else 
                this.packetParser.parseIgnore(this.reader);
            
            break;

        case XmlReader.END_TAG:
            this.reader.close();
            throw new IOException("Unexpected END_TAG "+this.reader.getName());

        default:
            this.reader.close();
            throw new IOException("Bad XML tag");
        
    



protected boolean doAuthentication() throws Exception 
    boolean loginSuccess = false;

    Vector mechanismList = this.packetParser.getMechanism();
     System.out.println(mechanismList.toString());
    if (mechanismList.contains("X-GOOGLE-TOKEN")) 
        // X-GOOGLE-TOKEN authorization doing. User can disable
        // google features using by deselecting corresponding
        // checkbox in profile
        String resp = this.packetParser.getGoogleToken(this.myjid, this.password);

        String msg = "<auth xmlns=\"urn:ietf:params:xml:ns:xmpp-sasl\" mechanism=\"X-GOOGLE-TOKEN\">" + resp + "</auth>";
        os.write(msg.getBytes());
        //os.flush();       

        reader.next();
        if (reader.getName().equals("success")) 
            loginSuccess = true;
            while (true) 
                if ((reader.getType() == XmlReader.END_TAG) && reader.getName().equals("success")) 
                    break;
                
                reader.next();
            
        
           


    if (mechanismList.contains("PLAIN") && loginSuccess == false) 
        String msg = "<auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>";
        byte[] auth_msg = (username + "@" + host + "\0" + username + "\0" + password).getBytes();
        msg = msg + MD5.toBase64(auth_msg) + "</auth>";
        os.write(msg.getBytes());
        os.flush();
        reader.next();
        if (reader.getName().equals("success")) 
            loginSuccess = true;
            while (true) 
                if ((reader.getType() == XmlReader.END_TAG) && reader.getName().equals("success")) 
                    break;
                
                reader.next();
            
        
    

    if (loginSuccess == false) 
        for (Enumeration e = listeners.elements(); e.hasMoreElements();) 
            XmppListener xl = (XmppListener) e.nextElement();
            xl.onAuthFailed(reader.getName() + ", failed authentication");
        
        return false;
    

    return loginSuccess;















public void getRosterVCard(String tojid) throws IOException 
    this.writer.startTag("iq");
    this.writer.attribute("id", "vc2");
    this.writer.attribute("to", tojid);
    this.writer.attribute("type", "get");
    this.writer.startTag("vCard");
    this.writer.attribute("xmlns", "vcard-temp");
    this.writer.endTag(); // vCard
    this.writer.endTag(); // iq
    this.writer.flush();



/**
 * Sends a roster query.
 * 
 * @throws java.io.IOException is thrown if @link XmlReader or @link XmlWriter
 *  throw an IOException.
 */
public void getRoster() throws IOException 



    this.writer.startTag("iq");
   //       this.writer.attribute("id", "roster");

    this.writer.attribute("type", "get");
    this.writer.startTag("query");
    this.writer.attribute("xmlns", "jabber:iq:roster");
    this.writer.endTag(); // query
    this.writer.endTag(); // iq
    this.writer.flush();

    //<iq id="qxmpp7" from="919700424402@213.204.83.20/QXmpp" type="get"><query xmlns="jabber:iq:roster"/></iq>

   

/**
 * Sends a message text to a known jid.
 * 
 * @param to the JID of the recipient
 * @param msg the message itself
 */
public void sendMessage(final String to, final String msg, final String id) 
    try 
        this.writer.startTag("message");
        this.writer.attribute("type", "chat");
        this.writer.attribute("to", to);
        this.writer.startTag("body");
        this.writer.text(msg);
        this.writer.endTag();
        this.writer.endTag();
        this.writer.flush();
     catch (final IOException e) 
        java.lang.System.out.println(e);
        this.connectionFailed();
    


/**
 * Requesting a subscription.
 * 
 * @param to the jid you want to subscribe
 */
public void subscribe(final String to) 
    this.sendPresence(to, "subscribe", null, null, 0);


/**
 * Remove a subscription.
 * 
 * @param to the jid you want to remove your subscription
 */
public void unsubscribe(final String to) 
    this.sendPresence(to, "unsubscribe", null, null, 0);


/**
 * Approve a subscription request.
 * 
 * @param to the jid that sent you a subscription request
 */
public void subscribed(final String to) 
    this.sendPresence(to, "subscribed", null, null, 0);


/**
 * Refuse/Reject a subscription request.
 * 
 * @param to the jid that sent you a subscription request
 */
public void unsubscribed(final String to) 
    this.sendPresence(to, "unsubscribed", null, null, 0);
   

/**
 * Sets your Jabber Status.
 * 
 * @param show is one of the following: <code>null</code>, chat, away,
 *        dnd, xa, invisible
 * @param status an extended text describing the actual status
 * @param priority the priority number (5 should be default)
 */
public void setStatus(String show, String status, final int priority) 
    if (show.equals("")) 
        show = null;
    
    if (status.equals("")) 
        status = null;
    
    if (show.equals("invisible")) 
        this.sendPresence(null, "invisible", null, null, priority);
     else 
        this.sendPresence(null, null, show, status, priority);
    


/**
 * Sends a presence stanza to a jid. This method can do various task but
 * it's private, please use setStatus to set your status or explicit
 * subscription methods subscribe, unsubscribe, subscribed and
 * unsubscribed to change subscriptions.
 */
public void sendPresence(final String to, final String type, final String show, final String status, final int priority) 
    try 
        this.writer.startTag("presence");
        if (type != null) 
            this.writer.attribute("type", type);
        
        if (to != null) 
            this.writer.attribute("to", to);
        
        if (show != null) 
            this.writer.startTag("show");
            this.writer.text(show);
            this.writer.endTag();
        
        if (status != null) 
            this.writer.startTag("status");
            this.writer.text(status);
            this.writer.endTag();
        
        if (priority != 0) 

            this.writer.startTag("priority");
            this.writer.text(Integer.toString(priority));
            this.writer.endTag();
            


        this.writer.endTag(); // presence
        this.writer.flush();
     catch (final IOException e) 
        java.lang.System.out.println(e);
        this.connectionFailed();
    


/**
 * Closes the stream-tag and the @link XmlWriter.
 */
public void logoff() 
    try 
        this.writer.endTag();
        this.writer.flush();
        this.writer.close();
     catch (final IOException e) 
        java.lang.System.out.println(e);
        this.connectionFailed();
    








/**
 * Save a contact to roster. This means, a message is send to jabber
 * server (which hosts your roster) to update the roster.
 * 
 * @param jid the jid of the contact
 * @param name the nickname of the contact
 * @param group the group of the contact
 * @param subscription the subscription of the contact
 */
public void saveContact(final String jid, final String name, final Enumeration group, final String subscription) 
    try 
        this.writer.startTag("iq");
        this.writer.attribute("type", "set");
        this.writer.startTag("query");
        this.writer.attribute("xmlns", "jabber:iq:roster");
        this.writer.startTag("item");
        this.writer.attribute("jid", jid);
        if (name != null) 
            this.writer.attribute("name", name);
        
        if (subscription != null) 
            this.writer.attribute("subscription", subscription);
        
        if (group != null) 
            while (group.hasMoreElements()) 
                this.writer.startTag("group");
                this.writer.text((String) group.nextElement());
                this.writer.endTag(); // group
            
        
        this.writer.endTag(); // item
        this.writer.endTag(); // query
        this.writer.endTag(); // iq
        this.writer.flush();
     catch (final IOException e) 
        java.lang.System.out.println(e);
        this.connectionFailed();
    


















/**
 * This method is used to be called on a parser or a connection error.
 * It tries to close the XML-Reader and XML-Writer one last time.
 *
 */
private void connectionFailed() 
    if (this.writer != null)
        this.writer.close();

    if (this.reader != null)
        this.reader.close();

    for (Enumeration e = listeners.elements(); e.hasMoreElements();) 
        XmppListener xl = (XmppListener) e.nextElement();
        xl.onConnFailed("");
    


private void connectionFailed(final String msg) 
    if (this.writer != null)
        this.writer.close();

    if (this.reader != null)
        this.reader.close();

    for (Enumeration e = listeners.elements(); e.hasMoreElements();) 
        XmppListener xl = (XmppListener) e.nextElement();
        xl.onConnFailed(msg);
    

;

xml 阅读器如下所示:

   public class XmlReader  
private InputStream is;

public final static int START_DOCUMENT = 0;

public final static int END_DOCUMENT = 1;

public final static int START_TAG = 2;

public final static int END_TAG = 3;

public final static int TEXT = 4;

//private Stack tags;

private boolean inside_tag;

private boolean left_angle;

private String tagName;

private String text;

private final Hashtable attributes = new Hashtable();

private int c;

private int type = START_DOCUMENT;

//public XmlReader(final InputStream in) throws IOException, UnsupportedEncodingException 
public XmlReader(final InputStream in) throws IOException 
    //reader = new InputStreamReader(in, "UTF-8");
    this.is = in;
    //this.tags = new Stack();
    this.inside_tag = false;
    this.left_angle = false;


//http://discussion.forum.nokia.com/forum/showthread.php?t=76814
//by abirr
private int getNextCharacter() throws IOException 
    int a = is.read();

    int t=a;

    if((t|0xC0)==t)
        int b = is.read();

        if( b == 0xFF ) // Check if legal
            t=-1;
        else if( b < 0x80 ) // Check for UTF8 compliancy
            throw new IOException("Bad UTF-8 Encoding encountered");

        else if((t|0xE0)==t) 
            int c = is.read();
            if( c == 0xFF ) // Check if legal
                t=-1;
            else if( c < 0x80 ) // Check for UTF8 compliancy
                throw new IOException("Bad UTF-8 Encoding encountered");
            else
                t=((a & 0x0F)<<12) | ((b & 0x3F)<<6) | (c & 0x3F);
        else
            t=((a & 0x1F)<<6)|(b&0x3F);

    

    return a;



public void close() 
    if (is != null) 
        try 
            is.close();
            is = null;
         catch (IOException e) 
            e.printStackTrace();
        
        /*try 
            reader.close();
         catch (IOException e) */
           


public int next() throws IOException 
  /*        while (!this.ready())
        try  
            java.lang.Thread.sleep(100);
         catch (InterruptedException e) */

    this.c = getNextCharacter();
    if (this.c <= ' ') 
        while (((this.c = getNextCharacter()) <= ' ') && (this.c != -1)) 
            ;
        
    
    if (this.c == -1) 
        this.type = END_DOCUMENT;
        return this.type;
    

    if (this.left_angle || (this.c == '<')) 
        this.inside_tag = true;
        // reset all
        this.tagName = null;
        this.text = null;
        this.attributes.clear();

        if (this.c == '<') 
            this.left_angle = true;
            this.c = getNextCharacter();
        
        if (this.left_angle && this.c == '/') 
            this.left_angle = false;
            this.type = END_TAG;
            this.c = getNextCharacter();
            this.tagName = this.readName('>');
         else if (this.left_angle && ((this.c == '?') || (this.c == '!'))) // ignore xml heading & // comments
            this.left_angle = false;
            while ((this.c = getNextCharacter()) != '>') 
                ;
            
            this.next();
         else 
            this.left_angle = false;
            this.type = START_TAG;
            this.tagName = this.readName(' ');

            String attribute = "";
            String value = "";
            while (this.c == ' ') 
                /*this.c = getNextCharacter();
                attribute = this.readName('=');

                int quote = getNextCharacter();//this.c = this.read(); // '''
                BTalk.debugConsole.addDebugMsg("quote: " + quote);
                this.c = getNextCharacter();
                value = this.readText(quote); //change from value = this.readText(''');
                this.c = getNextCharacter();
                this.attributes.put(attribute, value);
                BTalk.debugConsole.addDebugMsg("attributes: " + attributes);*/



                this.c = getNextCharacter();
                attribute = this.readName('=').trim();                  

                int quote = getNextCharacter();//this.c = this.read(); // '''
                if (quote == 32) 
                    while (quote == 32) 
                        quote = getNextCharacter();//this.c = this.read(); // '''

                    
                    this.c = getNextCharacter();
                    value = this.readText(quote); //change from value = this.readText(''');
                    this.c = getNextCharacter();
                    this.attributes.put(attribute, value);  

                 else 
                    this.c = getNextCharacter();
                    value = this.readText(quote); //change from value = this.readText(''');
                    this.c = getNextCharacter();
                    this.attributes.put(attribute, value);  
                

            
            if (this.c != '/') 
                this.inside_tag = false;
            
        
     else if ((this.c == '>') && this.inside_tag) // last tag ended
    
        this.type = END_TAG;
        this.inside_tag = false;
     else 
        this.tagName = null;
        this.attributes.clear();

        this.type = TEXT;
        this.text = this.readText('<');
        // fix the < dismatching problem
        this.left_angle = true;
    

    return this.type;


// NOTICE: this is only for debug use
public void parsehtml() throws IOException 
    while (true) 
        char c;
        c = (char) this.getNextCharacter();
        System.out.print(c);
    


public int getType() 
    return this.type;


public String getName() 
    return this.tagName;


public String getAttribute(final String name) 
    return (String) this.attributes.get(name);


public Enumeration getAttributes() 
    return this.attributes.keys();


public String getText() 
    return this.text;


private String readText(final int end) throws IOException 
    final StringBuffer output = new StringBuffer("");
    while (this.c != end) 
        if (this.c == '&') 
            this.c = getNextCharacter();
            switch (this.c) 
                case 'l':
                    output.append('<');
                    break;
                case 'g':
                    output.append('>');
                    break;
                case 'a':
                    if (getNextCharacter() == 'm') 
                        output.append('&');
                     else 
                        output.append('\'');
                    
                    break;
                case 'q':
                    output.append('"');
                    break;
                case 'n':
                    output.append(' ');
                    break;
                default:
                    output.append('?');
            

            while ((this.c = getNextCharacter()) != ';') 
                ;
            
        // NOTICE: Comment out these mystical codes
//           else if (this.c == '\\') 
//              // NOTICE: What this means?
//              if ((this.c = getNextCharacter()) == '<') 
//                  output.append('\\');
//                  break;
//               else 
//                  output.append((char) this.c);
//              
         else 
            output.append((char) this.c);
        
        this.c = getNextCharacter();
    
    // while((c = read()) != end);
    System.out.println(output.toString()+"");
    return output.toString();


private String readName(final int end) throws IOException 
    final StringBuffer output = new StringBuffer("");
    do 
        output.append((char) this.c);
     while (((this.c = getNextCharacter()) != end) && (this.c != '>') && (this.c != '/'));
    return output.toString();

;

【问题讨论】:

谁能帮帮我 【参考方案1】:

问题在于会话我们需要在名册之前创建会话

    String msg = "<iq type=\"set\" id=\"session_1\"><session xmlns=\"urn:ietf:params:xml:ns:xmpp-session\"/></iq>";

    try 
        os.write(msg.getBytes());
        os.flush();
     catch (IOException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
    
    try 
        reader.next();
     catch (IOException e) 
        // TODO Auto-generated catch block
        e.printStackTrace();
    
    if (reader.getName().equals("iq")) 

        while (true) 

                if((reader.getType() == XmlReader.END_TAG) && reader.getName().equals("iq"))
                
                    session=true;
                    break;
                


            try 
                reader.next();
             catch (IOException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
            
        
    
    //
now the problem is solved.thank you

【讨论】:

问题已解决。以上是我错过的代码。这在库中不可用。

以上是关于xmpp连接黑莓java的主要内容,如果未能解决你的问题,请参考以下文章

都说黑莓手机功能强大,黑莓手机到底都有啥功能?

黑莓手机将无法连接到一些HTTPS的网页。

Java 初学者 - 在 Macbook Pro 上编码(黑莓应用程序构建)

如何以编程方式阻止黑莓应用程序?

黑莓 - 使用EDGE网的HttpConnection

黑莓 8320 uncaught exception