Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to send custom XML data using the Smack library?

Tags:

java

xml

xmpp

smack

I'm using the Smack API in Java to connect to my XMPP server.

I want to send a customized message packet like this:

<message to="[email protected]" type="chat" MYFIELD="custom stuff">
    <body> hi </body>
    <CUSTOM_STANZA A="..." B="..."> 
        C="..." 
        D="..."
    </CUSTOM_STANZA>
</message>

I'm guessing that I create implement my own Packet with that returns this XML in it's toXML() method. But that doesn't seem to work.

Any help would be appreciated.

like image 562
BinRoot Avatar asked Jun 17 '11 15:06

BinRoot


4 Answers

I recently found out how to add custom stanza to your message. Its was quite easy once I figured it out. I just needed to extend the standard Message Class with my custom message class.

public class CustomMessage extends org.jivesoftware.smack.packet.Message {
  public CustomMessage() {
    super();
  }

  private String customStanza;

  /**
   * @param customStanza
   *            the customStanza to set
   */
  public void setCustomStanza(String customStanza) {
    this.customStanza = customStanza;
  }

  @Override
  public String toXML() {
    String XMLMessage = super.toXML();
    String XMLMessage1 = XMLMessage.substring(0, XMLMessage.indexOf(">"));
    String XMLMessage2 = XMLMessage.substring(XMLMessage.indexOf(">"));
    if (this.customStanza != null) {
      XMLMessage1 += " CustomStanza=\"" + this.customStanza + "\"";
    }

    return XMLMessage1 + XMLMessage2;
  }
}

Then use the custom class to send messages like this:

CustomMessage message = new CustomMessage();
message.setCustomStanza("my data here");
System.out.println(message.toXML());
muc.sendMessage(message);

Your XML message would then look like this:

<message id="ee7Y7-8" CustomStanza="my data here"></message>
like image 127
ngoa Avatar answered Oct 15 '22 01:10

ngoa


i don't know why you want to add custom attributes to the message. This will be problematic on the client and may cause issues on the server as well since it will not match the schema for the message stanza.

The message content, on the other hand is easily handled as @Femi said with a packet extension. You need to create a MyExtension which extends PacketExtension, and the toXML() in that class will return your custom stanza.

You can create and send your custom message by:

Message message = new Message();
message.addExtension(new MyExtension());
chat.sendMessage(message);

To read the stanza, you will want to register a provider, which will create and return your custom PacketExtension. You should take a look at the EmbeddedExtensionProvider for this as it handles the tag parsing for you, thus simplifying the process.

like image 32
Robin Avatar answered Oct 15 '22 00:10

Robin


You need to define a custom class that should implements ExtensionElement (as menitioned by @Flow)

A very detailed explanation that produces the following stanza is available in this answer

<message id='923442621149' type='chat'><body>shanraisshan</body>
<reply xmlns='shayan:reply' rText='this is custom attribute'/>
</message>

where reply is a custom extension, which contains

  1. Element (reply)
  2. Namespace (shayan:reply)

the list of default xmpp namespaces are available at Official XMPP website

like image 42
shanraisshan Avatar answered Oct 15 '22 01:10

shanraisshan


You can use a packet extension for this: unfortunately there is no good documentation or examples for using packet extensions. I've previously looked at this unresolved question which has example code but I was unable to get it working: I got no exceptions but it simply didn't work as my extension wasn't called and I moved on to just encoding my data in the body of a Message.

EDIT: for posterity, I managed to get the following code working. It uses the DOM4J classes DocumentHelper and Element.

Presence np, packet = new Presence();
        packet.setID(sessionManager.nextStreamID().toString());
        packet.setFrom(server.createJID(operator, null));
        if(!available) packet.setType(Presence.Type.unavailable);
        else packet.setType(null);

        // add the custom XML
        Element xml = DocumentHelper.createElement(QName.get("custom", "http://www.custom.com/xmpp"));
        xml.addAttribute("type", "presenceupdate");
        packet.addExtension(new PacketExtension(xml));

Mildly humorous: I ran into my own answer a year later while actually trying to solve this problem for a real project (as opposed to tinkering like I did before) and since I couldn't just abandon it I had to figure it out. I figure I'll need this answer again so here it is. SO: my memory in the sky.

EDIT: found an even simpler way of doing this:

        Element xml = packet.addChildElement("custom", "http://www.custom.com/xmpp");
        xml.addAttribute("type", "presenceupdate");

Thing to note: trying to add certain things (in my case, trying to add a delay element) resulted in the packet not being routed. Something in Openfire swallowed it, so this is something to watch for.

like image 23
Femi Avatar answered Oct 15 '22 01:10

Femi