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: + * + * @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: + * + * @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!"); + } +}