How to send custom XML data using the Smack library?
Asked Answered
P

4

11

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.

Perilymph answered 17/6, 2011 at 15:16 Comment(2)
As mentioned by Robin: Never add custom attributes to top level stanza elements. See also XEP-134. This is a mistake often made.Vernacularism
The how is not important, the why is. YOU SHOULD NEVER DO THIS!Moulton
T
1

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

Teteak answered 7/9, 2016 at 8:4 Comment(1)
No, the custom class should implement ExtensionElementVernacularism
M
7

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.

Moulton answered 17/6, 2011 at 18:19 Comment(2)
I'd like to point in this context to xmpp.org/extensions/xep-0134.html#xmpp which explains why it's a bad idea to add custom message attributes.Vernacularism
hi robin , can i know what is this new MyExtension()? can provide that classOctofoil
W
4

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>
Worms answered 24/1, 2012 at 17:32 Comment(3)
This is the best answer to understand custom stanza creation. Helped me lot...Thnx buddies.Damian
Never subclass Smack's Message. If you think you need to do so, you are doing something wrong. Message is meant to be extended by using PacketExtensionVernacularism
org.jivesoftware.smack.packet.Message is Final class now. ... public final class Message extends Stanza implements TypedCloneable<Message>.Openminded
P
2

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.

Piscary answered 17/6, 2011 at 15:24 Comment(2)
When I add a packet extension, I can add my <CUSTOM_STANZA ...> so that's fine and working. But what I really want to do is edit the message stanza to have a MYFIELD="custom stuff". For the life of my I can't figure out how to customize this message header to also include my custom field.Perilymph
Openfire seems to drop some packets with empty bodies. Add some non-whitespace text to the body.Mashe
T
1

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

Teteak answered 7/9, 2016 at 8:4 Comment(1)
No, the custom class should implement ExtensionElementVernacularism

© 2022 - 2024 — McMap. All rights reserved.