diff --git a/source/org/jivesoftware/smack/packet/IQ.java b/source/org/jivesoftware/smack/packet/IQ.java
index 0fbea9ee0..8b844674c 100644
--- a/source/org/jivesoftware/smack/packet/IQ.java
+++ b/source/org/jivesoftware/smack/packet/IQ.java
@@ -108,6 +108,75 @@ public abstract class IQ extends Packet {
*/
public abstract String getChildElementXML();
+ /**
+ * Convenience method to create a new empty {@link Type#RESULT IQ.Type.RESULT}
+ * IQ based on a {@link Type#GET IQ.Type.GET} or {@link Type#SET IQ.Type.SET}
+ * IQ. The new packet will be initialized with:
+ * - The sender set to the recipient of the originating IQ.
+ *
- The recipient set to the sender of the originating IQ.
+ *
- The type set to {@link Type#RESULT IQ.Type.RESULT}.
+ *
- The id set to the id of the originating IQ.
+ *
- No child element of the IQ element.
+ *
+ *
+ * @param iq the {@link Type#GET IQ.Type.GET} or {@link Type#SET IQ.Type.SET} IQ packet.
+ * @throws IllegalArgumentException if the IQ packet does not have a type of
+ * {@link Type#GET IQ.Type.GET} or {@link Type#SET IQ.Type.SET}.
+ * @return a new {@link Type#RESULT IQ.Type.RESULT} IQ based on the originating IQ.
+ */
+ public static IQ createResultIQ(final IQ request) {
+ if (!(request.getType() == Type.GET || request.getType() == Type.SET)) {
+ throw new IllegalArgumentException(
+ "IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML());
+ }
+ final IQ result = new IQ() {
+ public String getChildElementXML() {
+ return null;
+ }
+ };
+ result.setType(Type.RESULT);
+ result.setPacketID(request.getPacketID());
+ result.setFrom(request.getTo());
+ result.setTo(request.getFrom());
+ return result;
+ }
+
+ /**
+ * Convenience method to create a new {@link Type#ERROR IQ.Type.ERROR} IQ
+ * based on a {@link Type#GET IQ.Type.GET} or {@link Type#SET IQ.Type.SET}
+ * IQ. The new packet will be initialized with:
+ * - The sender set to the recipient of the originating IQ.
+ *
- The recipient set to the sender of the originating IQ.
+ *
- The type set to {@link Type#ERROR IQ.Type.ERROR}.
+ *
- The id set to the id of the originating IQ.
+ *
- The child element contained in the associated originating IQ.
+ *
- The provided {@link XMPPError XMPPError}.
+ *
+ *
+ * @param iq the {@link Type#GET IQ.Type.GET} or {@link Type#SET IQ.Type.SET} IQ packet.
+ * @param error the error to associate with the created IQ packet.
+ * @throws IllegalArgumentException if the IQ packet does not have a type of
+ * {@link Type#GET IQ.Type.GET} or {@link Type#SET IQ.Type.SET}.
+ * @return a new {@link Type#ERROR IQ.Type.ERROR} IQ based on the originating IQ.
+ */
+ public static IQ createErrorResponse(final IQ request, final XMPPError error) {
+ if (!(request.getType() == Type.GET || request.getType() == Type.SET)) {
+ throw new IllegalArgumentException(
+ "IQ must be of type 'set' or 'get'. Original IQ: " + request.toXML());
+ }
+ final IQ result = new IQ() {
+ public String getChildElementXML() {
+ return request.getChildElementXML();
+ }
+ };
+ result.setType(Type.ERROR);
+ result.setPacketID(request.getPacketID());
+ result.setFrom(request.getTo());
+ result.setTo(request.getFrom());
+ result.setError(error);
+ return result;
+ }
+
/**
* A class to represent the type of the IQ packet. The types are:
*
diff --git a/test-unit/org/jivesoftware/smack/packet/IQResponseTest.java b/test-unit/org/jivesoftware/smack/packet/IQResponseTest.java
new file mode 100644
index 000000000..de116ee52
--- /dev/null
+++ b/test-unit/org/jivesoftware/smack/packet/IQResponseTest.java
@@ -0,0 +1,139 @@
+/**
+ * $RCSfile$
+ * $Revision$
+ * $Date$
+ *
+ * Copyright 2010 Jive Software.
+ *
+ * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jivesoftware.smack.packet;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+/**
+ * Tests that verifies the correct behavior of creating result and error IQ packets.
+ *
+ * @see IQ Semantics
+ * @author Guenther Niess
+ */
+public class IQResponseTest {
+
+ final static private String childElement = "";
+
+ /**
+ * Test creating a simple and empty IQ response.
+ */
+ @Test
+ public void testGeneratingSimpleResponse() {
+ final IQ request = new IQ() {
+ public String getChildElementXML() {
+ return childElement;
+ }
+ };
+ request.setFrom("sender@test/Smack");
+ request.setTo("receiver@test/Smack");
+
+ final IQ result = IQ.createResultIQ(request);
+
+ assertEquals(IQ.Type.RESULT, result.getType());
+ assertNotNull(result.getPacketID());
+ assertEquals(request.getPacketID(), result.getPacketID());
+ assertEquals(request.getFrom(), result.getTo());
+ assertEquals(request.getTo(), result.getFrom());
+ assertNull(result.getChildElementXML());
+ }
+
+ /**
+ * Test creating a error response based on an IQ request.
+ */
+ @Test
+ public void testGeneratingValidErrorResponse() {
+ final XMPPError error = new XMPPError(XMPPError.Condition.bad_request);
+ final IQ request = new IQ() {
+ public String getChildElementXML() {
+ return childElement;
+ }
+ };
+ request.setType(IQ.Type.SET);
+ request.setFrom("sender@test/Smack");
+ request.setTo("receiver@test/Smack");
+
+ final IQ result = IQ.createErrorResponse(request, error);
+
+ assertEquals(IQ.Type.ERROR, result.getType());
+ assertNotNull(result.getPacketID());
+ assertEquals(request.getPacketID(), result.getPacketID());
+ assertEquals(request.getFrom(), result.getTo());
+ assertEquals(error, result.getError());
+ assertEquals(childElement, result.getChildElementXML());
+ }
+
+ /**
+ * According to RFC3920: IQ Semantics we shouldn't respond to an IQ of type result.
+ */
+ @Test
+ public void testGeneratingResponseBasedOnResult() {
+ final IQ request = new IQ() {
+ public String getChildElementXML() {
+ return childElement;
+ }
+ };
+ request.setType(IQ.Type.RESULT);
+ request.setFrom("sender@test/Smack");
+ request.setTo("receiver@test/Smack");
+
+ try {
+ IQ.createResultIQ(request);
+ }
+ catch (IllegalArgumentException e) {
+ return;
+ }
+
+ fail("It shouldn't be possible to generate a response for a result IQ!");
+ }
+
+ /**
+ * According to RFC3920: IQ Semantics we shouldn't respond to an IQ of type error.
+ */
+ @Test
+ public void testGeneratingErrorBasedOnError() {
+ final XMPPError error = new XMPPError(XMPPError.Condition.bad_request);
+ final IQ request = new IQ() {
+ public String getChildElementXML() {
+ return childElement;
+ }
+ };
+ request.setType(IQ.Type.ERROR);
+ request.setFrom("sender@test/Smack");
+ request.setTo("receiver@test/Smack");
+ request.setError(error);
+
+ try {
+ IQ.createErrorResponse(request, error);
+ }
+ catch (IllegalArgumentException e) {
+ return;
+ }
+
+ fail("It shouldn't be possible to generate a response for a error IQ!");
+ }
+}