├── .gitignore ├── src ├── test │ ├── resources │ │ └── jid-version-tinder1.1.serialized │ └── java │ │ └── org │ │ └── xmpp │ │ ├── component │ │ ├── ThrowExceptionOnGetComponent.java │ │ ├── DummyAbstractComponent.java │ │ ├── SlowRespondingThreadNameComponent.java │ │ ├── AbstractComponentIsConsumerTest.java │ │ ├── AbstractComponentServiceDiscovery.java │ │ └── AbstractComponentRespondsToIQRequestsTest.java │ │ ├── util │ │ └── JIDWeigherTest.java │ │ ├── packet │ │ ├── JIDEqualsHashCodeTest.java │ │ ├── NodePrepTest.java │ │ ├── DomainPrepTest.java │ │ ├── ResourcePrepTest.java │ │ ├── StringPrepCacheTest.java │ │ ├── JIDCreationDomainTest.java │ │ ├── JIDCreationResourceTest.java │ │ ├── JIDCreationNodeTest.java │ │ ├── JIDCachedBareAndFullJIDTest.java │ │ ├── PacketErrorApplicationConditionTest.java │ │ ├── BasicJIDTest.java │ │ ├── JIDSerializabilityTest.java │ │ └── PacketAddressingTest.java │ │ ├── forms │ │ ├── DataFormTest.java │ │ ├── FormFieldGetSetTest.java │ │ └── DataFormAddingFieldsTest.java │ │ └── resultsetmanagement │ │ └── ResultSetTest.java └── main │ └── java │ └── org │ └── xmpp │ ├── muc │ ├── LeaveRoom.java │ ├── JoinRoom.java │ ├── DestroyRoom.java │ ├── Invitation.java │ └── RoomConfiguration.java │ ├── component │ ├── ComponentException.java │ ├── IQResultListener.java │ ├── ComponentManagerFactory.java │ ├── Component.java │ └── ComponentManager.java │ ├── resultsetmanagement │ ├── Result.java │ └── ResultSetImpl.java │ ├── util │ ├── XMPPConstants.java │ ├── JIDWeigher.java │ └── ValueWrapper.java │ └── packet │ └── PacketExtension.java ├── .github ├── dependabot.yml └── workflows │ └── build.yml ├── .editorconfig ├── README.md ├── tinder.doap ├── pom.xml └── LICENSE.html /.gitignore: -------------------------------------------------------------------------------- 1 | # Maven build directory 2 | /target 3 | 4 | # Intellij project files 5 | *.iml 6 | *.idea 7 | -------------------------------------------------------------------------------- /src/test/resources/jid-version-tinder1.1.serialized: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/igniterealtime/tinder/HEAD/src/test/resources/jid-version-tinder1.1.serialized -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "maven" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | 8 | - package-ecosystem: "github-actions" 9 | directory: "/" 10 | schedule: 11 | interval: "monthly" 12 | groups: 13 | github-actions: 14 | patterns: 15 | - '*' 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent coding styles between different editors and IDEs. 2 | # 3 | # EditorConfig is awesome: http://EditorConfig.org 4 | 5 | # top-most EditorConfig file 6 | root = true 7 | 8 | [*] 9 | end_of_line = lf 10 | insert_final_newline = true 11 | charset = utf-8 12 | indent_style = space 13 | indent_size = 4 14 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/component/ThrowExceptionOnGetComponent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.xmpp.component; 17 | 18 | import org.xmpp.packet.IQ; 19 | 20 | /** 21 | * An {@link AbstractComponent} implementation that generates an exception every 22 | * time its {@link #handleIQGet(IQ)} method is called. 23 | *

24 | * This implementation supports the unit tests of Tinder and is not intended for 25 | * production use. 26 | * 27 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 28 | */ 29 | public class ThrowExceptionOnGetComponent extends DummyAbstractComponent { 30 | 31 | /** 32 | * Throw an exception 33 | */ 34 | @Override 35 | protected IQ handleIQGet(IQ request) throws Exception { 36 | throw new Exception("This exception is expected to be thrown. It is used during unit testing."); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/util/JIDWeigherTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Ignite Realtime Foundation. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.util; 18 | 19 | import org.junit.Assert; 20 | import org.junit.Test; 21 | 22 | /** 23 | * Various checks that verify the implementation of {@link JIDWeigher}. 24 | * 25 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 26 | */ 27 | public class JIDWeigherTest 28 | { 29 | /** 30 | * Asserts that a cache entry of a specific JID has an approximate size. 31 | */ 32 | @Test 33 | public void testHappyFlow() { 34 | // Setup fixture. 35 | final JIDWeigher weigher = new JIDWeigher(); 36 | final String jid = "jane_john_doe@example.org/this-is-a-resource"; 37 | final ValueWrapper value = new ValueWrapper<>( jid ); 38 | 39 | // Execute system under test 40 | final long result = weigher.weigh( jid, value ); 41 | 42 | // Verify results. 43 | Assert.assertTrue( result >= 90 ); 44 | Assert.assertTrue( result <= 110 ); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Tinder 2 | ======== 3 | 4 | [![Build Status](https://github.com/igniterealtime/tinder/workflows/Java%20CI/badge.svg)](https://github.com/igniterealtime/tinder/actions) 5 | 6 | About 7 | ----- 8 | [Tinder] is a Java based XMPP library, providing an implementation for XMPP stanzas and components. Tinders origins lie in code that's shared between Ignite Realtime's [Openfire] and Whack implementations. The implementation that's provided in Tinder hasn't been written again from scratch. Instead, code has been moved from the original projects into Tinder, preserving al of the existing features and functionality. Most of the code that's now in Tinder is based on the org.xmpp package implementation that previously existed in Openfire and Whack. This is the code that defines classes such as Packet, JID, IQ, Component and their extensions. Additionally, some multi-purpose code (such as the DataForm and Result Set Management implementations) have been moved to Tinder as well. 9 | 10 | Resources 11 | --------- 12 | 13 | - Project homepage : https://www.igniterealtime.org/projects/tinder/ 14 | - Bug Tracker: http://issues.igniterealtime.org/browse/TINDER 15 | 16 | Ignite Realtime 17 | =============== 18 | 19 | [Ignite Realtime] is an Open Source community composed of end-users and developers around the world who 20 | are interested in applying innovative, open-standards-based Real Time Collaboration to their businesses and organizations. 21 | We're aimed at disrupting proprietary, non-open standards-based systems and invite you to participate in what's already one 22 | of the biggest and most active Open Source communities. 23 | 24 | [Openfire]: https://www.igniterealtime.org/projects/openfire/ 25 | [Tinder]: https://www.igniterealtime.org/projects/tinder/ 26 | [Ignite Realtime]: http://www.igniterealtime.org 27 | [XMPP (Jabber)]: http://xmpp.org/ 28 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/muc/LeaveRoom.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.muc; 18 | 19 | import net.jcip.annotations.NotThreadSafe; 20 | 21 | import org.xmpp.packet.Presence; 22 | 23 | /** 24 | * Initial presence sent when joining an existing room or creating a new room. The JoinRoom presence 25 | * indicates the posibility of the sender to speak MUC.

26 | * 27 | * Code example: 28 | *

29 |  * // Join an existing room or create a new one.
30 |  * JoinRoom joinRoom = new JoinRoom("john@jabber.org/notebook", "room@conference.jabber.org/nick");
31 |  *
32 |  * component.sendPacket(joinRoom);
33 |  * 
34 | * 35 | * @author Gaston Dombiak 36 | */ 37 | @NotThreadSafe 38 | public class LeaveRoom extends Presence { 39 | 40 | /** 41 | * Creates a new Presence packet that could be sent to a MUC service in order to leave the room. 42 | * 43 | * @param from the full JID of the user that wants to leave the room. 44 | * @param to the room JID. That is the room address plus the nickname of the user as a resource. 45 | */ 46 | public LeaveRoom(String from, String to) { 47 | super(); 48 | setFrom(from); 49 | setTo(to); 50 | setType(Type.unavailable); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/component/ComponentException.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.component; 18 | 19 | import org.xmpp.packet.StreamError; 20 | 21 | /** 22 | * Thrown when an exception occors with a Component. 23 | * 24 | * @author Matt Tucker 25 | */ 26 | public class ComponentException extends Exception { 27 | 28 | private static final long serialVersionUID = -4133202596762415887L; 29 | 30 | private StreamError streamError; 31 | 32 | public ComponentException() { 33 | super(); 34 | } 35 | 36 | public ComponentException(String message) { 37 | super(message); 38 | } 39 | 40 | public ComponentException(String message, Throwable cause) { 41 | super(message, cause); 42 | } 43 | 44 | public ComponentException(Throwable cause) { 45 | super(cause); 46 | } 47 | 48 | public ComponentException(String message, StreamError streamError) { 49 | super(message); 50 | this.streamError = streamError; 51 | } 52 | 53 | public ComponentException(StreamError streamError) { 54 | super(streamError.getCondition().toXMPP()); 55 | this.streamError = streamError; 56 | } 57 | 58 | public StreamError getStreamError() { 59 | return streamError; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/component/IQResultListener.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.component; 18 | 19 | import org.xmpp.packet.IQ; 20 | 21 | /** 22 | * An IQResultListener will be invoked when a previously IQ packet sent by the server was answered. 23 | * Use {@code IQRouter#addIQResultListener(String, IQResultListener)} to add a new listener that 24 | * will process the answer to the IQ packet being sent. The listener will automatically be 25 | * removed from the {@code IQRouter} as soon as a reply for the sent IQ packet is received. The 26 | * reply can be of type RESULT or ERROR. 27 | * 28 | * @author Gaston Dombiak 29 | */ 30 | public interface IQResultListener { 31 | 32 | /** 33 | * Notification method indicating that a previously sent IQ packet has been answered. 34 | * The received IQ packet might be of type ERROR or RESULT. 35 | * 36 | * @param packet the IQ packet answering a previously sent IQ packet. 37 | */ 38 | void receivedAnswer(IQ packet); 39 | 40 | /** 41 | * Notification method indicating that a predefined time has passed without 42 | * receiving answer to a previously sent IQ packet. 43 | * 44 | * @param packetId The packet id of a previously sent IQ packet that wasn't answered. 45 | */ 46 | void answerTimeout(String packetId); 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/muc/JoinRoom.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.muc; 18 | 19 | import net.jcip.annotations.NotThreadSafe; 20 | 21 | import org.xmpp.packet.Presence; 22 | 23 | /** 24 | * Initial presence sent when joining an existing room or creating a new room. The JoinRoom presence 25 | * indicates the posibility of the sender to speak MUC.

26 | * 27 | * Code example: 28 | *

29 |  * // Join an existing room or create a new one.
30 |  * JoinRoom joinRoom = new JoinRoom("john@jabber.org/notebook", "room@conference.jabber.org/nick");
31 |  *
32 |  * component.sendPacket(joinRoom);
33 |  * 
34 | * 35 | * @author Gaston Dombiak 36 | */ 37 | @NotThreadSafe 38 | public class JoinRoom extends Presence { 39 | 40 | /** 41 | * Creates a new Presence packet that could be sent to a MUC service in order to join 42 | * an existing MUC room or create a new one. 43 | * 44 | * @param from the real full JID of the user that will join or create a MUC room. 45 | * @param to a full JID where the bare JID is the MUC room address and the resource is the 46 | * nickname of the user joining the room. 47 | */ 48 | public JoinRoom(String from, String to) { 49 | super(); 50 | setFrom(from); 51 | setTo(to); 52 | addChildElement("x", "http://jabber.org/protocol/muc"); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/resultsetmanagement/Result.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.resultsetmanagement; 18 | 19 | /** 20 | * Elements from a result set as defined by XEP-0059 have certain 21 | * characteristics. This interface defines these characteristics. 22 | * 23 | * Applying this interface to a class will allow you to use ResultSet operations 24 | * on collections of your class. In other words: you are making collections of 25 | * your class managable/navigable. 26 | * 27 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 28 | * @see XEP-0059: Result Set Management 29 | */ 30 | public interface Result { 31 | 32 | /** 33 | * Returns a unique identifier for this Result. Each element in a ResultSet 34 | * must have a distinct UIDs. 35 | * 36 | * XEP-0059 says:
(...) the UIDs are 37 | * unique in the context of all possible members of the full result set. 38 | * Each UID MAY be based on part of the content of its associated item (...) 39 | * or on an internal table index. Another possible method is to serialize 40 | * the XML of the item and then hash it to generate the UID. Note: The 41 | * requesting entity MUST treat all UIDs as opaque.
42 | * 43 | * @return Unique ID of the Result 44 | */ 45 | String getUID(); 46 | 47 | } 48 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/util/XMPPConstants.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.util; 18 | 19 | /** 20 | * Contains constant values representing various objects in Tinder. 21 | */ 22 | public class XMPPConstants { 23 | 24 | /** 25 | * The amount of milliseconds in one second. 26 | */ 27 | public static final long SECOND = 1000; 28 | 29 | /** 30 | * The amount of milliseconds in one minute. 31 | */ 32 | public static final long MINUTE = 60 * SECOND; 33 | 34 | /** 35 | * The amount of milliseconds in one . 36 | */ 37 | public static final long HOUR = 60 * MINUTE; 38 | 39 | /** 40 | * The amount of milliseconds in one . 41 | */ 42 | public static final long DAY = 24 * HOUR; 43 | 44 | /** 45 | * The amount of milliseconds in one . 46 | */ 47 | public static final long WEEK = 7 * DAY; 48 | 49 | /** 50 | * Date/time format for use by SimpleDateFormat. The format conforms to 51 | * XEP-0082, which defines 52 | * a unified date/time format for XMPP. 53 | */ 54 | public static final String XMPP_DATETIME_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"; 55 | 56 | /** 57 | * Date/time format for use by SimpleDateFormat. The format conforms to the format 58 | * defined in XEP-0091, 59 | * a specialized date format for historical XMPP usage. 60 | */ 61 | public static final String XMPP_DELAY_DATETIME_FORMAT = "yyyyMMdd'T'HH:mm:ss"; 62 | } 63 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/muc/DestroyRoom.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.muc; 18 | 19 | import net.jcip.annotations.NotThreadSafe; 20 | 21 | import org.dom4j.Element; 22 | import org.xmpp.packet.IQ; 23 | import org.xmpp.packet.JID; 24 | 25 | /** 26 | * DestroyRoom is a packet that when sent will ask the server to destroy a given room. The room to 27 | * destroy must be specified in the TO attribute of the IQ packet. The server will send a presence 28 | * unavailable together with the alternate room and reason for the destruction to all the room 29 | * occupants before destroying the room.

30 | * 31 | * When destroying a room it is possible to provide an alternate room which may be replacing the 32 | * room about to be destroyed. It is also possible to provide a reason for the room destruction. 33 | */ 34 | @NotThreadSafe 35 | public class DestroyRoom extends IQ { 36 | 37 | /** 38 | * Creates a new DestroyRoom with the reason for the destruction and an alternate room JID. 39 | * 40 | * @param alternateJID JID of the alternate room or null if none. 41 | * @param reason reason for the destruction or null if none. 42 | */ 43 | public DestroyRoom(JID alternateJID, String reason) { 44 | super(); 45 | setType(Type.set); 46 | Element query = setChildElement("query", "http://jabber.org/protocol/muc#owner"); 47 | Element destroy = query.addElement("destroy"); 48 | if (alternateJID != null) { 49 | destroy.addAttribute("jid", alternateJID.toString()); 50 | } 51 | if (reason != null) { 52 | destroy.addElement("reason").setText(reason); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/muc/Invitation.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.muc; 18 | 19 | import net.jcip.annotations.NotThreadSafe; 20 | 21 | import org.dom4j.Element; 22 | import org.xmpp.packet.Message; 23 | 24 | /** 25 | * Represents an invitation to a Multi-User Chat room from a room occupant to a user that is not 26 | * an occupant of the room. The invitation must be sent to the room and it's the room 27 | * responsibility to forward the invitation to the invitee. The sender of the invitation must be 28 | * the real full JID of the inviter.

29 | * 30 | * Code example: 31 | *

32 |  * // Invite the someone to the room.
33 |  * Invitation invitation = new Invitation("invitee@jabber.org", "Join this excellent room");
34 |  * invitation.setTo("room@conference.jabber.org");
35 |  * invitation.setFrom("inviter@jabber.org/notebook");
36 |  *
37 |  * component.sendPacket(invitation);
38 |  * 
39 | * 40 | * @author Gaston Dombiak 41 | */ 42 | @NotThreadSafe 43 | public class Invitation extends Message { 44 | 45 | /** 46 | * Creates a new invitation. 47 | * 48 | * @param invitee the XMPP address of the invitee. The room will forward the invitation to this 49 | * address. 50 | * @param reason the reason why the invitation is being sent. 51 | */ 52 | public Invitation(String invitee, String reason) { 53 | super(); 54 | Element element = addChildElement("x", "http://jabber.org/protocol/muc#user"); 55 | Element invite = element.addElement("invite"); 56 | invite.addAttribute("to", invitee); 57 | if (reason != null && reason.length() > 0) { 58 | invite.addElement("reason").setText(reason); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/component/DummyAbstractComponent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.component; 18 | 19 | import java.util.concurrent.BlockingQueue; 20 | import java.util.concurrent.LinkedBlockingQueue; 21 | import java.util.concurrent.TimeUnit; 22 | 23 | import org.xmpp.packet.Packet; 24 | 25 | /** 26 | * A dummy implementation of {@link AbstractComponentTest}, intended to be used 27 | * during unit tests. 28 | * 29 | * Instances store any packets that are delivered to be send using the 30 | * {@link #send(Packet)} method in a blocking queue. The content of this queue 31 | * can be inspected using {@link #getSentPacket()}. Typically these queues are 32 | * used to retrieve a response that was generated by the component. 33 | * 34 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 35 | */ 36 | public class DummyAbstractComponent extends AbstractComponent { 37 | 38 | private final BlockingQueue queue = new LinkedBlockingQueue<>(); 39 | 40 | /* 41 | * (non-Javadoc) 42 | * 43 | * @see org.xmpp.component.AbstractComponent#getDescription() 44 | */ 45 | @Override 46 | public String getDescription() { 47 | return "An AbstractComponent implementation that's used during the unit tests of the Tinder project."; 48 | } 49 | 50 | /* 51 | * (non-Javadoc) 52 | * 53 | * @see org.xmpp.component.AbstractComponent#getName() 54 | */ 55 | @Override 56 | public String getName() { 57 | return "debug"; 58 | } 59 | 60 | /* 61 | * (non-Javadoc) 62 | * 63 | * @see org.xmpp.component.AbstractComponent#send(org.xmpp.packet.Packet) 64 | */ 65 | @Override 66 | protected void send(Packet packet) { 67 | queue.add(packet); 68 | } 69 | 70 | /** 71 | * Returns the first packet that's sent through {@link #send(Packet)} and 72 | * that has not been returned by earlier calls to this method. This method 73 | * will block for up to two seconds if no packets have been sent yet. 74 | * 75 | * @return A sent packet. 76 | * @throws InterruptedException if interrupted while waiting 77 | */ 78 | public Packet getSentPacket() throws InterruptedException { 79 | return queue.poll(2, TimeUnit.SECONDS); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/util/JIDWeigher.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 Ignite Realtime Foundation. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.util; 18 | 19 | import com.github.benmanes.caffeine.cache.Weigher; 20 | import org.jspecify.annotations.NullMarked; 21 | import org.jspecify.annotations.Nullable; 22 | 23 | /** 24 | * A Weigher that weights cache entries that contains JID parts. The weights 25 | * that are used are byte-size based. 26 | * 27 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 28 | */ 29 | @NullMarked 30 | public class JIDWeigher implements Weigher> 31 | { 32 | /** 33 | * Returns the weight of a cache entry. There is no unit for entry weights; rather they are simply 34 | * relative to each other. 35 | * 36 | * @param key the key to weigh 37 | * @param value the value to weigh 38 | * @return the weight of the entry; must be non-negative 39 | */ 40 | @Override 41 | public int weigh(final String key, final ValueWrapper value) 42 | { 43 | int result = 0; 44 | result += sizeOfString( key ); 45 | result += sizeOfValueWrapper( value ); 46 | return result; 47 | } 48 | 49 | /** 50 | * Returns the size in bytes of a String. 51 | * 52 | * @param string the String to determine the size of. 53 | * @return the size of a String. 54 | */ 55 | public static int sizeOfString(@Nullable String string) { 56 | if (string == null) { 57 | return 0; 58 | } 59 | return 4 + string.getBytes().length; 60 | } 61 | 62 | /** 63 | * Returns the size in bytes of a String. 64 | * 65 | * @param value the object to determine the size of. 66 | * @return the size of the object. 67 | */ 68 | public static int sizeOfValueWrapper(@Nullable ValueWrapper value) { 69 | if (value == null) { 70 | return 0; 71 | } 72 | 73 | int result = 4; // 'object' overhead. 74 | result += sizeOfString( value.getValue() ); 75 | result += sizeOfString( value.getExceptionMessage() ); 76 | result += 4; // for the reference to the enum value. 77 | return result; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/component/ComponentManagerFactory.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.component; 18 | 19 | /** 20 | * Factory to get a ComponentManager implementation. The ComponentManager implementation 21 | * used will determined in the following way:
    22 | * 23 | *
  • An external process can set the ComponentManager using 24 | * {@link #setComponentManager(ComponentManager)}. 25 | *
  • If the component manager is null, the factory will check for 26 | * the Java system property "whack.componentManagerClass". The value of the 27 | * property should be the fully qualified class name of a ComponentManager 28 | * implementation (e.g. com.foo.MyComponentManager). The class must have a default 29 | * constructor. 30 | *
31 | * 32 | * @author Matt Tucker 33 | */ 34 | public class ComponentManagerFactory { 35 | 36 | private static ComponentManager componentManager; 37 | 38 | /** 39 | * Returns a ComponentManager instance. 40 | * 41 | * @return a ComponentManager instance. 42 | */ 43 | public static synchronized ComponentManager getComponentManager() { 44 | if (componentManager != null) { 45 | return componentManager; 46 | } 47 | // ComponentManager is null so we have to try to figure out how to load 48 | // an instance. Look for a Java property. 49 | String className = System.getProperty("whack.componentManagerClass"); 50 | if (className != null) { 51 | try { 52 | Class c = Class.forName(className); 53 | componentManager = (ComponentManager) c.newInstance(); 54 | return componentManager; 55 | } catch (Exception e) { 56 | e.printStackTrace(); 57 | } 58 | } 59 | // Got here, so throw exception. 60 | throw new NullPointerException("No ComponentManager implementation available."); 61 | } 62 | 63 | /** 64 | * Sets the ComponentManager instance that will be used. 65 | * 66 | * @param manager the ComponentManager instance. 67 | */ 68 | public static void setComponentManager(ComponentManager manager) { 69 | componentManager = manager; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/packet/JIDEqualsHashCodeTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.packet; 18 | 19 | import junitx.extensions.EqualsHashCodeTestCase; 20 | import org.junit.Assert; 21 | 22 | /** 23 | * Tests functional compliance of {@link JID} with the equals and hashCode 24 | * contract. 25 | * 26 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 27 | */ 28 | public class JIDEqualsHashCodeTest extends EqualsHashCodeTestCase { 29 | 30 | public JIDEqualsHashCodeTest(String name) { 31 | super(name); 32 | } 33 | 34 | @Override 35 | protected Object createInstance() throws Exception { 36 | return new JID("node@domain/resource"); 37 | } 38 | 39 | @Override 40 | protected Object createNotEqualInstance() throws Exception { 41 | return new JID("edon@niamod/ecrouser"); 42 | } 43 | 44 | public void testNullOtherResource() throws Exception { 45 | // Setup fixture. 46 | final JID a = new JID( "node", "domain", "resource" ); 47 | final JID b = new JID( "node", "domain", null ); 48 | 49 | // Execute system under test. 50 | final boolean areEqual = a.equals( b ); 51 | 52 | // Verify results. 53 | Assert.assertFalse( areEqual ); 54 | } 55 | 56 | public void testNullResource() throws Exception { 57 | // Setup fixture. 58 | final JID a = new JID( "node", "domain", null ); 59 | final JID b = new JID( "node", "domain", "resource" ); 60 | 61 | // Execute system under test. 62 | final boolean areEqual = a.equals( b ); 63 | 64 | // Verify results. 65 | Assert.assertFalse( areEqual ); 66 | } 67 | 68 | public void testNullResources() throws Exception { 69 | // Setup fixture. 70 | final JID a = new JID( "node", "domain", null ); 71 | final JID b = new JID( "node", "domain", null ); 72 | 73 | // Execute system under test. 74 | final boolean areEqual = a.equals( b ); 75 | 76 | // Verify results. 77 | Assert.assertTrue( areEqual ); 78 | } 79 | 80 | public void testNullNode() throws Exception { 81 | // Setup fixture. 82 | final JID a = new JID( null, "domain", null ); 83 | final JID b = new JID( "node", "domain", null ); 84 | 85 | // Execute system under test. 86 | final boolean areEqual = a.equals( b ); 87 | 88 | // Verify results. 89 | Assert.assertFalse( areEqual ); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/muc/RoomConfiguration.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.muc; 18 | 19 | import net.jcip.annotations.NotThreadSafe; 20 | 21 | import org.dom4j.Element; 22 | import org.xmpp.packet.IQ; 23 | 24 | import java.util.Collection; 25 | import java.util.Map; 26 | import java.util.Map.Entry; 27 | 28 | /** 29 | * RoomConfiguration is a packet that helps to set the configuration of MUC rooms. RoomConfiguration 30 | * is a speacial IQ packet whose child element contains a data form. The data form holds the fields 31 | * to set together with a list of values.

32 | * 33 | * Code example: 34 | *

35 |  * {@code
36 |  * // Set the fields and the values.
37 |  * Map> fields = new HashMap>();
38 |  * // Make a non-public room
39 |  * List values = new ArrayList();
40 |  * values.add("0");
41 |  * fields.put("muc#roomconfig_publicroom", values);
42 |  *
43 |  * // Create a RoomConfiguration with the fields and values
44 |  * RoomConfiguration conf = new RoomConfiguration(fields);
45 |  * conf.setTo("room@conference.jabber.org");
46 |  * conf.setFrom("john@jabber.org/notebook");
47 |  *
48 |  * component.sendPacket(conf);
49 |  * }
50 |  * 
51 | * 52 | * @author Gaston Dombiak 53 | */ 54 | @NotThreadSafe 55 | public class RoomConfiguration extends IQ { 56 | 57 | /** 58 | * Creates a new IQ packet that contains the field and values to send for setting the room 59 | * configuration. 60 | * 61 | * @param fieldValues the list of fields associated with the list of values. 62 | */ 63 | public RoomConfiguration(Map> fieldValues) { 64 | super(); 65 | setType(Type.set); 66 | Element query = setChildElement("query", "http://jabber.org/protocol/muc#owner"); 67 | Element form = query.addElement("x", "jabber:x:data"); 68 | form.addAttribute("type", "submit"); 69 | // Add static field 70 | Element field = form.addElement("field"); 71 | field.addAttribute("var", "FORM_TYPE"); 72 | field.addElement("value").setText("http://jabber.org/protocol/muc#roomconfig"); 73 | // Add the specified fields and their corresponding values 74 | for (Entry> entry : fieldValues.entrySet()) { 75 | field = form.addElement("field"); 76 | field.addAttribute("var", entry.getKey()); 77 | for (String value : entry.getValue()) { 78 | field.addElement("value").setText(value); 79 | } 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | # Version 2022-02-15 2 | name: Java CI 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | strategy: 9 | matrix: 10 | java: [ "11", "17", "21" ] 11 | 12 | steps: 13 | # Checkout Repo 14 | - uses: actions/checkout@v6 15 | 16 | # Create a variable with this plugin's name 17 | - id: get-id 18 | name: Compute needed variables 19 | run: | 20 | set -x 21 | id=$(echo ${{ github.repository }} | cut -d- -f2) 22 | echo "::set-output name=id::$id" 23 | echo "id is '$id'" 24 | tag=$(echo ${{ github.ref }} | cut -d '/' -f3) 25 | echo "::set-output name=tag::$tag" 26 | echo "tag is '$tag'" 27 | version=$(echo ${{ github.ref }} | cut -d '/' -f3 | cut -c 2-) 28 | echo "::set-output name=version::$version" 29 | echo "version is '$version'" 30 | rel_id=$(curl -sL https://api.github.com/repos/${{github.repository}}/releases | jq -r --arg TAG "$tag" '.[] | select(.tag_name==$TAG) | .id') 31 | echo ::set-output name=rel_id::$rel_id 32 | echo "rel_id is '$rel_id'" 33 | 34 | - name: Setup JDK ${{ matrix.java }} 35 | uses: actions/setup-java@v5 36 | with: 37 | distribution: zulu 38 | java-version: ${{ matrix.java }} 39 | 40 | - name: Cache Maven repository 41 | uses: actions/cache@v5 42 | with: 43 | path: ~/.m2/repository 44 | key: ${{ runner.os }}-java${{ matrix.java }}-maven-${{ hashFiles('**/pom.xml') }} 45 | restore-keys: | 46 | ${{ runner.os }}-java${{ matrix.java }}-maven- 47 | ${{ runner.os }}- 48 | 49 | - name: Igniterealtime CI Tooling 50 | run: | 51 | git clone --depth 1 https://github.com/igniterealtime/ci-tooling.git target/ci-tooling 52 | cp target/ci-tooling/maven-settings-for-openfire-plugins.xml $HOME/.m2/settings.xml 53 | 54 | - name: Build with Maven 55 | run: mvn -B package 56 | 57 | - name: Conditionally Deploy to Igniterealtime Archiva 58 | id: deploy 59 | if: ${{ contains(github.repository, 'igniterealtime/') && ( ( github.event_name == 'push' && github.ref == 'refs/heads/main' ) || contains(github.ref, 'refs/tags/') ) && matrix.java == '11' }} 60 | run: mvn -B deploy --settings target/ci-tooling/maven-settings-for-tinder.xml -P ci 61 | env: 62 | CI_DEPLOY_USERNAME: ${{ secrets.IGNITE_REALTIME_MAVEN_USERNAME }} 63 | CI_DEPLOY_PASSWORD: ${{ secrets.IGNITE_REALTIME_MAVEN_PASSWORD }} 64 | 65 | - name: Conditionally Push Artifact to Github Release 66 | uses: actions/upload-release-asset@v1 67 | if: ${{ contains(github.repository, 'igniterealtime/') && github.event_name == 'push' && contains(github.ref, 'refs/tags/') && matrix.java == '11' }} 68 | env: 69 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 70 | with: 71 | upload_url: https://uploads.github.com/repos/${{ github.repository }}/releases/${{ steps.get-id.outputs.rel_id }}/assets?name=${{ steps.get-id.outputs.id }}.jar 72 | asset_path: target/${{ steps.get-id.outputs.id }}-${{ steps.get-id.outputs.version }}.jar 73 | asset_name: ${{ steps.get-id.outputs.id }}.jar 74 | asset_content_type: application/java-archive 75 | -------------------------------------------------------------------------------- /tinder.doap: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | Tinder 9 | tinder 10 | 11 | XMPP Library 12 | 13 | Tinder is a Java based XMPP library, providing an implementation for XMPP stanzas and components. Tinders origins lie in code that's shared between Ignite Realtime's 14 | Openfire and Whack implementations. The implementation that's provided in Tinder hasn't been written again from scratch. Instead, code has been moved from the original 15 | projects into Tinder, preserving al of the existing features and functionality. Most of the code that's now in Tinder is based on the 'org.xmpp' package implementation 16 | that previously existed in Openfire and Whack. This is the code that defines classes such as Packet, JID, IQ, Component and their extensions. Additionally, some 17 | multi-purpose code (such as the DataForm and Result Set Management implementations) have been moved to Tinder as well. 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | Java 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/component/SlowRespondingThreadNameComponent.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.component; 18 | 19 | import org.dom4j.Element; 20 | import org.xmpp.packet.IQ; 21 | 22 | /** 23 | * An {@link AbstractComponent} implementation that features debug 24 | * functionality, intended to be used by unit tests. 25 | * 26 | * This component will respond to IQ-get requests containing a child element 27 | * escaped by the namespace tinder:debug. If the child element name is 28 | * threadname, a response will be generated that reports the name of 29 | * the thread used to process the stanza, as shown: 30 | * 31 | *
32 |  * <iq type='get' id='debug_1'>
33 |  *   <threadname xmlns='tinder:debug'/>
34 |  * </iq>
35 |  * 
36 | * 37 | *
38 |  * <iq type='result' id='debug_1'>
39 |  *   <threadname xmlns='tinder:debug'>consumer-thread-34</threadname>
40 |  * </iq>
41 |  * 
42 | * 43 | * If the element name is slowresponse, an empty response will be 44 | * generated 4000 milliseconds after the request was delivered to the component. 45 | * 46 | *
47 |  * <iq type='get' id='debug_2'>
48 |  *   <slowresponse xmlns='tinder:debug'/>
49 |  * </iq>
50 |  * 
51 | * 52 | *
53 |  * <iq type='result' id='debug_2'/>
54 |  * 
55 | * 56 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 57 | */ 58 | public class SlowRespondingThreadNameComponent extends DummyAbstractComponent { 59 | 60 | public static final String DEBUG_NAMESPACE = "tinder:debug"; 61 | public static final String ELEMENTNAME_SLOWRESPONSE = "slowresponse"; 62 | public static final String ELEMENTNAME_THREADNAME = "threadname"; 63 | 64 | /** 65 | * Processes the tinder:debug requests. 66 | */ 67 | @Override 68 | protected IQ handleIQGet(IQ request) throws Exception { 69 | final Element element = request.getChildElement(); 70 | if (!DEBUG_NAMESPACE.equals(element.getNamespaceURI())) { 71 | log.debug("Can not process {}", request.toXML()); 72 | return null; 73 | } 74 | 75 | if (ELEMENTNAME_SLOWRESPONSE.equals(element.getName())) { 76 | log.debug("Waiting 4000 millis before responding to: {}", request 77 | .toXML()); 78 | Thread.sleep(4000); 79 | log.debug("Responding to {} now.", request.toXML()); 80 | return IQ.createResultIQ(request); 81 | } 82 | 83 | if (ELEMENTNAME_THREADNAME.equals(element.getName())) { 84 | final String threadName = Thread.currentThread().getName(); 85 | final IQ response = IQ.createResultIQ(request); 86 | response.setChildElement(ELEMENTNAME_THREADNAME, DEBUG_NAMESPACE) 87 | .addText(threadName); 88 | log.debug("Responding to {} with {}", request.toXML(), response 89 | .toXML()); 90 | return response; 91 | } 92 | 93 | log.debug("Cannot process {}", request.toXML()); 94 | return null; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/component/Component.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.component; 18 | 19 | import org.xmpp.packet.JID; 20 | import org.xmpp.packet.Packet; 21 | 22 | /** 23 | * Components enhance the functionality of an XMPP server. Components receive 24 | * all packets addressed to a particular sub-domain. For example, 25 | * test_component.example.com. So, a packet sent to 26 | * joe@test_component.example.com would be delivered to the component. 27 | * Note that the sub-domains defined as components are unrelated to DNS entries 28 | * for sub-domains. All XMPP routing at the socket level is done using the 29 | * primary server domain (example.com in the example above); sub-domains are 30 | * only used for routing within the XMPP server. 31 | * 32 | * @author Matt Tucker 33 | */ 34 | public interface Component { 35 | 36 | /** 37 | * Returns the name of this component. 38 | * 39 | * @return the name of this component. 40 | */ 41 | String getName(); 42 | 43 | /** 44 | * Returns the description of this component. 45 | * 46 | * @return the description of this component. 47 | */ 48 | String getDescription(); 49 | 50 | /** 51 | * Processes a packet sent to this Component. 52 | * 53 | * @param packet the packet. 54 | * @see ComponentManager#sendPacket(Component, Packet) 55 | */ 56 | void processPacket(Packet packet); 57 | 58 | /** 59 | * Initializes this component with a ComponentManager and the JID 60 | * that this component is available at (e.g. service.example.com). If a 61 | * ComponentException is thrown then the component will not be loaded.

62 | * 63 | * The initialization code must not rely on receiving packets from the server since 64 | * the component has not been fully initialized yet. This means that at this point the 65 | * component must not rely on information that is obtained from the server such us 66 | * discovered items. 67 | * 68 | * @param jid the XMPP address that this component is available at. 69 | * @param componentManager the component manager. 70 | * @throws ComponentException if an error occured while initializing the component. 71 | */ 72 | void initialize(JID jid, ComponentManager componentManager) throws ComponentException; 73 | 74 | /** 75 | * Notification message indicating that the component will start receiving incoming 76 | * packets. At this time the component may finish pending initialization issues that 77 | * require information obtained from the server.

78 | * 79 | * It is likely that most of the component will leave this method empty. 80 | */ 81 | void start(); 82 | 83 | /** 84 | * Shuts down this component. All component resources must be released as 85 | * part of shutdown. 86 | */ 87 | void shutdown(); 88 | } 89 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/packet/NodePrepTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.packet; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | import org.junit.Test; 22 | 23 | /** 24 | * Verifies {@link JID#nodeprep(String)}. 25 | * 26 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 27 | */ 28 | public class NodePrepTest { 29 | 30 | /** 31 | * Basic test that verifies that a string that shouldn't be modified by 32 | * node-prepping gets prepped without a problem. 33 | */ 34 | @Test 35 | public void testValidString() throws Exception { 36 | // setup 37 | final String node = "node"; 38 | 39 | // do magic 40 | final String result = JID.nodeprep(node); 41 | 42 | // verify 43 | assertEquals(node, result); 44 | } 45 | 46 | /** 47 | * Checks that node-prepping is case insensitive. 48 | */ 49 | @Test 50 | public void testCaseSensitivity() throws Exception { 51 | // setup 52 | final String node = "nOdE"; 53 | 54 | // do magic 55 | final String result = JID.nodeprep(node); 56 | 57 | // verify 58 | assertEquals(node.toLowerCase(), result); 59 | } 60 | 61 | /** 62 | * Verifies that an input value bigger than 1023 bytes will cause an 63 | * exception to be thrown. 64 | */ 65 | @Test(expected = IllegalArgumentException.class) 66 | public void testToLong() throws Exception { 67 | // setup 68 | final StringBuilder builder = new StringBuilder(); 69 | for (int i = 0; i < 1024; i++) { 70 | builder.append('a'); 71 | } 72 | builder.append('a'); 73 | final String toBig = builder.toString(); 74 | 75 | // do magic / verify 76 | JID.nodeprep(toBig); 77 | } 78 | 79 | /** 80 | * Verifies that Stringprep mapping is correctly executed. This test uses a 81 | * 'word joiner' character, which is listed on the B1 table of Stringprep. 82 | * Characters on this table must be mapped in resource strings, according to 83 | * RFC 3920. This specific character should be mapped to nothing. 84 | */ 85 | @Test 86 | public void testMapping() throws Exception { 87 | // setup; 88 | final String input = "word\u2060joiner"; 89 | 90 | // do magic 91 | final String result = JID.nodeprep(input); 92 | 93 | // verify 94 | assertEquals("wordjoiner", result); 95 | } 96 | 97 | /** 98 | * Checks cache usage, by making sure that a subsequent request returns the 99 | * stringprepped answer, not the input data. Input data often equals the 100 | * prepped answer, which allows a bug like this to slip by easily. 101 | */ 102 | @Test 103 | public void testCachedResult() throws Exception { 104 | // setup; 105 | final String input = "bword\u2060joiner"; 106 | 107 | // do magic 108 | final String result1 = JID.nodeprep(input); 109 | final String result2 = JID.nodeprep(input); 110 | 111 | // verify 112 | assertEquals("bwordjoiner", result1); 113 | assertEquals(result1, result2); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/packet/DomainPrepTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.packet; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | import org.junit.Test; 22 | 23 | /** 24 | * Verifies {@link JID#domainprep(String)}. 25 | * 26 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 27 | */ 28 | public class DomainPrepTest { 29 | 30 | /** 31 | * Basic test that verifies that a string that shouldn't be modified by 32 | * domain-prepping gets prepped without a problem. 33 | */ 34 | @Test 35 | public void testValidString() throws Exception { 36 | // setup 37 | final String domain = "domain"; 38 | 39 | // do magic 40 | final String result = JID.domainprep(domain); 41 | 42 | // verify 43 | assertEquals(domain, result); 44 | } 45 | 46 | /** 47 | * Checks that domain-prepping is case insensitive. 48 | */ 49 | @Test 50 | public void testCaseSensitivity() throws Exception { 51 | // setup 52 | final String domain = "dOmAiN"; 53 | 54 | // do magic 55 | final String result = JID.domainprep(domain); 56 | 57 | // verify 58 | assertEquals(domain.toLowerCase(), result); 59 | } 60 | 61 | /** 62 | * Verifies that an input value bigger than 1023 bytes will cause an 63 | * exception to be thrown. 64 | */ 65 | @Test(expected = IllegalArgumentException.class) 66 | public void testToLong() throws Exception { 67 | // setup 68 | final StringBuilder builder = new StringBuilder(); 69 | for (int i = 0; i < 1023; i++) { 70 | builder.append('a'); 71 | } 72 | builder.append(".a"); 73 | final String toBig = builder.toString(); 74 | 75 | // do magic / verify 76 | JID.domainprep(toBig); 77 | } 78 | 79 | /** 80 | * Verifies that Stringprep mapping is correctly executed. This test uses a 81 | * 'word joiner' character, which is listed on the B1 table of Stringprep. 82 | * Characters on this table must be mapped in resource strings, according to 83 | * RFC 3920. This specific character should be mapped to nothing. 84 | */ 85 | @Test 86 | public void testMapping() throws Exception { 87 | // setup; 88 | final String input = "word\u2060joiner"; 89 | 90 | // do magic 91 | final String result = JID.domainprep(input); 92 | 93 | // verify 94 | assertEquals("wordjoiner", result); 95 | } 96 | 97 | /** 98 | * Checks cache usage, by making sure that a subsequent request returns the 99 | * stringprepped answer, not the input data. Input data often equals the 100 | * prepped answer, which allows a bug like this to slip by easily. 101 | */ 102 | @Test 103 | public void testCachedResult() throws Exception { 104 | // setup; 105 | final String input = "bword\u2060joiner"; 106 | 107 | // do magic 108 | final String result1 = JID.domainprep(input); 109 | final String result2 = JID.domainprep(input); 110 | 111 | // verify 112 | assertEquals("bwordjoiner", result1); 113 | assertEquals(result1, result2); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/packet/ResourcePrepTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.packet; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | import org.junit.Test; 22 | 23 | /** 24 | * Verifies {@link JID#resourceprep(String)}. 25 | * 26 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 27 | */ 28 | public class ResourcePrepTest { 29 | 30 | /** 31 | * Basic test that verifies that a string that shouldn't be modified by 32 | * resource-prepping gets prepped without a problem. 33 | */ 34 | @Test 35 | public void testValidString() throws Exception { 36 | // setup 37 | final String resource = "resource"; 38 | 39 | // do magic 40 | final String result = JID.resourceprep(resource); 41 | 42 | // verify 43 | assertEquals(resource, result); 44 | } 45 | 46 | /** 47 | * Checks that resource-prepping is case sensitive. 48 | */ 49 | @Test 50 | public void testCaseSensitivity() throws Exception { 51 | // setup 52 | final String resource = "rEsOuRcE"; 53 | 54 | // do magic 55 | final String result = JID.resourceprep(resource); 56 | 57 | // verify 58 | assertEquals(resource, result); 59 | } 60 | 61 | /** 62 | * Verifies that an input value bigger than 1023 bytes will cause an 63 | * exception to be thrown. 64 | */ 65 | @Test(expected = IllegalArgumentException.class) 66 | public void testToLong() throws Exception { 67 | // setup 68 | final StringBuilder builder = new StringBuilder(); 69 | for (int i = 0; i < 1024; i++) { 70 | builder.append('a'); 71 | } 72 | builder.append('a'); 73 | final String toBig = builder.toString(); 74 | 75 | // do magic / verify 76 | JID.resourceprep(toBig); 77 | } 78 | 79 | /** 80 | * Verifies that Stringprep mapping is correctly executed. This test uses a 81 | * 'word joiner' character, which is listed on the B1 table of Stringprep. 82 | * Characters on this table must be mapped in resource strings, according to 83 | * RFC 3920. This specific character should be mapped to nothing. 84 | */ 85 | @Test 86 | public void testMapping() throws Exception { 87 | // setup; 88 | final String input = "word\u2060joiner"; 89 | 90 | // do magic 91 | final String result = JID.resourceprep(input); 92 | 93 | // verify 94 | assertEquals("wordjoiner", result); 95 | } 96 | 97 | /** 98 | * Checks cache usage, by making sure that a subsequent request returns the 99 | * stringprepped answer, not the input data. Input data often equals the 100 | * prepped answer, which allows a bug like this to slip by easily. 101 | */ 102 | @Test 103 | public void testCachedResult() throws Exception { 104 | // setup; 105 | final String input = "bword\u2060joiner"; 106 | 107 | // do magic 108 | final String result1 = JID.resourceprep(input); 109 | final String result2 = JID.resourceprep(input); 110 | 111 | // verify 112 | assertEquals("bwordjoiner", result1); 113 | assertEquals(result1, result2); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/forms/DataFormTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2022 Ignite Realtime Foundation. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.xmpp.forms; 17 | 18 | import org.junit.Test; 19 | 20 | import java.time.LocalDateTime; 21 | import java.time.ZoneId; 22 | import java.time.ZoneOffset; 23 | import java.time.ZonedDateTime; 24 | import java.util.Date; 25 | 26 | import static org.junit.Assert.assertEquals; 27 | import static org.junit.Assert.fail; 28 | 29 | /** 30 | * This test verifies the implementation of {@link DataForm}. 31 | * 32 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 33 | */ 34 | public class DataFormTest 35 | { 36 | /** 37 | * Verifies that {@link DataForm#encode(Object)} throws a NullPointerException when the provided input is null. 38 | */ 39 | @Test(expected = NullPointerException.class) 40 | public void encodeNull() throws Exception 41 | { 42 | // Set up test fixture. 43 | final Object input = null; 44 | 45 | // Execute System under test. 46 | DataForm.encode(input); 47 | 48 | // Verify results. 49 | fail("A NullPointerException should have been thrown"); 50 | } 51 | 52 | /** 53 | * Verifies that {@link DataForm#encode(Object)} returns a String that is equal to a String that is provided as input. 54 | */ 55 | @Test 56 | public void encodeString() throws Exception 57 | { 58 | // Set up test fixture. 59 | final Object input = "A string"; 60 | 61 | // Execute System under test. 62 | final String result = DataForm.encode(input); 63 | 64 | // Verify results. 65 | assertEquals("A string", result); 66 | } 67 | 68 | /** 69 | * Verifies that {@link DataForm#encode(Object)} returns '1' when the provided input is a boolean 'true'. 70 | */ 71 | @Test 72 | public void encodeTrue() throws Exception 73 | { 74 | // Set up test fixture. 75 | final Object input = Boolean.TRUE; 76 | 77 | // Execute System under test. 78 | final String result = DataForm.encode(input); 79 | 80 | // Verify results. 81 | assertEquals("1", result); 82 | } 83 | 84 | /** 85 | * Verifies that {@link DataForm#encode(Object)} returns '0' when the provided input is a boolean 'false'. 86 | */ 87 | @Test 88 | public void encodeFalse() throws Exception 89 | { 90 | // Set up test fixture. 91 | final Object input = Boolean.FALSE; 92 | 93 | // Execute System under test. 94 | final String result = DataForm.encode(input); 95 | 96 | // Verify results. 97 | assertEquals("0", result); 98 | } 99 | 100 | /** 101 | * Verifies that {@link DataForm#encode(Object)} returns a String that conforms to a specific format when the input 102 | * that is provided is a Date. 103 | */ 104 | @Test 105 | public void encodeDate() throws Exception 106 | { 107 | // Set up test fixture. 108 | final ZonedDateTime zdt = ZonedDateTime.of(1979, 11, 27, 17, 42, 51, 201312, ZoneId.of("+01:00")); 109 | final Object input = Date.from(zdt.toInstant()); 110 | 111 | // Execute System under test. 112 | final String result = DataForm.encode(input); 113 | 114 | // Verify results. 115 | assertEquals("19791127T16:42:51", result); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/packet/PacketExtension.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.packet; 18 | 19 | import java.util.Map; 20 | import java.util.concurrent.ConcurrentHashMap; 21 | 22 | import net.jcip.annotations.NotThreadSafe; 23 | 24 | import org.dom4j.DocumentFactory; 25 | import org.dom4j.Element; 26 | import org.dom4j.QName; 27 | 28 | /** 29 | * A packet extension represents a child element of a Packet for a given qualified name. The 30 | * PacketExtension acts as a wrapper on a child element the same way Packet does for a whole 31 | * element. The wrapper provides an easy way to handle the packet extension.

32 | * 33 | * Subclasses of this class can be registered using the static variable 34 | * registeredExtensions. The registration process associates the new subclass 35 | * with a given qualified name (ie. element name and namespace). This information will be used by 36 | * {@link Packet#getExtension(String, String)} for locating the corresponding PacketExtension 37 | * subclass to return for the requested qualified name. Each PacketExtension must have a public 38 | * constructor that takes an Element instance as an argument. 39 | * 40 | * @author Gaston Dombiak 41 | */ 42 | @NotThreadSafe 43 | public class PacketExtension { 44 | 45 | protected static final DocumentFactory docFactory = DocumentFactory.getInstance(); 46 | /** 47 | * Subclasses of PacketExtension should register the element name and namespace that the 48 | * subclass is using. 49 | */ 50 | protected static final Map> registeredExtensions = new ConcurrentHashMap<>(); 51 | 52 | protected Element element; 53 | 54 | /** 55 | * Returns the extension class to use for the specified element name and namespace. For 56 | * instance, the DataForm class should be used for the element "x" and 57 | * namespace "jabber:x:data". 58 | * 59 | * @param name the child element name. 60 | * @param namespace the child element namespace. 61 | * @return the extension class to use for the specified element name and namespace. 62 | */ 63 | public static Class getExtensionClass(String name, String namespace) { 64 | return registeredExtensions.get(QName.get(name, namespace)); 65 | } 66 | 67 | /** 68 | * Constructs a new Packet extension using the specified name and namespace. 69 | * 70 | * @param name the child element name. 71 | * @param namespace the child element namespace. 72 | */ 73 | public PacketExtension(String name, String namespace) { 74 | this.element = docFactory.createDocument().addElement(name, namespace); 75 | } 76 | 77 | /** 78 | * Constructs a new PacketExtension. 79 | * 80 | * @param element the XML Element that contains the packet extension contents. 81 | */ 82 | public PacketExtension(Element element) { 83 | this.element = element; 84 | } 85 | 86 | /** 87 | * Returns the DOM4J Element that backs the packet. The element is the definitive 88 | * representation of the packet and can be manipulated directly to change 89 | * packet contents. 90 | * 91 | * @return the DOM4J Element that represents the packet. 92 | */ 93 | public Element getElement() { 94 | return element; 95 | } 96 | 97 | /** 98 | * Creates a deep copy of this packet extension. 99 | * 100 | * @return a deep copy of this packet extension. 101 | */ 102 | public PacketExtension createCopy() { 103 | Element copy = element.createCopy(); 104 | docFactory.createDocument().add(copy); 105 | return new PacketExtension(element); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/component/AbstractComponentIsConsumerTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.component; 18 | 19 | import static org.junit.Assert.assertFalse; 20 | import static org.junit.Assert.assertTrue; 21 | 22 | import org.dom4j.Element; 23 | import org.junit.After; 24 | import org.junit.Before; 25 | import org.junit.Test; 26 | import org.xmpp.packet.IQ; 27 | import org.xmpp.packet.IQ.Type; 28 | 29 | /** 30 | * The {@link AbstractComponent} implementation follows the producer/consumer 31 | * design pattern. The tests in this class verifies that characteristics of this 32 | * pattern are recognizable in the AbstractComponent implementation. 33 | * 34 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 35 | * @see Tinder 36 | * bugtracker: TINDER-18 37 | */ 38 | public class AbstractComponentIsConsumerTest { 39 | 40 | private DummyAbstractComponent debugComp = null; 41 | 42 | /** 43 | * Starts a fresh new component before each test. 44 | */ 45 | @Before 46 | public void setUp() { 47 | debugComp = new SlowRespondingThreadNameComponent(); 48 | debugComp.start(); 49 | } 50 | 51 | /** 52 | * Shuts down the component after each test. 53 | */ 54 | @After 55 | public void tearDown() { 56 | if (debugComp != null) { 57 | debugComp.shutdown(); 58 | } 59 | } 60 | 61 | /** 62 | * The actual work being done by the component (the consumer) should be done 63 | * by a different thread than the thread that feeds the input (the 64 | * producer). 65 | * 66 | * This test uses an AbstractComponent implementation that reports the 67 | * thread name that was used during processing. This name is compared with 68 | * the name of the thread that feeds the component the request packet (the 69 | * producer) to verify that the producer and consumer threads are indeed 70 | * different. 71 | */ 72 | @Test 73 | public void consumesOnDifferentThreadTest() throws Exception { 74 | // setup 75 | final String producerThreadName = Thread.currentThread().getName(); 76 | final IQ request = new IQ(Type.get); 77 | request.setChildElement( 78 | SlowRespondingThreadNameComponent.ELEMENTNAME_THREADNAME, 79 | SlowRespondingThreadNameComponent.DEBUG_NAMESPACE); 80 | 81 | // do magic 82 | debugComp.processPacket(request); 83 | final IQ response = (IQ) debugComp.getSentPacket(); 84 | 85 | // verify 86 | final Element elem = response.getChildElement(); 87 | final String consumerThreadName = elem.getText(); 88 | assertFalse(consumerThreadName.equals(producerThreadName)); 89 | } 90 | 91 | /** 92 | * The producer thread should be released as soon as it delivers work to the 93 | * consumer, regardless of how long the consumer takes to process a packet. 94 | * 95 | * This test uses an AbstractComponent implementation that takes a 96 | * significant time to process a packet. The test verifies that the producer 97 | * thread finishes work before the consumer threads finish. This verifies 98 | * that the workload has been properly offloaded by the producer thread. 99 | */ 100 | @Test 101 | public void consumesAsynchronouslyTest() throws Exception { 102 | // setup 103 | final IQ request = new IQ(Type.get); 104 | request.setChildElement( 105 | SlowRespondingThreadNameComponent.ELEMENTNAME_SLOWRESPONSE, 106 | SlowRespondingThreadNameComponent.DEBUG_NAMESPACE); 107 | 108 | // do magic 109 | final long start = System.currentTimeMillis(); 110 | debugComp.processPacket(request); 111 | final long end = System.currentTimeMillis(); 112 | 113 | // verify 114 | final long elapsed = end - start; 115 | assertTrue(elapsed < 4000); 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/util/ValueWrapper.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.util; 18 | 19 | import java.io.Serializable; 20 | import java.util.Map; 21 | 22 | import net.jcip.annotations.Immutable; 23 | 24 | /** 25 | * A wrapper implementation for cached values, suitable for {@link Map} based 26 | * caches where a significant portion of keys matches the corresponding value 27 | * exactly. 28 | * 29 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 30 | */ 31 | @Immutable 32 | public class ValueWrapper implements Serializable { 33 | 34 | private static final long serialVersionUID = 3685221890410462582L; 35 | 36 | /** 37 | * Indication of how the key of this cache entry represents the cache value. 38 | */ 39 | public enum Representation { 40 | 41 | /** 42 | * The key that maps to this {@link ValueWrapper} instance cannot be 43 | * used to generate a valid value. 44 | */ 45 | ILLEGAL, 46 | 47 | /** 48 | * The generated value based on the key that maps to this 49 | * {@link ValueWrapper} would be an exact duplicate of the key. To 50 | * conserve memory, this wrapped value instance will not have a value 51 | * set. Use the key that points to this wrapper instead. 52 | */ 53 | USE_KEY, 54 | 55 | /** 56 | * The key that maps to this {@link ValueWrapper} can be used to 57 | * generate a valid value. The generated value is wrapped in this 58 | * {@link ValueWrapper} instance. 59 | */ 60 | USE_VALUE 61 | } 62 | 63 | /** 64 | * The value that is wrapped. 65 | */ 66 | private final V value; 67 | 68 | /** 69 | * Indicates how the key that maps to this value can be used to extract the 70 | * value from the cache entry. 71 | */ 72 | private final Representation representation; 73 | 74 | /** 75 | * Describes the issue that caused the value to be denoted as 'Illegal'. 76 | */ 77 | private final String exceptionMessage; 78 | 79 | /** 80 | * Constructs an empty wrapper. This wrapper is used to indicate that 81 | * the key that maps to this value is an exact duplicate of the generated value. 82 | */ 83 | public ValueWrapper() { 84 | this.representation = Representation.USE_KEY; 85 | this.value = null; 86 | this.exceptionMessage = null; 87 | } 88 | 89 | /** 90 | * Constructs a wrapper that is used to indicate that the key that maps to 91 | * this value cannot be used to generate a valid value 92 | * 93 | * @param exception 94 | * Describes the invalidity of the key. 95 | */ 96 | public ValueWrapper(Exception exception) { 97 | this.representation = Representation.ILLEGAL; 98 | this.value = null; 99 | this.exceptionMessage = exception.getMessage(); 100 | } 101 | 102 | /** 103 | * Wraps a value while using the USE_VALUE representation. 104 | * 105 | * @param value 106 | * The value that is wrapped. 107 | */ 108 | public ValueWrapper(V value) { 109 | this.representation = Representation.USE_VALUE; 110 | this.value = value; 111 | this.exceptionMessage = null; 112 | } 113 | 114 | /** 115 | * Returns the wrapped value, or null if the representation used in 116 | * this instance is not USE_VALUE; 117 | * 118 | * @return the wrapped value. 119 | */ 120 | public V getValue() { 121 | return value; 122 | } 123 | 124 | public Representation getRepresentation() { 125 | return representation; 126 | } 127 | 128 | /** 129 | * Returns the message describing the invalidity of the key that maps 130 | * to this instance. 131 | * 132 | * @return An exception message , possibly null. 133 | */ 134 | public String getExceptionMessage() { 135 | return exceptionMessage; 136 | } 137 | 138 | @Override 139 | public String toString() 140 | { 141 | return "ValueWrapper{" + 142 | "value=" + value + 143 | ", representation=" + representation + 144 | ", exceptionMessage='" + exceptionMessage + '\'' + 145 | '}'; 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/packet/StringPrepCacheTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.packet; 18 | 19 | import org.junit.Test; 20 | 21 | /** 22 | * A testcase that verifies the effect of stringprep caching in the JID class. 23 | *

24 | * This testcase, amongst others, checks for a bug identified as TINDER-8: If 25 | * the same cache is used to store StringPrep results, a problem might be 26 | * introduced: a particular value might be valid for one identifier of the JID, 27 | * while it is illegal for another identifier of the JID. 28 | *

29 | * Implementation note: do not re-use the same values in different tests. As we 30 | * have no control over the JID cache, we might end up testing against a cached 31 | * value of the cache that's being tested by this JUnit testcase. 32 | * 33 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 34 | * @see Tinder 35 | * bugtracker: TINDER-8 36 | */ 37 | public class StringPrepCacheTest { 38 | 39 | /** 40 | * Verifies that when a cached instance is used to construct a JID, no 41 | * unexpected exceptions pop up. 42 | */ 43 | @Test 44 | public void testNode() { 45 | new JID("validnode", "validdomain", "validresource"); 46 | new JID("validnode", "validdomain", "validresource"); 47 | } 48 | 49 | /** 50 | * Verify cache usage, by inserting a value in the cache that's a valid 51 | * node, but an invalid domain identifier. Next, create a JID that uses this 52 | * value for its domain identifier. This JID constructions should fail, but 53 | * will succeed if the cache that was used to store the node-value is the 54 | * same cache that's used to lookup previously stringprepped domain 55 | * identifiers. 56 | */ 57 | @Test(expected = IllegalArgumentException.class) 58 | public void testNodeDomainCacheLookup() { 59 | // valid value for node identifier, invalid for domain identifier 60 | final String value = "-test-a-"; 61 | 62 | // populate the cache (value is valid in the context of a node) 63 | new JID(value, "validdomain.org", "validresource"); 64 | 65 | // verify if the cache gets re-used to lookup value. 66 | new JID("validnode", value, "validresource"); 67 | } 68 | 69 | /** 70 | * Verify cache usage, by inserting a value in the cache that's a valid 71 | * resource, but an invalid domain identifier. Next, create a JID that uses 72 | * this value for its domain identifier. This JID constructions should fail, 73 | * but will succeed if the cache that was used to store the resource-value 74 | * is the same cache that's used to lookup previously stringprepped domain 75 | * identifiers. 76 | */ 77 | @Test(expected = IllegalArgumentException.class) 78 | public void testResourceDomainCacheLookup() { 79 | // valid value for resource identifier, invalid for domain identifier 80 | final String value = "-test-b-"; 81 | 82 | // populate the cache (value is valid in the context of a node) 83 | new JID("validnode", "validdomain.org", value); 84 | 85 | // verify if the cache gets re-used to lookup value. 86 | new JID("validnode", value, "validresource"); 87 | } 88 | 89 | /** 90 | * Verify cache usage, by inserting a value in the cache that's a valid 91 | * resource, but an invalid node identifier. Next, create a JID that uses 92 | * this value for its domain identifier. This JID constructions should fail, 93 | * but will succeed if the cache that was used to store the resource-value 94 | * is the same cache that's used to lookup previously stringprepped node 95 | * identifiers. 96 | */ 97 | @Test(expected = IllegalArgumentException.class) 98 | public void testResourceNodeCacheLookup() { 99 | // valid value for resource identifier, invalid for nodeidentifier 100 | final String value = "test@c"; 101 | 102 | // populate the cache (value is valid in the context of a resource) 103 | new JID("validnode", "validdomain.org", value); 104 | 105 | // verify if the cache gets re-used to lookup value. 106 | new JID(value, "valid_domain", "validresource"); 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/packet/JIDCreationDomainTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.packet; 18 | 19 | import static org.junit.Assert.*; 20 | 21 | import org.junit.Test; 22 | 23 | /** 24 | * Tests compliance of {@link JID} with the restrictions defined in RFC-3920 for 25 | * the domain identifier. 26 | * 27 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 28 | * @see RFC 3920 - Extensible 29 | * Messaging and Presence Protocol (XMPP): Core 30 | */ 31 | public class JIDCreationDomainTest { 32 | 33 | /** 34 | * A node identifier that's RFC 3920 valid. 35 | */ 36 | public static final String NODE = "node"; 37 | 38 | /** 39 | * A domain identifier that's RFC 3920 valid. 40 | */ 41 | public static final String DOMAIN = "domain"; 42 | 43 | /** 44 | * A resource identifier that's RFC 3920 valid. 45 | */ 46 | public static final String RESOURCE = "resource"; 47 | 48 | /** 49 | * Domain identifiers are a required part of a JID. This testcase 50 | * verifies that node identifiers can be left out of the creation of a JID. 51 | */ 52 | @Test 53 | public void testOptionality() throws Exception { 54 | try { 55 | new JID(null); 56 | fail("Domain identifiers should be a required part of " 57 | + "a JID. No exception occurred while trying to " 58 | + "leave out a domain identifier"); 59 | } catch (IllegalArgumentException | NullPointerException ex) { 60 | // expected 61 | } 62 | 63 | try { 64 | new JID(null, null, null); 65 | fail("Domain identifiers should be a required part of " 66 | + "a JID. No exception occurred while trying to " 67 | + "leave out a domain identifier"); 68 | } catch (IllegalArgumentException | NullPointerException ex) { 69 | // expected 70 | } 71 | 72 | try { 73 | new JID(NODE, null, null); 74 | fail("Domain identifiers should be a required part of " 75 | + "a JID. No exception occurred while trying to " 76 | + "leave out a domain identifier"); 77 | } catch (IllegalArgumentException | NullPointerException ex) { 78 | // expected 79 | } 80 | 81 | try { 82 | new JID(null, null, RESOURCE); 83 | fail("Domain identifiers should be a required part of " 84 | + "a JID. No exception occurred while trying to " 85 | + "leave out a domain identifier"); 86 | } catch (IllegalArgumentException | NullPointerException ex) { 87 | // expected 88 | } 89 | 90 | try { 91 | new JID(NODE, null, RESOURCE); 92 | fail("Domain identifiers should be a required part of " 93 | + "a JID. No exception occurred while trying to " 94 | + "leave out a domain identifier"); 95 | } catch (IllegalArgumentException | NullPointerException ex) { 96 | // expected 97 | } 98 | } 99 | 100 | /** 101 | * The maximum size of the domain identifier is 1023 bytes (note: bytes, not 102 | * characters!). This test verifies that using as much characters as 103 | * possible without crossing the 1023 byte boundry, will not cause a 104 | * problem. 105 | */ 106 | @Test 107 | public void testMaximumSize() throws Exception { 108 | // setup 109 | final StringBuilder builder = new StringBuilder("a"); 110 | for (int i = 0; i < 511; i++) { 111 | builder.append(".a"); 112 | } 113 | final String longestPossibleValue = builder.toString(); 114 | 115 | // do magic / verify 116 | new JID(NODE, longestPossibleValue, RESOURCE); 117 | } 118 | 119 | /** 120 | * The maximum size of the domain identifier is 1023 bytes (note: bytes, not 121 | * characters!). This test verifies that using more bytes will cause an 122 | * exception to be thrown. 123 | */ 124 | @Test(expected = IllegalArgumentException.class) 125 | public void testOverMaximumSize() throws Exception { 126 | // setup 127 | final StringBuilder builder = new StringBuilder("a"); 128 | for (int i = 0; i < 512; i++) { 129 | builder.append(".a"); 130 | } 131 | final String toBig = builder.toString(); 132 | 133 | // do magic / verify 134 | new JID(NODE, toBig, RESOURCE); 135 | } 136 | 137 | /** 138 | * Verifies that the bare representation of a JID that contains a domain 139 | * name only corresponds to the domain name itself. 140 | */ 141 | @Test 142 | public void testBareJID() throws Exception { 143 | // setup 144 | final JID fullJID = new JID(null, DOMAIN, null); 145 | 146 | // do magic 147 | final String bareJID = fullJID.toBareJID(); 148 | 149 | // verify 150 | assertEquals(DOMAIN, bareJID); 151 | } 152 | } 153 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/packet/JIDCreationResourceTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.packet; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | 21 | import org.junit.Test; 22 | 23 | /** 24 | * Tests compliance of {@link JID} with the restrictions defined in RFC-3920 for 25 | * the resource identifier. 26 | * 27 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 28 | * @see RFC 3920 - Extensible 29 | * Messaging and Presence Protocol (XMPP): Core 30 | */ 31 | public class JIDCreationResourceTest { 32 | 33 | /** 34 | * A node identifier that's RFC 3920 valid. 35 | */ 36 | public static final String NODE = "node"; 37 | 38 | /** 39 | * A domain identifier that's RFC 3920 valid. 40 | */ 41 | public static final String DOMAIN = "domain"; 42 | 43 | /** 44 | * A resource identifier that's RFC 3920 valid. 45 | */ 46 | public static final String RESOURCE = "resource"; 47 | 48 | /** 49 | * Resource identifiers are an optional part of a JID. This testcase 50 | * verifies that resource identifiers can be left out of the creation of a 51 | * JID. 52 | */ 53 | @Test 54 | public void testOptionality() throws Exception { 55 | assertEquals(DOMAIN, new JID(DOMAIN).toString()); 56 | assertEquals(DOMAIN, new JID(null, DOMAIN, null).toString()); 57 | assertEquals(NODE + '@' + DOMAIN, new JID(NODE, DOMAIN, null).toString()); 58 | assertEquals(NODE + '@' + DOMAIN, new JID(NODE, DOMAIN, "").toString()); 59 | } 60 | 61 | /** 62 | * The maximum size of the resource identifier is 1023 bytes (note: bytes, 63 | * not characters!). This test verifies that using as much characters as 64 | * possible without crossing the 1023 byte boundry, will not cause a 65 | * problem. 66 | */ 67 | @Test 68 | public void testMaximumSizeOnByteChar() throws Exception { 69 | // setup 70 | final StringBuilder builder = new StringBuilder(); 71 | for (int i = 0; i < 1023; i++) { 72 | builder.append('a'); 73 | } 74 | final String longestPossibleValue = builder.toString(); 75 | 76 | // do magic / verify 77 | new JID(NODE, DOMAIN, longestPossibleValue); 78 | } 79 | 80 | /** 81 | * The maximum size of the resource identifier is 1023 bytes (note: bytes, 82 | * not characters!). This test verifies that using more bytes will cause an 83 | * exception to be thrown. 84 | */ 85 | @Test(expected = IllegalArgumentException.class) 86 | public void testOverMaximumSizeOnByteChar() throws Exception { 87 | // setup 88 | final StringBuilder builder = new StringBuilder(); 89 | for (int i = 0; i < 1024; i++) { 90 | builder.append('a'); 91 | } 92 | builder.append('a'); 93 | final String toBig = builder.toString(); 94 | 95 | // do magic / verify 96 | new JID(NODE, DOMAIN, toBig); 97 | } 98 | 99 | /** 100 | * UTF-8 characters use 1 to 4 bytes. The JID implementation should 101 | * correctly identify the length of all UTF-8 characters. 102 | * 103 | * This issue has been filed as TINDER-32 104 | * 105 | * @see Tinder 107 | * bugtracker: TINDER-32Tinder 134 | * bugtracker: TINDER-32RFC 3920 - Extensible 29 | * Messaging and Presence Protocol (XMPP): Core 30 | */ 31 | public class JIDCreationNodeTest { 32 | 33 | /** 34 | * A node identifier that's RFC 3920 valid. 35 | */ 36 | public static final String NODE = "node"; 37 | 38 | /** 39 | * A domain identifier that's RFC 3920 valid. 40 | */ 41 | public static final String DOMAIN = "domain"; 42 | 43 | /** 44 | * A resource identifier that's RFC 3920 valid. 45 | */ 46 | public static final String RESOURCE = "resource"; 47 | 48 | /** 49 | * Node identifiers are an optional part of a JID. This testcase verifies 50 | * that node identifiers can be left out of the creation of a JID. 51 | */ 52 | @Test 53 | public void testOptionality() throws Exception { 54 | assertEquals(DOMAIN, new JID(DOMAIN).toString()); 55 | assertEquals(DOMAIN, new JID(null, DOMAIN, null).toString()); 56 | assertEquals(DOMAIN + '/' + RESOURCE, new JID(null, DOMAIN, RESOURCE).toString()); 57 | assertEquals(DOMAIN + '/' + RESOURCE, new JID("", DOMAIN, RESOURCE).toString()); 58 | } 59 | 60 | /** 61 | * The maximum size of the node identifier is 1023 bytes (note: bytes, not 62 | * characters!). This test verifies that using as much characters as 63 | * possible without crossing the 1023 byte boundry, will not cause a 64 | * problem. 65 | */ 66 | @Test 67 | public void testMaximumSizeOneByteChar() throws Exception { 68 | // setup 69 | final StringBuilder builder = new StringBuilder(); 70 | for (int i = 0; i < 1023; i++) { 71 | builder.append('a'); 72 | } 73 | final String longestPossibleValue = builder.toString(); 74 | 75 | // do magic / verify 76 | new JID(longestPossibleValue, DOMAIN, RESOURCE); 77 | } 78 | 79 | /** 80 | * The maximum size of the node identifier is 1023 bytes (note: bytes, not 81 | * characters!). This test verifies that using more bytes will cause an 82 | * exception to be thrown. 83 | */ 84 | @Test(expected = IllegalArgumentException.class) 85 | public void testOverMaximumSizeOneByteChar() throws Exception { 86 | // setup 87 | final StringBuilder builder = new StringBuilder(); 88 | for (int i = 0; i < 1024; i++) { 89 | builder.append('a'); 90 | } 91 | builder.append('a'); 92 | final String toBig = builder.toString(); 93 | 94 | // do magic / verify 95 | new JID(toBig, DOMAIN, RESOURCE); 96 | } 97 | 98 | /** 99 | * UTF-8 characters use 1 to 4 bytes. The JID implementation should 100 | * correctly identify the length of all UTF-8 characters. 101 | * 102 | * This issue has been filed as TINDER-32 103 | * 104 | * @see Tinder 106 | * bugtracker: TINDER-32Tinder 133 | * bugtracker: TINDER-32Tinder 35 | * bugtracker: TINDER-29 36 | */ 37 | public class JIDCachedBareAndFullJIDTest { 38 | 39 | /** 40 | * Verifies that Stringprep mapping results are correctly stored in the 41 | * cache. This test uses a 'word joiner' character, which is listed on the 42 | * B1 table of Stringprep. Characters on this table must be mapped in 43 | * resource strings, according to RFC 3920. This specific character should 44 | * be mapped to nothing. The cached value should not contain this character. 45 | */ 46 | @Test 47 | public void testCachedFullJIDisNodePrepped() throws Exception { 48 | 49 | // setup 50 | final String node = "word\u2060joiner"; 51 | final String domain = "domain"; 52 | final String resource = "resource"; 53 | 54 | // do magic 55 | final JID result = new JID(node, domain, resource); 56 | final String fullJID = result.toString(); 57 | 58 | // verify 59 | assertEquals("wordjoiner" + "@" + domain + "/" + resource, fullJID); 60 | } 61 | 62 | /** 63 | * Verifies that Stringprep mapping results are correctly stored in the 64 | * cache. This test uses a 'word joiner' character, which is listed on the 65 | * B1 table of Stringprep. Characters on this table must be mapped in 66 | * resource strings, according to RFC 3920. This specific character should 67 | * be mapped to nothing. The cached value should not contain this character. 68 | */ 69 | @Test 70 | public void testCachedFullJIDisDomainPrepped() throws Exception { 71 | 72 | // setup 73 | final String node = "node"; 74 | final String domain = "word\u2060joiner"; 75 | final String resource = "resource"; 76 | 77 | // do magic 78 | final JID result = new JID(node, domain, resource); 79 | final String fullJID = result.toString(); 80 | 81 | // verify 82 | assertEquals(node + "@" + "wordjoiner" + "/" + resource, fullJID); 83 | } 84 | 85 | /** 86 | * Verifies that Stringprep mapping results are correctly stored in the 87 | * cache. This test uses a 'word joiner' character, which is listed on the 88 | * B1 table of Stringprep. Characters on this table must be mapped in 89 | * resource strings, according to RFC 3920. This specific character should 90 | * be mapped to nothing. The cached value should not contain this character. 91 | */ 92 | @Test 93 | public void testCachedFullJIDisResourcePrepped() throws Exception { 94 | 95 | // setup 96 | final String node = "node"; 97 | final String domain = "domain"; 98 | final String resource = "word\u2060joiner"; 99 | 100 | // do magic 101 | final JID result = new JID(node, domain, resource); 102 | final String fullJID = result.toString(); 103 | 104 | // verify 105 | assertEquals(node + "@" + domain + "/" + "wordjoiner", fullJID); 106 | } 107 | 108 | /** 109 | * Verifies that Stringprep mapping results are correctly stored in the 110 | * cache. This test uses a 'word joiner' character, which is listed on the 111 | * B1 table of Stringprep. Characters on this table must be mapped in 112 | * resource strings, according to RFC 3920. This specific character should 113 | * be mapped to nothing. The cached value should not contain this character. 114 | */ 115 | @Test 116 | public void testCachedBareJIDisNodePrepped() throws Exception { 117 | 118 | // setup 119 | final String node = "word\u2060joiner"; 120 | final String domain = "domain"; 121 | final String resource = "resource"; 122 | 123 | // do magic 124 | final JID result = new JID(node, domain, resource); 125 | final String bareJID = result.toBareJID(); 126 | 127 | // verify 128 | assertEquals("wordjoiner" + "@" + domain, bareJID); 129 | } 130 | 131 | /** 132 | * Verifies that Stringprep mapping results are correctly stored in the 133 | * cache. This test uses a 'word joiner' character, which is listed on the 134 | * B1 table of Stringprep. Characters on this table must be mapped in 135 | * resource strings, according to RFC 3920. This specific character should 136 | * be mapped to nothing. The cached value should not contain this character. 137 | */ 138 | @Test 139 | public void testCachedBareJIDisDomainPrepped() throws Exception { 140 | 141 | // setup 142 | final String node = "node"; 143 | final String domain = "word\u2060joiner"; 144 | final String resource = "resource"; 145 | 146 | // do magic 147 | final JID result = new JID(node, domain, resource); 148 | final String bareJID = result.toBareJID(); 149 | 150 | // verify 151 | assertEquals(node + "@" + "wordjoiner", bareJID); 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/packet/PacketErrorApplicationConditionTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.packet; 18 | 19 | import static org.junit.Assert.*; 20 | 21 | import org.junit.Before; 22 | import org.junit.Test; 23 | import org.xmpp.packet.PacketError.Condition; 24 | import org.xmpp.packet.PacketError.Type; 25 | 26 | /** 27 | * Tests compliance of Application-Specific Conditions provided by 28 | * {@link PacketError} with the restrictions defined in RFC-3920. 29 | * 30 | * @author Günther Nieß, guenther.niess@web.de 31 | * @see RFC 3920 - Extensible 32 | * Messaging and Presence Protocol (XMPP): Core 33 | */ 34 | public class PacketErrorApplicationConditionTest { 35 | 36 | /** 37 | * XML namespace name for stanza-related error data. 38 | */ 39 | public static final String ERROR_NAMESPACE = "urn:ietf:params:xml:ns:xmpp-stanzas"; 40 | 41 | /** 42 | * Fallback namespace for generalized error conditions (see XEP-0182). 43 | */ 44 | public static final String GENERAL_ERROR_NAMESPACE = "urn:xmpp:errors"; 45 | 46 | /** 47 | * A text describing a sample packet-error. 48 | */ 49 | public static final String ERROR_TEXT = "Some special application information..."; 50 | 51 | /** 52 | * A simple error for testing application specific error conditions. 53 | */ 54 | private PacketError stanzaError; 55 | 56 | /** 57 | * A more complex error for testing application specific error conditions. 58 | */ 59 | private PacketError applicationError; 60 | 61 | 62 | /** 63 | * Initialize the used packet-errors. 64 | */ 65 | @Before 66 | public void setUp() { 67 | stanzaError = new PacketError(Condition.not_acceptable); 68 | applicationError = new PacketError( 69 | Condition.undefined_condition, 70 | Type.modify, 71 | ERROR_TEXT, 72 | "en"); 73 | } 74 | 75 | /** 76 | * Testing the default behavior of the setter and getter methods, when an 77 | * application error is set, without a namespace being provided. 78 | */ 79 | @Test 80 | public void testValidBehaviorJustCondition() { 81 | String requestErrorName = "stanza-too-big"; 82 | stanzaError.setApplicationCondition(requestErrorName); 83 | if (!requestErrorName.equals(stanzaError.getApplicationConditionName())) { 84 | fail("Don't get the applied name of the application-specific " 85 | + "error condition."); 86 | } 87 | if (!GENERAL_ERROR_NAMESPACE.equals( 88 | stanzaError.getApplicationConditionNamespaceURI())) { 89 | fail("According to the XEP-0182 the default namespace of general " 90 | + "application-specific error conditions is " 91 | + GENERAL_ERROR_NAMESPACE + ". " 92 | + "This namespace should be applied as fallback."); 93 | } 94 | } 95 | 96 | /** 97 | * Testing the default behavior of the setter and getter methods, when an 98 | * application error including a namespace is set. 99 | */ 100 | @Test 101 | public void testValidBehaviorConditionAndNamespace() { 102 | String appErrorName = "special-application-condition"; 103 | String appNS = "application-ns"; 104 | applicationError.setApplicationCondition(appErrorName, appNS); 105 | if (!appNS.equals(applicationError.getApplicationConditionNamespaceURI())) { 106 | fail("Don't get the expected namespace of the application-specific " 107 | + "error condition."); 108 | } 109 | if (Condition.undefined_condition != applicationError.getCondition()) { 110 | fail("The application-specific error condition don't have to modify " 111 | + "the standard error condition."); 112 | } 113 | if (!ERROR_TEXT.equals(applicationError.getText())) { 114 | fail("The application-specific error condition don't have to modify " 115 | + "the text of the packet-error."); 116 | } 117 | } 118 | 119 | /** 120 | * Verifies the valid behavior of this class, even after a previously set condition is removed. 121 | */ 122 | @Test 123 | public void testValidBehaviorReset() { 124 | // set error 125 | String appErrorName = "special-application-condition"; 126 | String appNS = "application-ns"; 127 | applicationError.setApplicationCondition(appErrorName, appNS); 128 | 129 | // unset error 130 | applicationError.setApplicationCondition(null); 131 | 132 | // verify that unsetting the error propagated correctly. 133 | if (applicationError.getApplicationConditionNamespaceURI() != null) { 134 | fail("Removing the application-specific error condition don't " 135 | + "remove the namespace of the application."); 136 | } 137 | if (Condition.undefined_condition != applicationError.getCondition()) { 138 | fail("Removing the application-specific error condition don't have " 139 | + "to modify the standard error condition."); 140 | } 141 | if (!ERROR_TEXT.equals(applicationError.getText())) { 142 | fail("Removing the application-specific error condition don't have " 143 | + "to modify the text of the packet-error."); 144 | } 145 | } 146 | 147 | /** 148 | * Insert an application-specific error, using the namespace 149 | * urn:ietf:params:xml:ns:xmpp-stanzas isn't allowed by RFC 3920. 150 | */ 151 | @Test(expected = IllegalArgumentException.class) 152 | public void testInvalidParameters() throws Exception { 153 | // verify 154 | applicationError.setApplicationCondition("invalid-ns", ERROR_NAMESPACE); 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/main/java/org/xmpp/component/ComponentManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.component; 18 | 19 | import org.xmpp.packet.IQ; 20 | import org.xmpp.packet.Packet; 21 | 22 | /** 23 | * Manages components. 24 | * 25 | * @see Component 26 | * @author Matt Tucker 27 | */ 28 | public interface ComponentManager { 29 | 30 | /** 31 | * Adds a component. The {@link Component#initialize(org.xmpp.packet.JID, ComponentManager)} 32 | * method will be called on the component. The subdomain specifies the address of 33 | * the component on a server. For example, if the subdomain is "test" and the XMPP 34 | * server is at "example.com", then the component's address would be "test.example.com". 35 | * 36 | * @param subdomain the subdomain of the component's address. 37 | * @param component the component. 38 | * @throws ComponentException if the component connection is lost and the component cannot be added. 39 | */ 40 | void addComponent(String subdomain, Component component) throws ComponentException; 41 | 42 | /** 43 | * Removes a component. The {@link Component#shutdown} method will be called on the 44 | * component. 45 | * 46 | * @param subdomain the subdomain of the component's address. 47 | * @throws ComponentException if the component connection is lost and the component cannot be removed. 48 | */ 49 | void removeComponent(String subdomain) throws ComponentException; 50 | 51 | /** 52 | * Sends a packet to the XMPP server. The "from" value of the packet must not be null. 53 | * An IllegalArgumentException will be thrown when the "from" value is null.

54 | * 55 | * Components are trusted by the server and may use any value in from address. Usually 56 | * the from address uses the component's address as the domain but this is not required. 57 | * 58 | * @param component the component sending the packet. 59 | * @param packet the packet to send. 60 | * @throws ComponentException if the component connection is lost or unavialble during the time of sending and 61 | * recieving packets. 62 | */ 63 | void sendPacket(Component component, Packet packet) throws ComponentException; 64 | 65 | /** 66 | * Sends an IQ packet to the XMPP server and waits to get an IQ of type result or error. 67 | * The "from" value of the packet must not be null. An IllegalArgumentException 68 | * will be thrown when the "from" value is null.

69 | * 70 | * If no answer is received from the server before the specified timeout then null will be returned. 71 | * 72 | * Components are trusted by the server and may use any value in from address. Usually 73 | * the from address uses the component's address as the domain but this is not required. 74 | * 75 | * @param component the component sending the packet. 76 | * @param packet the IQ packet to send. 77 | * @param timeout the number of milliseconds to wait before returning an IQ error. 78 | * @return the answer sent by the server. The answer could be an IQ of type result or 79 | * error. null will be returned if there is no response from the server. 80 | * @throws ComponentException if the component connection is lost or unavialble during the time of sending and 81 | * recieving packets. 82 | */ 83 | IQ query(Component component, IQ packet, long timeout) throws ComponentException; 84 | 85 | /** 86 | * Sends an IQ packet to the server and returns immediately. The specified IQResultListener 87 | * will be invoked when an answer is received. 88 | * 89 | * @param component the component sending the packet. 90 | * @param packet the IQ packet to send. 91 | * @param listener the listener that will be invoked when an answer is received. 92 | * @throws ComponentException if the component connection is lost or unavialble during the time of sending and 93 | * recieving packets. 94 | */ 95 | void query(Component component, IQ packet, IQResultListener listener) throws ComponentException; 96 | 97 | /** 98 | * Returns a property value specified by name. Properties can be used by 99 | * components to store configuration data. It is recommended that each 100 | * component qualify property names to prevent overlap. For example a 101 | * component that broadcasts messages to groups of users, might prepend 102 | * all property names it uses with "broadcast.". 103 | * 104 | * @param name the property name. 105 | * @return the property value. 106 | */ 107 | String getProperty(String name); 108 | 109 | /** 110 | * Sets a property value. Properties can be used by components to 111 | * store configuration data. It is recommended that each component 112 | * qualify property names to prevent overlap. For example a component 113 | * that broadcasts messages to groups of users, might prepend all 114 | * property names it uses with "broadcast.". 115 | * 116 | * @param name the property name. 117 | * @param value the property value. 118 | */ 119 | void setProperty(String name, String value); 120 | 121 | /** 122 | * Returns the domain of the XMPP server. The domain name may be the IP address or the host 123 | * name. 124 | * 125 | * @return the domain of the XMPP server. 126 | */ 127 | String getServerName(); 128 | 129 | /** 130 | * Returns true if components managed by this component manager are external 131 | * components connected to the server over a network connection. Otherwise, 132 | * the components are internal to the server. 133 | * 134 | * @return true if the managed components are external components. 135 | */ 136 | boolean isExternalMode(); 137 | } 138 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/packet/BasicJIDTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2010 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package org.xmpp.packet; 17 | 18 | import static org.junit.Assert.assertEquals; 19 | import static org.junit.Assert.assertNull; 20 | 21 | import org.junit.Test; 22 | 23 | /** 24 | * Various checks that verify basic JID behaviour. 25 | * 26 | * @author Guus der Kinderen 27 | */ 28 | public class BasicJIDTest { 29 | 30 | @Test(expected = IllegalArgumentException.class) 31 | public void testNullArgument() { 32 | new JID(null); 33 | } 34 | 35 | @Test(expected = IllegalArgumentException.class) 36 | public void testEmptyArgument() { 37 | new JID(""); 38 | } 39 | 40 | @Test 41 | public void testC1FullJID() { 42 | // setup 43 | final JID jid = new JID("node@domain/resource"); 44 | 45 | // verify 46 | assertEquals("node", jid.getNode()); 47 | assertEquals("domain", jid.getDomain()); 48 | assertEquals("resource", jid.getResource()); 49 | } 50 | 51 | @Test 52 | public void testC1BareJID() { 53 | // setup 54 | final JID jid = new JID("node@domain"); 55 | 56 | // verify 57 | assertEquals("node", jid.getNode()); 58 | assertEquals("domain", jid.getDomain()); 59 | assertNull(jid.getResource()); 60 | } 61 | 62 | @Test 63 | public void testC1JIDWithoutNode() { 64 | // setup 65 | final JID jid = new JID("domain/resource"); 66 | 67 | // verify 68 | assertNull(jid.getNode()); 69 | assertEquals("domain", jid.getDomain()); 70 | assertEquals("resource", jid.getResource()); 71 | } 72 | 73 | @Test 74 | public void testC1BareJIDWithoutNode() { 75 | // setup 76 | final JID jid = new JID("domain"); 77 | 78 | // verify 79 | assertNull(jid.getNode()); 80 | assertEquals("domain", jid.getDomain()); 81 | assertNull(jid.getResource()); 82 | } 83 | 84 | @Test 85 | public void testC2FullJID() { 86 | // setup 87 | final JID jid = new JID("node", "domain", "resource"); 88 | 89 | // verify 90 | assertEquals("node", jid.getNode()); 91 | assertEquals("domain", jid.getDomain()); 92 | assertEquals("resource", jid.getResource()); 93 | } 94 | 95 | @Test 96 | public void testC2BareJID() { 97 | // setup 98 | final JID jid = new JID("node", "domain", null); 99 | 100 | // verify 101 | assertEquals("node", jid.getNode()); 102 | assertEquals("domain", jid.getDomain()); 103 | assertNull(jid.getResource()); 104 | } 105 | 106 | @Test 107 | public void testC2JIDWithoutNode() { 108 | // setup 109 | final JID jid = new JID(null, "domain", "resource"); 110 | 111 | // verify 112 | assertNull(jid.getNode()); 113 | assertEquals("domain", jid.getDomain()); 114 | assertEquals("resource", jid.getResource()); 115 | } 116 | 117 | @Test 118 | public void testC2BareJIDWithoutNode() { 119 | // setup 120 | final JID jid = new JID(null, "domain", null); 121 | 122 | // verify 123 | assertNull(jid.getNode()); 124 | assertEquals("domain", jid.getDomain()); 125 | assertNull(jid.getResource()); 126 | } 127 | 128 | /** 129 | * Verifies that {@link JID#toBareJID()} returns a correct representation of 130 | * the JID instance when the original JID was a full JID. 131 | */ 132 | @Test 133 | public void testFullJIDToBareJID() throws Exception { 134 | 135 | // setup 136 | final String node = "node"; 137 | final String domain = "domain"; 138 | final String resource = "resource"; 139 | final JID jid = new JID(node, domain, resource); 140 | 141 | // do magic 142 | final String bare = jid.toBareJID(); 143 | 144 | // verify 145 | assertEquals(node + "@" + domain, bare); 146 | } 147 | 148 | /** 149 | * Verifies that {@link JID#toBareJID()} returns a correct representation of 150 | * the JID instance when the original JID was a bare JID. 151 | */ 152 | @Test 153 | public void testBareJIDToBareJID() throws Exception { 154 | 155 | // setup 156 | final String node = "node"; 157 | final String domain = "domain"; 158 | final JID jid = new JID(node, domain, null); 159 | 160 | // do magic 161 | final String bare = jid.toBareJID(); 162 | 163 | // verify 164 | assertEquals(node + "@" + domain, bare); 165 | } 166 | 167 | /** 168 | * Verifies that {@link JID#asBareJID()} returns a correct representation of 169 | * the JID instance when the original JID was a full JID. 170 | * 171 | * @see TINDER-68 172 | */ 173 | @Test 174 | public void testFullJIDAsBareJID() throws Exception { 175 | 176 | // setup 177 | final String node = "node"; 178 | final String domain = "domain"; 179 | final String resource = "resource"; 180 | final JID jid = new JID(node, domain, resource); 181 | 182 | // do magic 183 | final JID bare = jid.asBareJID(); 184 | 185 | // verify 186 | assertEquals(node + "@" + domain, bare.toString()); 187 | } 188 | 189 | /** 190 | * Verifies that {@link JID#asBareJID()} returns a correct representation of 191 | * the JID instance when the original JID was a bare JID. 192 | * 193 | * @see TINDER-68 194 | */ 195 | @Test 196 | public void tesBareJIDAsBareJID() throws Exception { 197 | 198 | // setup 199 | final String node = "node"; 200 | final String domain = "domain"; 201 | final JID jid = new JID(node, domain, null); 202 | 203 | // do magic 204 | final JID bare = jid.asBareJID(); 205 | 206 | // verify 207 | assertEquals(node + "@" + domain, bare.toString()); 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/packet/JIDSerializabilityTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.packet; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | import static org.junit.Assert.assertTrue; 21 | 22 | import java.io.ByteArrayInputStream; 23 | import java.io.ByteArrayOutputStream; 24 | import java.io.InputStream; 25 | import java.io.ObjectInputStream; 26 | import java.io.ObjectOutputStream; 27 | 28 | import org.junit.Test; 29 | 30 | /** 31 | * Various tests that verify the serializability of JID instances. 32 | * 33 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 34 | * @see Based on Testing object serialization 37 | */ 38 | public class JIDSerializabilityTest { 39 | 40 | /** 41 | * The first serialization test you usually write is one that verifies 42 | * serialization is possible. Even if a class implements Serializable, 43 | * there's no guarantee that it can be serialized. For instance, if a 44 | * serializable container such as an ArrayList contains a non-serializable 45 | * object such as a Socket, it throws a NotSerializableException when you 46 | * try to serialize it. 47 | * 48 | * Usually for this test, you just write the data onto a 49 | * ByteArrayOutputStream. If no exception is thrown, the test passes. If you 50 | * like, you can also test that some output has been written 51 | * 52 | * @see Testing 54 | * object serialization 55 | */ 56 | @Test 57 | public void testIsSerializable() throws Exception { 58 | // setup 59 | JID test = new JID("a", "b.com", "c"); 60 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 61 | 62 | // do magic 63 | ObjectOutputStream oos = new ObjectOutputStream(out); 64 | oos.writeObject(test); 65 | oos.close(); 66 | 67 | // verify 68 | assertTrue(out.toByteArray().length > 0); 69 | } 70 | 71 | /** 72 | * You want to write a test that verifies not only that the output is 73 | * present, but that it's correct. Deserialize the object and compare it to 74 | * the original. 75 | * 76 | * @see Testing 78 | * object serialization 79 | */ 80 | @Test 81 | public void testRoundTripSerialization() throws Exception { 82 | 83 | // construct test object 84 | JID original = new JID("a", "b.com", "c"); 85 | 86 | // serialize 87 | ByteArrayOutputStream out = new ByteArrayOutputStream(); 88 | ObjectOutputStream oos = new ObjectOutputStream(out); 89 | oos.writeObject(original); 90 | oos.close(); 91 | 92 | // deserialize 93 | byte[] pickled = out.toByteArray(); 94 | InputStream in = new ByteArrayInputStream(pickled); 95 | ObjectInputStream ois = new ObjectInputStream(in); 96 | Object o = ois.readObject(); 97 | JID copy = (JID) o; 98 | 99 | // test the result 100 | assertEquals(original.getNode(), copy.getNode()); 101 | assertEquals(original.getDomain(), copy.getDomain()); 102 | assertEquals(original.getResource(), copy.getResource()); 103 | } 104 | 105 | /** 106 | * You usually can't rely on the default serialization format to retain 107 | * file-format compatibility between different versions of a class. You have 108 | * to customize it in a variety of ways using serialPersistentFields, 109 | * readObject() and writeObject() methods, and/or the transient modifier. If 110 | * you do make an incompatible change to the serialization format of a 111 | * class, you should also change the serialVersionUID field to indicate that 112 | * you've done so. 113 | *

114 | * Normally you don't care much about the detailed structure of serialized 115 | * objects. You just care that whatever format you start out with is 116 | * maintained as the class evolves. Once the class is in more-or-less 117 | * complete shape, write some serialized instances of the class and store 118 | * them where you can use them as references going forward. (You probably do 119 | * want to think at least a little about how you will serialize to ensure 120 | * sufficient flexibility for evolution going forward.) 121 | *

122 | * All you need to do is write a serialized object into a file, and you only 123 | * do that once. It's the file you want to save, not the code that wrote it. 124 | * Your test deserializes the object in the file and then compare its 125 | * properties to their expected values. 126 | */ 127 | @Test 128 | public void testDeserializeVersionJIDversion1dot1() throws Exception { 129 | // this JID is build from the String values that were also used to build 130 | // the String that's serialized in the file 131 | // "jid-version-tinder1.1.serialized" 132 | final JID original = new JID("abc", "dom4in.com", "@home", true); 133 | 134 | // deserialize 135 | final InputStream in = getClass().getResourceAsStream( 136 | "/jid-version-tinder1.1.serialized"); 137 | final ObjectInputStream ois = new ObjectInputStream(in); 138 | final Object o = ois.readObject(); 139 | final JID deserialized = (JID) o; 140 | 141 | // test the result 142 | assertEquals(original.getDomain(), deserialized.getDomain()); 143 | assertEquals(original.getResource(), deserialized.getResource()); 144 | assertEquals(original.getNode(), deserialized.getNode()); 145 | } 146 | 147 | // This code is used to generate serialized JID instances. After every 148 | // change of the JID class, a new serialized object should be created. This 149 | // object should be added (not replace!) the existing objects in the 150 | // /test/resources/ directory, and a new unit test should be written that 151 | // verifies that the object can be correctly deserialized. This way, 152 | // backwards compatibility of the deserialization implementation is checked. 153 | // public static void main(String[] args) throws Exception { 154 | // final File file = new File( 155 | // "src/test/resources/jid-version-tinder1.CHANGEME.serialized"); 156 | // final OutputStream fout = new FileOutputStream(file); 157 | // 158 | // final ObjectOutputStream out = new ObjectOutputStream(fout); 159 | // 160 | // final JID jid = new JID("abc", "dom4in.com", "@home"); 161 | // out.writeObject(jid); 162 | // out.flush(); 163 | // out.close(); 164 | // } 165 | } 166 | -------------------------------------------------------------------------------- /src/test/java/org/xmpp/forms/FormFieldGetSetTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright (C) 2004-2009 Jive Software. All rights reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package org.xmpp.forms; 18 | 19 | import static org.junit.Assert.assertEquals; 20 | import static org.junit.Assert.assertTrue; 21 | import static org.junit.Assert.fail; 22 | 23 | import java.util.List; 24 | 25 | import org.dom4j.DocumentFactory; 26 | import org.dom4j.Element; 27 | import org.junit.Before; 28 | import org.junit.Test; 29 | import org.xmpp.forms.FormField.Option; 30 | import org.xmpp.forms.FormField.Type; 31 | 32 | /** 33 | * This test verifies the functionality of the setters and getters of fields in 34 | * the {@link FormField} implementation. Every test in this class works 35 | * according to the same principle: use the setter to set a particular value, 36 | * then use the getter to verify that this value is returned. 37 | * 38 | * This test should identify problems such as TINDER-12 39 | * 40 | * @author Guus der Kinderen, guus.der.kinderen@gmail.com 41 | * @see http://www.igniterealtime.org/issues/browse/TINDER-12 42 | */ 43 | public class FormFieldGetSetTest { 44 | 45 | private static final DocumentFactory DF = DocumentFactory.getInstance(); 46 | 47 | /** 48 | * Every test will be using a new, empty {@link FormField} instance, which 49 | * is set and reset in this field. 50 | */ 51 | private FormField field = null; 52 | 53 | @Before 54 | public void setUp() { 55 | // reset the element before every test. 56 | final Element emptyElement = DF.createDocument().addElement("field"); 57 | field = new FormField(emptyElement); 58 | } 59 | 60 | /** 61 | * Test method for 62 | * {@link org.xmpp.forms.FormField#addValue(java.lang.Object)} and 63 | * {@link org.xmpp.forms.FormField#getValues()}. 64 | */ 65 | @Test 66 | public void testValues_OneValue() { 67 | // setup 68 | final String value = "a value"; 69 | 70 | // do magic 71 | field.addValue(value); 72 | final List result = field.getValues(); 73 | 74 | // verify 75 | assertEquals(1, result.size()); 76 | assertTrue(result.contains(value)); 77 | } 78 | 79 | /** 80 | * Test method for 81 | * {@link org.xmpp.forms.FormField#addValue(java.lang.Object)} and 82 | * {@link org.xmpp.forms.FormField#getValues()}. 83 | */ 84 | @Test 85 | public void testValues_TwoValues() { 86 | // setup 87 | final String valueA = "a value"; 88 | final String valueB = "another value"; 89 | 90 | // do magic 91 | field.addValue(valueA); 92 | field.addValue(valueB); 93 | final List result = field.getValues(); 94 | 95 | // verify 96 | assertEquals(2, result.size()); 97 | assertTrue(result.contains(valueA)); 98 | assertTrue(result.contains(valueB)); 99 | } 100 | 101 | /** 102 | * Test method for 103 | * {@link org.xmpp.forms.FormField#addOption(String, String)} and 104 | * {@link org.xmpp.forms.FormField#getOptions()}. 105 | */ 106 | @Test 107 | public void testOptions_OneOption() { 108 | // setup 109 | final String label = "the label"; 110 | final String value = "a value"; 111 | 112 | // do magic 113 | field.addOption(label, value); 114 | final List

 11 | ---------------------------------------------------------------------
 12 | Apache License
 13 |                       Version 2.0, January 2004
 14 |                    http://www.apache.org/licenses/
 15 | 
 16 |   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
 17 | 
 18 |   1. Definitions.
 19 | 
 20 |  "License" shall mean the terms and conditions for use, reproduction,
 21 |  and distribution as defined by Sections 1 through 9 of this document.
 22 | 
 23 |  "Licensor" shall mean the copyright owner or entity authorized by
 24 |  the copyright owner that is granting the License.
 25 | 
 26 |  "Legal Entity" shall mean the union of the acting entity and all
 27 |  other entities that control, are controlled by, or are under common
 28 |  control with that entity. For the purposes of this definition,
 29 |  "control" means (i) the power, direct or indirect, to cause the
 30 |  direction or management of such entity, whether by contract or
 31 |  otherwise, or (ii) ownership of fifty percent (50%) or more of the
 32 |  outstanding shares, or (iii) beneficial ownership of such entity.
 33 | 
 34 |  "You" (or "Your") shall mean an individual or Legal Entity
 35 |  exercising permissions granted by this License.
 36 | 
 37 |  "Source" form shall mean the preferred form for making modifications,
 38 |  including but not limited to software source code, documentation
 39 |  source, and configuration files.
 40 | 
 41 |  "Object" form shall mean any form resulting from mechanical
 42 |  transformation or translation of a Source form, including but
 43 |  not limited to compiled object code, generated documentation,
 44 |  and conversions to other media types.
 45 | 
 46 |  "Work" shall mean the work of authorship, whether in Source or
 47 |  Object form, made available under the License, as indicated by a
 48 |  copyright notice that is included in or attached to the work
 49 |  (an example is provided in the Appendix below).
 50 | 
 51 |  "Derivative Works" shall mean any work, whether in Source or Object
 52 |  form, that is based on (or derived from) the Work and for which the
 53 |  editorial revisions, annotations, elaborations, or other modifications
 54 |  represent, as a whole, an original work of authorship. For the purposes
 55 |  of this License, Derivative Works shall not include works that remain
 56 |  separable from, or merely link (or bind by name) to the interfaces of,
 57 |  the Work and Derivative Works thereof.
 58 | 
 59 |  "Contribution" shall mean any work of authorship, including
 60 |  the original version of the Work and any modifications or additions
 61 |  to that Work or Derivative Works thereof, that is intentionally
 62 |  submitted to Licensor for inclusion in the Work by the copyright owner
 63 |  or by an individual or Legal Entity authorized to submit on behalf of
 64 |  the copyright owner. For the purposes of this definition, "submitted"
 65 |  means any form of electronic, verbal, or written communication sent
 66 |  to the Licensor or its representatives, including but not limited to
 67 |  communication on electronic mailing lists, source code control systems,
 68 |  and issue tracking systems that are managed by, or on behalf of, the
 69 |  Licensor for the purpose of discussing and improving the Work, but
 70 |  excluding communication that is conspicuously marked or otherwise
 71 |  designated in writing by the copyright owner as "Not a Contribution."
 72 | 
 73 |  "Contributor" shall mean Licensor and any individual or Legal Entity
 74 |  on behalf of whom a Contribution has been received by Licensor and
 75 |  subsequently incorporated within the Work.
 76 | 
 77 |   2. Grant of Copyright License. Subject to the terms and conditions of
 78 |  this License, each Contributor hereby grants to You a perpetual,
 79 |  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 80 |  copyright license to reproduce, prepare Derivative Works of,
 81 |  publicly display, publicly perform, sublicense, and distribute the
 82 |  Work and such Derivative Works in Source or Object form.
 83 | 
 84 |   3. Grant of Patent License. Subject to the terms and conditions of
 85 |  this License, each Contributor hereby grants to You a perpetual,
 86 |  worldwide, non-exclusive, no-charge, royalty-free, irrevocable
 87 |  (except as stated in this section) patent license to make, have made,
 88 |  use, offer to sell, sell, import, and otherwise transfer the Work,
 89 |  where such license applies only to those patent claims licensable
 90 |  by such Contributor that are necessarily infringed by their
 91 |  Contribution(s) alone or by combination of their Contribution(s)
 92 |  with the Work to which such Contribution(s) was submitted. If You
 93 |  institute patent litigation against any entity (including a
 94 |  cross-claim or counterclaim in a lawsuit) alleging that the Work
 95 |  or a Contribution incorporated within the Work constitutes direct
 96 |  or contributory patent infringement, then any patent licenses
 97 |  granted to You under this License for that Work shall terminate
 98 |  as of the date such litigation is filed.
 99 | 
100 |   4. Redistribution. You may reproduce and distribute copies of the
101 |  Work or Derivative Works thereof in any medium, with or without
102 |  modifications, and in Source or Object form, provided that You
103 |  meet the following conditions:
104 | 
105 |  (a) You must give any other recipients of the Work or
106 |      Derivative Works a copy of this License; and
107 | 
108 |  (b) You must cause any modified files to carry prominent notices
109 |      stating that You changed the files; and
110 | 
111 |  (c) You must retain, in the Source form of any Derivative Works
112 |      that You distribute, all copyright, patent, trademark, and
113 |      attribution notices from the Source form of the Work,
114 |      excluding those notices that do not pertain to any part of
115 |      the Derivative Works; and
116 | 
117 |  (d) If the Work includes a "NOTICE" text file as part of its
118 |      distribution, then any Derivative Works that You distribute must
119 |      include a readable copy of the attribution notices contained
120 |      within such NOTICE file, excluding those notices that do not
121 |      pertain to any part of the Derivative Works, in at least one
122 |      of the following places: within a NOTICE text file distributed
123 |      as part of the Derivative Works; within the Source form or
124 |      documentation, if provided along with the Derivative Works; or,
125 |      within a display generated by the Derivative Works, if and
126 |      wherever such third-party notices normally appear. The contents
127 |      of the NOTICE file are for informational purposes only and
128 |      do not modify the License. You may add Your own attribution
129 |      notices within Derivative Works that You distribute, alongside
130 |      or as an addendum to the NOTICE text from the Work, provided
131 |      that such additional attribution notices cannot be construed
132 |      as modifying the License.
133 | 
134 |  You may add Your own copyright statement to Your modifications and
135 |  may provide additional or different license terms and conditions
136 |  for use, reproduction, or distribution of Your modifications, or
137 |  for any such Derivative Works as a whole, provided Your use,
138 |  reproduction, and distribution of the Work otherwise complies with
139 |  the conditions stated in this License.
140 | 
141 |   5. Submission of Contributions. Unless You explicitly state otherwise,
142 |  any Contribution intentionally submitted for inclusion in the Work
143 |  by You to the Licensor shall be under the terms and conditions of
144 |  this License, without any additional terms or conditions.
145 |  Notwithstanding the above, nothing herein shall supersede or modify
146 |  the terms of any separate license agreement you may have executed
147 |  with Licensor regarding such Contributions.
148 | 
149 |   6. Trademarks. This License does not grant permission to use the trade
150 |  names, trademarks, service marks, or product names of the Licensor,
151 |  except as required for reasonable and customary use in describing the
152 |  origin of the Work and reproducing the content of the NOTICE file.
153 | 
154 |   7. Disclaimer of Warranty. Unless required by applicable law or
155 |  agreed to in writing, Licensor provides the Work (and each
156 |  Contributor provides its Contributions) on an "AS IS" BASIS,
157 |  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
158 |  implied, including, without limitation, any warranties or conditions
159 |  of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
160 |  PARTICULAR PURPOSE. You are solely responsible for determining the
161 |  appropriateness of using or redistributing the Work and assume any
162 |  risks associated with Your exercise of permissions under this License.
163 | 
164 |   8. Limitation of Liability. In no event and under no legal theory,
165 |  whether in tort (including negligence), contract, or otherwise,
166 |  unless required by applicable law (such as deliberate and grossly
167 |  negligent acts) or agreed to in writing, shall any Contributor be
168 |  liable to You for damages, including any direct, indirect, special,
169 |  incidental, or consequential damages of any character arising as a
170 |  result of this License or out of the use or inability to use the
171 |  Work (including but not limited to damages for loss of goodwill,
172 |  work stoppage, computer failure or malfunction, or any and all
173 |  other commercial damages or losses), even if such Contributor
174 |  has been advised of the possibility of such damages.
175 | 
176 |   9. Accepting Warranty or Additional Liability. While redistributing
177 |  the Work or Derivative Works thereof, You may choose to offer,
178 |  and charge a fee for, acceptance of support, warranty, indemnity,
179 |  or other liability obligations and/or rights consistent with this
180 |  License. However, in accepting such obligations, You may act only
181 |  on Your own behalf and on Your sole responsibility, not on behalf
182 |  of any other Contributor, and only if You agree to indemnify,
183 |  defend, and hold each Contributor harmless for any liability
184 |  incurred by, or claims asserted against, such Contributor by reason
185 |  of your accepting any such warranty or additional liability.
186 | 
187 |   END OF TERMS AND CONDITIONS
188 | 
189 |   APPENDIX: How to apply the Apache License to your work.
190 | 
191 |  To apply the Apache License to your work, attach the following
192 |  boilerplate notice, with the fields enclosed by brackets "[]"
193 |  replaced with your own identifying information. (Don't include
194 |  the brackets!)  The text should be enclosed in the appropriate
195 |  comment syntax for the file format. We also recommend that a
196 |  file or class name and description of purpose be included on the
197 |  same "printed page" as the copyright notice for easier
198 |  identification within third-party archives.
199 | 
200 |   Copyright [yyyy] [name of copyright owner]
201 | 
202 |   Licensed under the Apache License, Version 2.0 (the "License");
203 |   you may not use this file except in compliance with the License.
204 |   You may obtain a copy of the License at
205 | 
206 |   http://www.apache.org/licenses/LICENSE-2.0
207 | 
208 |   Unless required by applicable law or agreed to in writing, software
209 |   distributed under the License is distributed on an "AS IS" BASIS,
210 |   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
211 |   See the License for the specific language governing permissions and
212 |   limitations under the License.
213 | 
214 | 215 | 216 | 217 | --------------------------------------------------------------------------------