From d44debab6726edbac07901a2b94a07f2ef4771ee Mon Sep 17 00:00:00 2001
From: steckbrief <steckbrief@chefmail.de>
Date: Fri, 15 Jan 2016 21:57:36 +0100
Subject: [PATCH] Introducing some specialized IqPacketGenerators -
 IqPacketGenerator - PubSubPacketGenerator - AvatarPacketGenerator

---
 .../generator/IqGenerator.java                |  60 ---------
 .../parser/AbstractParser.java                |   8 --
 .../conversationsplus/parser/IqParser.java    |  13 --
 .../services/AvatarService.java               |  13 +-
 .../xmpp/avatar/AvatarPacketGenerator.java    | 124 ++++++++++++++++++
 .../xmpp/avatar/AvatarPacketParser.java       |  29 ++++
 .../xmpp/pubsub/PubSubPacket.java             |  33 +++++
 .../xmpp/pubsub/PubSubPacketGenerator.java    |  32 +++++
 .../xmpp/pubsub/PubSubPacketParser.java       |  27 ++++
 .../xmpp/stanzas/IqPacketGenerator.java       |  31 +++++
 10 files changed, 283 insertions(+), 87 deletions(-)
 create mode 100644 src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarPacketGenerator.java
 create mode 100644 src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarPacketParser.java
 create mode 100644 src/main/java/de/thedevstack/conversationsplus/xmpp/pubsub/PubSubPacket.java
 create mode 100644 src/main/java/de/thedevstack/conversationsplus/xmpp/pubsub/PubSubPacketGenerator.java
 create mode 100644 src/main/java/de/thedevstack/conversationsplus/xmpp/pubsub/PubSubPacketParser.java
 create mode 100644 src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacketGenerator.java

diff --git a/src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java b/src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java
index 2fd9071e..8f6b128f 100644
--- a/src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java
+++ b/src/main/java/de/thedevstack/conversationsplus/generator/IqGenerator.java
@@ -42,58 +42,6 @@ public class IqGenerator extends AbstractGenerator {
 		return packet;
 	}
 
-	protected static IqPacket publish(final String node, final Element item) {
-		final IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
-		final Element pubsub = packet.addChild("pubsub",
-				"http://jabber.org/protocol/pubsub");
-		final Element publish = pubsub.addChild("publish");
-		publish.setAttribute("node", node);
-		publish.addChild(item);
-		return packet;
-	}
-
-	protected static IqPacket retrieve(String node, Element item) {
-		final IqPacket packet = new IqPacket(IqPacket.TYPE.GET);
-		final Element pubsub = packet.addChild("pubsub",
-				"http://jabber.org/protocol/pubsub");
-		final Element items = pubsub.addChild("items");
-		items.setAttribute("node", node);
-		if (item != null) {
-			items.addChild(item);
-		}
-		return packet;
-	}
-
-	public static IqPacket publishAvatar(Avatar avatar) {
-		final Element item = new Element("item");
-		item.setAttribute("id", avatar.sha1sum);
-		final Element data = item.addChild("data", "urn:xmpp:avatar:data");
-		data.setContent(avatar.image);
-		return publish("urn:xmpp:avatar:data", item);
-	}
-
-	public static IqPacket publishAvatarMetadata(final Avatar avatar) {
-		final Element item = new Element("item");
-		item.setAttribute("id", avatar.sha1sum);
-		final Element metadata = item
-			.addChild("metadata", "urn:xmpp:avatar:metadata");
-		final Element info = metadata.addChild("info");
-		info.setAttribute("bytes", avatar.size);
-		info.setAttribute("id", avatar.sha1sum);
-		info.setAttribute("height", avatar.height);
-		info.setAttribute("width", avatar.height);
-		info.setAttribute("type", avatar.type);
-		return publish("urn:xmpp:avatar:metadata", item);
-	}
-
-	public static IqPacket retrievePepAvatar(final Avatar avatar) {
-		final Element item = new Element("item");
-		item.setAttribute("id", avatar.sha1sum);
-		final IqPacket packet = retrieve("urn:xmpp:avatar:data", item);
-		packet.setTo(avatar.owner);
-		return packet;
-	}
-
 	public static IqPacket retrieveVcardAvatar(final Avatar avatar) {
 		final IqPacket packet = new IqPacket(IqPacket.TYPE.GET);
 		packet.setTo(avatar.owner);
@@ -101,14 +49,6 @@ public class IqGenerator extends AbstractGenerator {
 		return packet;
 	}
 
-	public static IqPacket retrieveAvatarMetaData(final Jid to) {
-		final IqPacket packet = retrieve("urn:xmpp:avatar:metadata", null);
-		if (to != null) {
-			packet.setTo(to);
-		}
-		return packet;
-	}
-
 	public IqPacket queryMessageArchiveManagement(final MessageArchiveService.Query mam) {
 		final IqPacket packet = new IqPacket(IqPacket.TYPE.SET);
 		final Element query = packet.query("urn:xmpp:mam:0");
diff --git a/src/main/java/de/thedevstack/conversationsplus/parser/AbstractParser.java b/src/main/java/de/thedevstack/conversationsplus/parser/AbstractParser.java
index fe6522a3..1b520bbe 100644
--- a/src/main/java/de/thedevstack/conversationsplus/parser/AbstractParser.java
+++ b/src/main/java/de/thedevstack/conversationsplus/parser/AbstractParser.java
@@ -87,12 +87,4 @@ public abstract class AbstractParser {
 			}
 		}
 	}
-
-	protected static String avatarData(Element items) {
-		Element item = items.findChild("item");
-		if (item == null) {
-			return null;
-		}
-		return item.findChildContent("data", "urn:xmpp:avatar:data");
-	}
 }
diff --git a/src/main/java/de/thedevstack/conversationsplus/parser/IqParser.java b/src/main/java/de/thedevstack/conversationsplus/parser/IqParser.java
index fc764a88..f7f56f79 100644
--- a/src/main/java/de/thedevstack/conversationsplus/parser/IqParser.java
+++ b/src/main/java/de/thedevstack/conversationsplus/parser/IqParser.java
@@ -58,19 +58,6 @@ public class IqParser extends AbstractParser implements OnIqPacketReceived {
 		mXmppConnectionService.updateRosterUi();
 	}
 
-	public static String avatarData(final IqPacket packet) {
-		final Element pubsub = packet.findChild("pubsub",
-				"http://jabber.org/protocol/pubsub");
-		if (pubsub == null) {
-			return null;
-		}
-		final Element items = pubsub.findChild("items");
-		if (items == null) {
-			return null;
-		}
-		return AbstractParser.avatarData(items);
-	}
-
 	@Override
 	public void onIqPacketReceived(final Account account, final IqPacket packet) {
 		if (packet.hasChild("query", Xmlns.ROSTER) && packet.fromServer(account)) {
diff --git a/src/main/java/de/thedevstack/conversationsplus/services/AvatarService.java b/src/main/java/de/thedevstack/conversationsplus/services/AvatarService.java
index 63e94c03..1cbda222 100644
--- a/src/main/java/de/thedevstack/conversationsplus/services/AvatarService.java
+++ b/src/main/java/de/thedevstack/conversationsplus/services/AvatarService.java
@@ -23,7 +23,6 @@ import de.thedevstack.conversationsplus.entities.Conversation;
 import de.thedevstack.conversationsplus.entities.ListItem;
 import de.thedevstack.conversationsplus.entities.MucOptions;
 import de.thedevstack.conversationsplus.generator.IqGenerator;
-import de.thedevstack.conversationsplus.parser.IqParser;
 import de.thedevstack.conversationsplus.persistance.DatabaseBackend;
 import de.thedevstack.conversationsplus.ui.UiCallback;
 import de.thedevstack.conversationsplus.utils.AvatarUtil;
@@ -33,6 +32,8 @@ import de.thedevstack.conversationsplus.utils.UiUpdateHelper;
 import de.thedevstack.conversationsplus.utils.XmppSendUtil;
 import de.thedevstack.conversationsplus.xml.Element;
 import de.thedevstack.conversationsplus.xmpp.OnIqPacketReceived;
+import de.thedevstack.conversationsplus.xmpp.avatar.AvatarPacketGenerator;
+import de.thedevstack.conversationsplus.xmpp.avatar.AvatarPacketParser;
 import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
 import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
 
@@ -323,13 +324,13 @@ public class AvatarService {
 				callback.error(R.string.error_saving_avatar, avatar);
 				return;
 			}
-			final IqPacket packet = IqGenerator.publishAvatar(avatar);
+			final IqPacket packet = AvatarPacketGenerator.generatePublishAvatarPacket(avatar);
 			XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
 
 				@Override
 				public void onIqPacketReceived(Account account, IqPacket result) {
 					if (result.getType() == IqPacket.TYPE.RESULT) {
-						final IqPacket packet = IqGenerator.publishAvatarMetadata(avatar);
+						final IqPacket packet = AvatarPacketGenerator.generatePublishAvatarMetadataPacket(avatar);
 						XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
 
 							@Override
@@ -385,7 +386,7 @@ public class AvatarService {
 	}
 
 	private void fetchAvatarPep(final Account account, final Avatar avatar, final UiCallback<Avatar> callback) {
-		IqPacket packet = IqGenerator.retrievePepAvatar(avatar);
+		IqPacket packet = AvatarPacketGenerator.generateRetrieveAvatarPacket(avatar);
         XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
 
             @Override
@@ -396,7 +397,7 @@ public class AvatarService {
                 final String ERROR = account.getJid().toBareJid()
                         + ": fetching avatar for " + avatar.owner + " failed ";
                 if (result.getType() == IqPacket.TYPE.RESULT) {
-                    avatar.image = IqParser.avatarData(result);
+                    avatar.image = AvatarPacketParser.parseAvatarData(result);
                     if (avatar.image != null) {
                         if (AvatarUtil.save(avatar)) {
                             if (account.getJid().toBareJid().equals(avatar.owner)) {
@@ -472,7 +473,7 @@ public class AvatarService {
 	}
 
 	public void checkForAvatar(Account account, final UiCallback<Avatar> callback) {
-		IqPacket packet = IqGenerator.retrieveAvatarMetaData(null);
+		IqPacket packet = AvatarPacketGenerator.generateRetrieveAvatarMetadataPacket(null);
 		XmppSendUtil.sendIqPacket(account, packet, new OnIqPacketReceived() {
 
             @Override
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarPacketGenerator.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarPacketGenerator.java
new file mode 100644
index 00000000..bb7e557e
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarPacketGenerator.java
@@ -0,0 +1,124 @@
+package de.thedevstack.conversationsplus.xmpp.avatar;
+
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.jid.Jid;
+import de.thedevstack.conversationsplus.xmpp.pep.Avatar;
+import de.thedevstack.conversationsplus.xmpp.pubsub.PubSubPacketGenerator;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ * Generates the IQ Packets for handling Avatars
+ * as defined in XEP-0084.
+ * @see {@link http://xmpp.org/extensions/xep-0084.html}
+ */
+public final class AvatarPacketGenerator {
+    public static final String NAMESPACE_AVATAR_DATA = "urn:xmpp:avatar:data";
+    public static final String NAMESPACE_AVATAR_METADATA = "urn:xmpp:avatar:metadata";
+
+    /**
+     * Generates an IqPacket for publishing avatar data.
+     * The attributes from and id are not set in here - this is added while sending the packet.
+     * <pre>
+     *     <iq type='set'>
+     *          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
+     *              <publish node='urn:xmpp:avatar:data'>
+     *                  <item id='111f4b3c50d7b0df729d299bc6f8e9ef9066971f'>
+     *                      <data xmlns='urn:xmpp:avatar:data'>
+     *                      qANQR1DBwU4DX7jmYZnncm...
+     *                      </data>
+     *                  </item>
+     *              </publish>
+     *          </pubsub>
+     *      </iq>
+     * </pre>
+     * @param avatar the avatar to publish
+     * @return the IqPacket
+     */
+    public static IqPacket generatePublishAvatarPacket(Avatar avatar) {
+        final Element item = new Element("item");
+        item.setAttribute("id", avatar.sha1sum);
+        final Element data = item.addChild("data", NAMESPACE_AVATAR_DATA);
+        data.setContent(avatar.image);
+        return PubSubPacketGenerator.generatePubSubPublishPacket(NAMESPACE_AVATAR_DATA, item);
+    }
+
+    /**
+     * Generates an IqPacket to retrieve avatar data.
+     * The attributes from and id are not set in here - this is added while sending the packet.
+     * <pre>
+     *     <iq type='get'>
+     *       <pubsub xmlns='http://jabber.org/protocol/pubsub'>
+     *           <items node='urn:xmpp:avatar:data'>
+     *              <item id='111f4b3c50d7b0df729d299bc6f8e9ef9066971f'/>
+     *           </items>
+     *       </pubsub>
+     *      </iq>
+     * </pre>
+     * @param avatar the avatar to retrieve
+     * @return the IqPacket
+     */
+    public static IqPacket generateRetrieveAvatarPacket(Avatar avatar) {
+        final Element item = new Element("item");
+        item.setAttribute("id", avatar.sha1sum);
+        final IqPacket packet = PubSubPacketGenerator.generatePubSubRetrievePacket(NAMESPACE_AVATAR_DATA, item);
+        packet.setTo(avatar.owner);
+        return packet;
+    }
+
+    /**
+     * Generates an IqPacket to publish metadata for an avatar.
+     * The attributes from and id are not set in here - this is added while sending the packet.
+     * <pre>
+     *     <iq type='set'>
+     *          <pubsub xmlns='http://jabber.org/protocol/pubsub'>
+     *              <publish node='urn:xmpp:avatar:metadata'>
+     *                  <item id='111f4b3c50d7b0df729d299bc6f8e9ef9066971f'>
+     *                      <metadata xmlns='urn:xmpp:avatar:metadata'>
+     *                          <info bytes='12345'
+     *                                id='111f4b3c50d7b0df729d299bc6f8e9ef9066971f'
+     *                                height='64'
+     *                                type='image/png'
+     *                                width='64'/>
+     *                      </metadata>
+     *                  </item>
+     *              </publish>
+     *          </pubsub>
+     *      </iq>
+     * </pre>
+     * @param avatar the avatar to publish the metadata
+     * @return the IqPacket
+     */
+    public static IqPacket generatePublishAvatarMetadataPacket(Avatar avatar) {
+        final Element item = new Element("item");
+        item.setAttribute("id", avatar.sha1sum);
+        final Element metadata = item.addChild("metadata", NAMESPACE_AVATAR_METADATA);
+        final Element info = metadata.addChild("info");
+        info.setAttribute("bytes", avatar.size);
+        info.setAttribute("id", avatar.sha1sum);
+        info.setAttribute("height", avatar.height);
+        info.setAttribute("width", avatar.height);
+        info.setAttribute("type", avatar.type);
+        return PubSubPacketGenerator.generatePubSubPublishPacket(NAMESPACE_AVATAR_METADATA, item);
+    }
+
+    /**
+     * Generates an IqPacket to retrieve metadata of an avatar.
+     * The attributes from and id are not set in here - this is added while sending the packet.
+     * @param to the Jid to deliver the metadata to
+     * @return the IqPacket
+     */
+    public static IqPacket generateRetrieveAvatarMetadataPacket(Jid to) {
+        final IqPacket packet = PubSubPacketGenerator.generatePubSubRetrievePacket(NAMESPACE_AVATAR_METADATA, null);
+        if (to != null) {
+            packet.setTo(to);
+        }
+        return packet;
+    }
+
+    /**
+     * Helper class - private constructor to avoid instantiation
+     */
+    private AvatarPacketGenerator() {
+        // avoid instantiation
+    }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarPacketParser.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarPacketParser.java
new file mode 100644
index 00000000..26d5202f
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/avatar/AvatarPacketParser.java
@@ -0,0 +1,29 @@
+package de.thedevstack.conversationsplus.xmpp.avatar;
+
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.pubsub.PubSubPacketParser;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ * Parses the IQ Packets for handling Avatars
+ * as defined in XEP-0084.
+ * @see {@link http://xmpp.org/extensions/xep-0084.html}
+ */
+public class AvatarPacketParser {
+    /**
+     * Extracts the base64 encoded avatar data from an IqPacket.
+     * @param packet the IqPacket to be parsed.
+     * @return base64 encoded avatar data
+     */
+    public static String parseAvatarData(IqPacket packet) {
+        Element items = PubSubPacketParser.findItems(packet);
+        String base64Avatar = null;
+        if (null != items) {
+            Element item = items.findChild("item");
+            if (null != item) {
+                base64Avatar = item.findChildContent("data", AvatarPacketGenerator.NAMESPACE_AVATAR_DATA);
+            }
+        }
+        return base64Avatar;
+    }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/pubsub/PubSubPacket.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/pubsub/PubSubPacket.java
new file mode 100644
index 00000000..fea1383c
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/pubsub/PubSubPacket.java
@@ -0,0 +1,33 @@
+package de.thedevstack.conversationsplus.xmpp.pubsub;
+
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ * Created by tzur on 15.01.2016.
+ */
+public class PubSubPacket extends IqPacket {
+    public static final String NAMESPACE = "http://jabber.org/protocol/pubsub";
+    public static final String ELEMENT_NAME = "pubsub";
+    private Element pubSubElement;
+
+    public PubSubPacket(IqPacket.TYPE type) {
+        super(type);
+        this.pubSubElement = super.addChild(PubSubPacket.ELEMENT_NAME, PubSubPacket.NAMESPACE);
+    }
+
+    @Override
+    public Element addChild(Element child) {
+        return this.pubSubElement.addChild(child);
+    }
+
+    @Override
+    public Element addChild(String name) {
+        return this.pubSubElement.addChild(name);
+    }
+
+    @Override
+    public Element addChild(String name, String xmlns) {
+        return this.pubSubElement.addChild(name, xmlns);
+    }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/pubsub/PubSubPacketGenerator.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/pubsub/PubSubPacketGenerator.java
new file mode 100644
index 00000000..1eb44b5e
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/pubsub/PubSubPacketGenerator.java
@@ -0,0 +1,32 @@
+package de.thedevstack.conversationsplus.xmpp.pubsub;
+
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ * Created by tzur on 15.01.2016.
+ */
+public final class PubSubPacketGenerator {
+
+    public static PubSubPacket generatePubSubPublishPacket(String nodeName, Element item) {
+        final PubSubPacket pubsub = new PubSubPacket(IqPacket.TYPE.SET);
+        final Element publish = pubsub.addChild("publish");
+        publish.setAttribute("node", nodeName);
+        publish.addChild(item);
+        return pubsub;
+    }
+
+    public static PubSubPacket generatePubSubRetrievePacket(String nodeName, Element item) {
+        final PubSubPacket pubsub = new PubSubPacket(IqPacket.TYPE.GET);
+        final Element items = pubsub.addChild("items");
+        items.setAttribute("node", nodeName);
+        if (item != null) {
+            items.addChild(item);
+        }
+        return pubsub;
+    }
+
+    private PubSubPacketGenerator() {
+        // Avoid instantiation
+    }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/pubsub/PubSubPacketParser.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/pubsub/PubSubPacketParser.java
new file mode 100644
index 00000000..a5172577
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/pubsub/PubSubPacketParser.java
@@ -0,0 +1,27 @@
+package de.thedevstack.conversationsplus.xmpp.pubsub;
+
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ * Created by tzur on 15.01.2016.
+ */
+public class PubSubPacketParser {
+    public static PubSubPacket findPubSubPacket(IqPacket packet){
+        if (null == packet) {
+            return null;
+        }
+        return (PubSubPacket) packet.findChild("pubsub", "http://jabber.org/protocol/pubsub");
+    }
+
+    public static Element findItems(PubSubPacket pubSubPacket) {
+        if (null == pubSubPacket) {
+            return null;
+        }
+        return pubSubPacket.findChild("items");
+    }
+
+    public static Element findItems(IqPacket packet) {
+        return PubSubPacketParser.findItems(PubSubPacketParser.findPubSubPacket(packet));
+    }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacketGenerator.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacketGenerator.java
new file mode 100644
index 00000000..27e6607f
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacketGenerator.java
@@ -0,0 +1,31 @@
+package de.thedevstack.conversationsplus.xmpp.stanzas;
+
+/**
+ * Created by tzur on 15.01.2016.
+ */
+public final class IqPacketGenerator {
+
+    private static IqPacket generateIqPacket(IqPacket.TYPE type) {
+        return new IqPacket(type);
+    }
+
+    public static IqPacket generateIqSetPacket() {
+        return generateIqPacket(IqPacket.TYPE.SET);
+    }
+
+    public static IqPacket generateIqGetPacket() {
+        return generateIqPacket(IqPacket.TYPE.GET);
+    }
+
+    public static IqPacket generateIqResultPacket() {
+        return generateIqPacket(IqPacket.TYPE.RESULT);
+    }
+
+    public static IqPacket generateIqErrorPacket() {
+        return generateIqPacket(IqPacket.TYPE.ERROR);
+    }
+
+    private IqPacketGenerator() {
+        // avoid Instantiation
+    }
+}