From dc9e9875a01065f3091738eb6d370c77d914481a Mon Sep 17 00:00:00 2001
From: Kevin Smith <git@kismith.co.uk>
Date: Tue, 2 Oct 2012 11:37:00 +0100
Subject: Adding Support for SoftwareVersionResponder


diff --git a/src/com/isode/stroke/client/Client.java b/src/com/isode/stroke/client/Client.java
index 741597c..4478deb 100644
--- a/src/com/isode/stroke/client/Client.java
+++ b/src/com/isode/stroke/client/Client.java
@@ -8,13 +8,13 @@
  */
 package com.isode.stroke.client;
 
-import com.isode.stroke.eventloop.EventLoop;
 import com.isode.stroke.jid.JID;
 import com.isode.stroke.muc.MUCManager;
 import com.isode.stroke.muc.MUCRegistry;
 import com.isode.stroke.network.NetworkFactories;
 import com.isode.stroke.presence.DirectedPresenceSender;
 import com.isode.stroke.presence.StanzaChannelPresenceSender;
+import com.isode.stroke.queries.responders.SoftwareVersionResponder;
 
 /**
  * Provides the core functionality for writing XMPP client software.
@@ -29,6 +29,7 @@ public class Client extends CoreClient {
     private MUCRegistry mucRegistry;
     private DirectedPresenceSender directedPresenceSender;
     private StanzaChannelPresenceSender stanzaChannelPresenceSender;
+    private SoftwareVersionResponder softwareVersionResponder;
 
     /**
      * Constructor.
@@ -53,6 +54,9 @@ public class Client extends CoreClient {
 
         mucRegistry = new MUCRegistry();
         mucManager = new MUCManager(getStanzaChannel(), getIQRouter(), directedPresenceSender, mucRegistry);
+
+        softwareVersionResponder = new SoftwareVersionResponder(getIQRouter());
+        softwareVersionResponder.start();
     }
 
     /**
@@ -70,4 +74,13 @@ public class Client extends CoreClient {
     public MUCRegistry getMUCRegistry() {
         return mucRegistry;
     }
+    
+    /**
+     * Sets the software version of the client.                  
+     *
+     * This will be used to respond to version queries from other entities.
+     */
+    public void setSoftwareVersion(final String name, final String version, final String os) {
+        softwareVersionResponder.setVersion(name, version, os);
+    }
 }
diff --git a/src/com/isode/stroke/elements/IQ.java b/src/com/isode/stroke/elements/IQ.java
index 78d4d6a..d06d3a6 100644
--- a/src/com/isode/stroke/elements/IQ.java
+++ b/src/com/isode/stroke/elements/IQ.java
@@ -46,6 +46,15 @@ public class IQ extends Stanza {
         iq.addPayload(payload);
         return iq;
     }
+    
+    public static IQ createResult(JID to, JID from, String id, Payload payload) {
+        IQ iq = new IQ(Type.Result);
+        iq.setTo(to);
+        iq.setFrom(from);
+        iq.setID(id);
+        iq.addPayload(payload);
+        return iq;
+    }
 
     public static IQ createError(JID to, String id, ErrorPayload.Condition condition, ErrorPayload.Type type) {
         IQ iq = new IQ(Type.Error);
@@ -54,7 +63,28 @@ public class IQ extends Stanza {
         iq.addPayload(new ErrorPayload(condition, type));
         return iq;
     }
+    
+    public static IQ createError(JID to, String id, ErrorPayload.Condition condition, ErrorPayload.Type type, Payload payload) {
+        IQ iq = new IQ(Type.Error);
+        iq.setTo(to);
+        iq.setID(id);
+        ErrorPayload errorPayload = new ErrorPayload(condition, type);
+        errorPayload.setPayload(payload);
+        iq.addPayload(errorPayload);
+        return iq;
+    }
 
+    public static IQ createError(JID to, JID from, String id, ErrorPayload.Condition condition, ErrorPayload.Type type, Payload payload) {
+        IQ iq = new IQ(Type.Error);
+        iq.setTo(to);
+        iq.setFrom(from);
+        iq.setID(id);
+        ErrorPayload errorPayload = new ErrorPayload(condition, type);
+        errorPayload.setPayload(payload);
+        iq.addPayload(errorPayload);
+        return iq;
+    }
+    
     @Override
     public String toString() {
         return super.toString() + " Type=" + type_; 
diff --git a/src/com/isode/stroke/elements/SoftwareVersion.java b/src/com/isode/stroke/elements/SoftwareVersion.java
new file mode 100644
index 0000000..1576a29
--- /dev/null
+++ b/src/com/isode/stroke/elements/SoftwareVersion.java
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 2010 Isode Limited, London, England.
+ * All rights reserved.
+ */
+
+package com.isode.stroke.elements;
+
+
+public class SoftwareVersion extends Payload {
+    private String name_;
+    private String version_;
+    private String os_;
+
+    public SoftwareVersion(final String name, final String version, final String os) {
+        name_ = name;
+        version_ = version;
+        os_ = os;
+    }
+
+    public SoftwareVersion() {
+        
+    }
+
+    public String getName() {
+        return name_;
+    }
+
+    public String getVersion() {
+        return version_;
+    }
+
+    public String getOS() {
+        return os_;
+    }
+
+    public void setName(final String name) {
+        name_ = name;
+    }
+
+    public void setVersion(final String version) {
+        version_ = version;
+    }
+
+    public void setOS(final String os) {
+        os_ = os;
+    }
+}
diff --git a/src/com/isode/stroke/elements/Version.java b/src/com/isode/stroke/elements/Version.java
deleted file mode 100644
index 0dacd32..0000000
--- a/src/com/isode/stroke/elements/Version.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (c) 2010 Remko Tronçon
- * All rights reserved.
- */
-/*
- * Copyright (c) 2010 Isode Limited, London, England.
- * All rights reserved.
- */
-
-package com.isode.stroke.elements;
-
-
-public class Version extends Payload {
-    private String name_;
-    private String version_;
-    private String os_;
-
-    public Version(final String name, final String version, final String os) {
-        name_ = name;
-        version_ = version;
-        os_ = os;
-    }
-
-    public Version() {
-        
-    }
-
-    public String getName() {
-        return name_;
-    }
-
-    public String getVersion() {
-        return version_;
-    }
-
-    public String getOS() {
-        return os_;
-    }
-
-    public void setName(final String name) {
-        name_ = name;
-    }
-
-    public void setVersion(final String version) {
-        version_ = version;
-    }
-
-    public void setOS(final String os) {
-        os_ = os;
-    }
-}
diff --git a/src/com/isode/stroke/parser/payloadparsers/SoftwareVersionParser.java b/src/com/isode/stroke/parser/payloadparsers/SoftwareVersionParser.java
index 84c4559..b94b086 100644
--- a/src/com/isode/stroke/parser/payloadparsers/SoftwareVersionParser.java
+++ b/src/com/isode/stroke/parser/payloadparsers/SoftwareVersionParser.java
@@ -9,14 +9,14 @@
 
 package com.isode.stroke.parser.payloadparsers;
 
-import com.isode.stroke.elements.Version;
+import com.isode.stroke.elements.SoftwareVersion;
 import com.isode.stroke.parser.AttributeMap;
 import com.isode.stroke.parser.GenericPayloadParser;
 
-public class SoftwareVersionParser extends GenericPayloadParser<Version> {
+public class SoftwareVersionParser extends GenericPayloadParser<SoftwareVersion> {
 
     public SoftwareVersionParser() {
-        super(new Version());
+        super(new SoftwareVersion());
     }
 
     public void handleStartElement(String element, String ns, AttributeMap attributes) {
diff --git a/src/com/isode/stroke/queries/GetResponder.java b/src/com/isode/stroke/queries/GetResponder.java
new file mode 100644
index 0000000..edc798b
--- /dev/null
+++ b/src/com/isode/stroke/queries/GetResponder.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2012, Isode Limited, London, England.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+package com.isode.stroke.queries;
+
+import com.isode.stroke.elements.Payload;
+import com.isode.stroke.jid.JID;
+
+public abstract class GetResponder<T extends Payload> extends Responder<T> {
+
+    public GetResponder(T t, IQRouter router) {
+        super(t, router);
+    }
+
+    @Override
+    protected boolean handleSetRequest(final JID from, final JID to, final String id, final T payload) {
+        return false;
+    }
+};
diff --git a/src/com/isode/stroke/queries/GetVersionRequest.java b/src/com/isode/stroke/queries/GetVersionRequest.java
index b81e972..f387a27 100644
--- a/src/com/isode/stroke/queries/GetVersionRequest.java
+++ b/src/com/isode/stroke/queries/GetVersionRequest.java
@@ -10,15 +10,15 @@
 package com.isode.stroke.queries;
 
 import com.isode.stroke.elements.IQ.Type;
-import com.isode.stroke.elements.Version;
+import com.isode.stroke.elements.SoftwareVersion;
 import com.isode.stroke.jid.JID;
 
-public class GetVersionRequest extends GenericRequest<Version> {
+public class GetVersionRequest extends GenericRequest<SoftwareVersion> {
     public GetVersionRequest(JID target, IQRouter iqRouter) {
-        super(Type.Get, target, new Version(), iqRouter);
+        super(Type.Get, target, new SoftwareVersion(), iqRouter);
     }
 
     public GetVersionRequest(IQRouter iqRouter) {
-        super(Type.Get, new JID(), new Version(), iqRouter);
+        super(Type.Get, new JID(), new SoftwareVersion(), iqRouter);
     }
 }
diff --git a/src/com/isode/stroke/queries/IQHandler.java b/src/com/isode/stroke/queries/IQHandler.java
index 54ff4c6..783f013 100644
--- a/src/com/isode/stroke/queries/IQHandler.java
+++ b/src/com/isode/stroke/queries/IQHandler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2010, Isode Limited, London, England.
+ * Copyright (c) 2010-2012, Isode Limited, London, England.
  * All rights reserved.
  */
 /*
@@ -15,5 +15,5 @@ import com.isode.stroke.elements.IQ;
  * Thing reacting to IQs.
  */
 public interface IQHandler {
-    boolean handleIQ(IQ iq);
+    public boolean handleIQ(IQ iq);
 }
diff --git a/src/com/isode/stroke/queries/Responder.java b/src/com/isode/stroke/queries/Responder.java
new file mode 100644
index 0000000..203dd7e
--- /dev/null
+++ b/src/com/isode/stroke/queries/Responder.java
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2012, Isode Limited, London, England.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+package com.isode.stroke.queries;
+
+import com.isode.stroke.elements.ErrorPayload;
+import com.isode.stroke.elements.IQ;
+import com.isode.stroke.elements.Payload;
+import com.isode.stroke.jid.JID;
+
+/**
+ * A class for handling incoming IQ Get and Set requests of a specific payload
+ * type.
+ *
+ * Concrete subclasses of this class need to implement handleGetRequest() and
+ * handleSetRequest() to implement the behavior of the responder.
+ *
+ * \tparam PAYLOAD_TYPE The type of payload this Responder handles. Only IQ
+ * requests containing this payload type will be passed to handleGetRequest()
+ * and handleSetRequest()
+ */
+public abstract class Responder<PAYLOAD_TYPE extends Payload> implements IQHandler {
+
+    public Responder(final PAYLOAD_TYPE payloadType, IQRouter router) {
+        payloadType_ = payloadType;
+        router_ = router;
+    }
+
+    /**
+     * Starts the responder.
+     *
+     * After the responder has started, it will start receiving and responding
+     * to requests.
+     *
+     * \see stop()
+     */
+    public void start() {
+        router_.addHandler(this);
+    }
+
+    /**
+     * Stops the responder.
+     *
+     * When the responder is stopped, it will no longer receive incoming
+     * requests.
+     *
+     * \see start()
+     */
+    public void stop() {
+        router_.removeHandler(this);
+    }
+
+    /**
+     * Handle an incoming IQ-Get request containing a payload of class
+     * PAYLOAD_TYPE.
+     *
+     * This method is implemented in the concrete subclasses.
+     */
+    protected abstract boolean handleGetRequest(final JID from, final JID to, final String id, PAYLOAD_TYPE payload);
+
+    /**
+     * Handle an incoming IQ-Set request containing a payload of class
+     * PAYLOAD_TYPE.
+     *
+     * This method is implemented in the concrete subclasses.
+     */
+    protected abstract boolean handleSetRequest(final JID from, final JID to, final String id, PAYLOAD_TYPE payload);
+
+    /**
+     * Convenience function for sending an IQ response.
+     */
+    protected void sendResponse(final JID to, final String id, PAYLOAD_TYPE payload) {
+        router_.sendIQ(IQ.createResult(to, id, payload));
+    }
+
+    /**
+     * Convenience function for sending an IQ response, with a specific from
+     * address.
+     */
+    protected void sendResponse(final JID to, final JID from, final String id, PAYLOAD_TYPE payload) {
+        router_.sendIQ(IQ.createResult(to, from, id, payload));
+    }
+
+    /**
+     * Convenience function for responding with an error.
+     */
+    protected void sendError(final JID to, final String id, ErrorPayload.Condition condition, ErrorPayload.Type type, Payload payload) {
+        router_.sendIQ(IQ.createError(to, id, condition, type, payload));
+    }
+
+    protected void sendError(final JID to, final String id, ErrorPayload.Condition condition, ErrorPayload.Type type) {
+        sendError(to, id, condition, type, null);
+    }
+
+    /**
+     * Convenience function for responding with an error from a specific from
+     * address.
+     */
+    protected void sendError(final JID to, final JID from, final String id, ErrorPayload.Condition condition, ErrorPayload.Type type, Payload payload) {
+        router_.sendIQ(IQ.createError(to, from, id, condition, type, payload));
+    }
+
+    protected void sendError(final JID to, final JID from, final String id, ErrorPayload.Condition condition, ErrorPayload.Type type) {
+        sendError(to, from, id, condition, type, null);
+    }
+
+    protected IQRouter getIQRouter() {
+        return router_;
+    }
+
+    @Override
+    public boolean handleIQ(IQ iq) {
+        if (IQ.Type.Set.equals(iq.getType()) || IQ.Type.Get.equals(iq.getType())) {
+            PAYLOAD_TYPE payload = iq.getPayload(payloadType_);
+            if (payload != null) {
+                boolean result;
+                if (IQ.Type.Set.equals(
+                        iq.getType())) {
+                    result = handleSetRequest(iq.getFrom(), iq.getTo(), iq.getID(), payload);
+                } else {
+                    result = handleGetRequest(iq.getFrom(), iq.getTo(), iq.getID(), payload);
+                }
+                if (!result) {
+                    router_.sendIQ(IQ.createError(iq.getFrom(), iq.getID(), ErrorPayload.Condition.NotAllowed, ErrorPayload.Type.Cancel));
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+    private IQRouter router_;
+    private PAYLOAD_TYPE payloadType_;
+};
diff --git a/src/com/isode/stroke/queries/responders/SoftwareVersionResponder.java b/src/com/isode/stroke/queries/responders/SoftwareVersionResponder.java
new file mode 100644
index 0000000..1fd5b36
--- /dev/null
+++ b/src/com/isode/stroke/queries/responders/SoftwareVersionResponder.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2012, Isode Limited, London, England.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 2010 Remko Tronçon
+ * Licensed under the GNU General Public License v3.
+ * See Documentation/Licenses/GPLv3.txt for more information.
+ */
+package com.isode.stroke.queries.responders;
+
+import com.isode.stroke.elements.SoftwareVersion;
+import com.isode.stroke.jid.JID;
+import com.isode.stroke.queries.GetResponder;
+import com.isode.stroke.queries.IQRouter;
+
+public class SoftwareVersionResponder extends GetResponder<SoftwareVersion> {
+
+    public SoftwareVersionResponder(IQRouter router) {
+        super(new SoftwareVersion(), router);
+    }
+
+    public void setVersion(final String client, final String version, final String os) {
+        this.client = client;
+        this.version = version;
+        this.os = os;
+    }
+
+    @Override
+    public boolean handleGetRequest(final JID from, final JID to, final String id, SoftwareVersion payload) {
+        sendResponse(from, id, new SoftwareVersion(client, version, os));
+        return true;
+    }
+    private String client;
+    private String version;
+    private String os;
+}
\ No newline at end of file
diff --git a/src/com/isode/stroke/serializer/payloadserializers/SoftwareVersionSerializer.java b/src/com/isode/stroke/serializer/payloadserializers/SoftwareVersionSerializer.java
index 27baada..a62ed4c 100644
--- a/src/com/isode/stroke/serializer/payloadserializers/SoftwareVersionSerializer.java
+++ b/src/com/isode/stroke/serializer/payloadserializers/SoftwareVersionSerializer.java
@@ -9,17 +9,17 @@
 
 package com.isode.stroke.serializer.payloadserializers;
 
-import com.isode.stroke.elements.Version;
+import com.isode.stroke.elements.SoftwareVersion;
 import com.isode.stroke.serializer.GenericPayloadSerializer;
 
-public class SoftwareVersionSerializer extends GenericPayloadSerializer<Version>{
+public class SoftwareVersionSerializer extends GenericPayloadSerializer<SoftwareVersion>{
 
     public SoftwareVersionSerializer() {
-        super(Version.class);
+        super(SoftwareVersion.class);
     }
 
     @Override
-    protected String serializePayload(Version version) {
+    protected String serializePayload(SoftwareVersion version) {
         StringBuilder result = new StringBuilder();
         result.append("<query xmlns=\"jabber:iq:version\">");
         if (version.getName() != null && version.getName().length() > 0) {
-- 
cgit v0.10.2-6-g49f6