Sushant Sushant - 5 months ago 28
Android Question

Android aSmack - How to make custom message extension for file sending?

I'm trying to implement offline file extension for my chat application. I'm using PacketExtension and EmbeddedExtensionProvider for adding and parsing custom extension. I can see that values and tags are added while sending message, but at receiver end these are absent. What i'm doing wrong ?

Sending message:

<message id="224K2-7" to="testfirzan@sushant" type="chat">
<body>hi</body>
<custom xmlns="jabber2:x2:oob2">
<url>URL</url>
<desc>Description</desc>
</custom>
</message>


Receiving message:

System.out(734): EmbeddedExtensionProvider

<message id="224K2-7" to="testfirzan@sushant" from="testsushant@sushant/Smack" type="chat">
<body>hi</body>
<custom xmlns="jabber2:x2:oob2"></custom>
</message>

File Extension description:(734): <custom xmlns="jabber2:x2:oob2"></custom>


Packet extension and provider manager code:

public class FileExtension implements PacketExtension {

public static final String ELEMENT = "custom";
public static final String NAMESPACE = "jabber2:x2:oob2";

String description;
String url;

@Override
public String getElementName() {
return "custom";
}

@Override
public String getNamespace() {
return "jabber2:x2:oob2";
}

@Override
public String toXML() {

StringBuilder builder = new StringBuilder();
builder.append("<" + getElementName() + " xmlns=\"" + getNamespace()
+ "\">");
if (url != null) {
builder.append("<url>").append(url).append("</url>");
}
if (description != null) {
builder.append("<desc>").append(description).append("</desc>");
}
builder.append("</" + getElementName() + ">");
return builder.toString();
}

public String getDescription() {
return description;
}

public void setDescription(String description) {
this.description = description;
}

public String getUrl() {
return url;
}

public void setUrl(String imageUrl) {
this.url = imageUrl;
}

public static class FileExtensionProvider extends EmbeddedExtensionProvider {

@Override
protected PacketExtension createReturnExtension(String currentElement,
String currentNamespace, Map<String, String> attributeMap,
List<? extends PacketExtension> content) {

System.out.println("EmbeddedExtensionProvider");
return new FileExtension();
}
}
}


Registering provider :

ProviderManager.getInstance().addExtensionProvider(
FileExtension.ELEMENT, FileExtension.NAMESPACE,
new FileExtension.FileExtensionProvider());


While sending message :

FileExtension fileExt = new FileExtension("URL");
fileExt.setDescription("Description");
fileExt.setUrl("URL");

msg.addExtension(fileExt);


After receiving message :

FileExtension fileExt = (FileExtension) message
.getExtension("jabber2:x2:oob2");

Log.i("File Extension description:", fileExt.toXML());

Answer

Following is the complete solution for making custom extension with aSmack:

1st i had to create PacketExtension:

public class ExtensionFile implements PacketExtension {

    public static final String ELEMENT = "file";
    public static final String NAMESPACE = "file:namespace";

    private String fileURL;
    private String fileSize;

    @Override
    public String getElementName() {
        return ELEMENT;
    }

    @Override
    public String getNamespace() {
        return NAMESPACE;
    }

    @Override
    public String toXML() {

        StringBuilder builder = new StringBuilder();
        builder.append("<" + getElementName() + " xmlns=\"" + getNamespace()
            + "\">");
        if (fileURL != null) {
            builder.append("<fileURL>").append(fileURL).append("</fileURL>");
        }
        if (fileSize != null) {
            builder.append("<fileSize>").append(fileSize).append("</fileSize>");
        }
        builder.append("</" + getElementName() + ">");
        return builder.toString();
    }

    public void setFileURL(String fileURL) {
        this.fileURL = fileURL;
    }

    public String getFileURL() {
        return fileURL;
    }

    public void setFileSize(String fileSize) {
        this.fileSize = fileSize;
    }

    public String getFileSize() {
        return fileSize;
    }
}

Then provider to parse this packet:

public class ExtensionProviderFile implements PacketExtensionProvider {

@Override
public PacketExtension parseExtension(XmlPullParser parser)
        throws Exception {

    ExtensionFile fileExt = new ExtensionFile();

    int eventType = parser.next();

    while (eventType == XmlPullParser.START_TAG) {

        String name = parser.getName();

        switch (parser.getEventType()) {

            case XmlPullParser.START_TAG:
                if (name.equals("fileURL")) {

                    fileExt.setFileURL(parser.nextText());
                } else if (name.equals("fileSize")) {

                    fileExt.setFileSize(parser.nextText());
                }
        }

        eventType = parser.next();
    }

    return fileExt;
}
}

Sending message with file extension:

private void sendMessage(String recipient, String message){

    Message msg = new Message(recipient,Message.Type.chat);
    msg.setBody(message);

    //Create extension and set values
    ExtensionFile fileExt = new ExtensionFile();
    fileExt.setFileURL("http://www.example.com/upload_files/"+ abc.jpg);
    fileExt.setFileSize(fileSize);

    //add extension to message
    msg.addExtension(fileExt);

    //send message
    xmppConnection.sendPacket(msg);
}

To receive this message implement PacketListener and override processPacket():

@Override
public void processPacket(Packet packet) {

    Message message = (Message) packet;

    //Get extension from message
    ExtensionFile extFile = (ExtensionFile) message
                    .getExtension("file:namespace");

    if (extFile != null) {

        //Get values from extension
        String filePath = extFile.getFileURL();
        String fileSize = extFile.getFileSize();

        System.out.println("Message :" + message.getBody() + " File url:" + filePath + " File size:" + fileSize);
    }
}

and add this provide before connecting to xmpp server:

ProviderManager.getInstance().addExtensionProvider(
            ExtensionFile.ELEMENT, ExtensionFile.NAMESPACE,
            new ExtensionProviderFile());