/** * * Copyright 2010 Jive Software. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jivesoftware.smack; import java.io.IOException; import java.util.Date; import java.util.Random; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import org.jivesoftware.smack.packet.ExtensionElement; import org.jivesoftware.smack.packet.Nonza; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.packet.TopLevelStreamElement; import org.jxmpp.jid.EntityFullJid; import org.jxmpp.jid.JidTestUtil; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.parts.Resourcepart; import org.jxmpp.stringprep.XmppStringprepException; /** * A dummy implementation of {@link XMPPConnection}, intended to be used during * unit tests. * * Instances store any packets that are delivered to be send using the * {@link #sendStanza(Stanza)} method in a blocking queue. The content of this queue * can be inspected using {@link #getSentPacket()}. Typically these queues are * used to retrieve a message that was generated by the client. * * Packets that should be processed by the client to simulate a received stanza * can be delivered using the {@linkplain #processStanza(Stanza)} method. * It invokes the registered stanza(/packet) interceptors and listeners. * * @see XMPPConnection * @author Guenther Niess */ public class DummyConnection extends AbstractXMPPConnection { private boolean reconnect = false; private final BlockingQueue queue = new LinkedBlockingQueue(); public static ConnectionConfiguration.Builder getDummyConfigurationBuilder() { return DummyConnectionConfiguration.builder().setXmppDomain(JidTestUtil.EXAMPLE_ORG).setUsernameAndPassword("dummy", "dummypass"); } public DummyConnection() { this(getDummyConfigurationBuilder().build()); } private EntityFullJid getUserJid() { try { return JidCreate.entityFullFrom(config.getUsername() + "@" + config.getXMPPServiceDomain() + "/" + (config.getResource() != null ? config.getResource() : "Test")); } catch (XmppStringprepException e) { throw new IllegalStateException(e); } } public DummyConnection(ConnectionConfiguration configuration) { super(configuration); for (ConnectionCreationListener listener : XMPPConnectionRegistry.getConnectionCreationListeners()) { listener.connectionCreated(this); } user = getUserJid(); } @Override protected void connectInternal() { connected = true; saslFeatureReceived.reportSuccess(); tlsHandled.reportSuccess(); streamId = "dummy-" + new Random(new Date().getTime()).nextInt(); if (reconnect) { notifyReconnection(); } } @Override protected void shutdown() { user = null; authenticated = false; callConnectionClosedListener(); reconnect = true; } @Override public boolean isSecureConnection() { return false; } @Override public boolean isUsingCompression() { return false; } @Override protected void loginInternal(String username, String password, Resourcepart resource) throws XMPPException { user = getUserJid(); authenticated = true; } @Override public void sendNonza(Nonza element) { queue.add(element); } @Override protected void sendStanzaInternal(Stanza packet) { queue.add(packet); } /** * Returns the number of packets that's sent through {@link #sendStanza(Stanza)} and * that has not been returned by {@link #getSentPacket()}. * * @return the number of packets which are in the queue. */ public int getNumberOfSentPackets() { return queue.size(); } /** * Returns the first stanza(/packet) that's sent through {@link #sendStanza(Stanza)} * and that has not been returned by earlier calls to this method. * * @return a sent packet. */ public

P getSentPacket() { return getSentPacket(5 * 60); } /** * Returns the first stanza(/packet) that's sent through {@link #sendStanza(Stanza)} * and that has not been returned by earlier calls to this method. This * method will block for up to the specified number of seconds if no packets * have been sent yet. * * @return a sent packet. */ @SuppressWarnings("unchecked") public

P getSentPacket(int wait) { try { return (P) queue.poll(wait, TimeUnit.SECONDS); } catch (InterruptedException e) { throw new IllegalStateException(e); } } /** * Processes a stanza(/packet) through the installed stanza(/packet) collectors and listeners * and letting them examine the stanza(/packet) to see if they are a match with the * filter. * * @param packet the stanza(/packet) to process. */ @Override public void processStanza(Stanza packet) { invokeStanzaCollectorsAndNotifyRecvListeners(packet); } /** * Enable stream feature. * * @param streamFeature the stream feature. * @since 4.2 */ public void enableStreamFeature(ExtensionElement streamFeature) { addStreamFeature(streamFeature); } public static DummyConnection newConnectedDummyConnection() { DummyConnection dummyConnection = new DummyConnection(); try { dummyConnection.connect(); dummyConnection.login(); } catch (InterruptedException | SmackException | IOException | XMPPException e) { throw new IllegalStateException(e); } return dummyConnection; } public static class DummyConnectionConfiguration extends ConnectionConfiguration { protected DummyConnectionConfiguration(Builder builder) { super(builder); } public static Builder builder() { return new Builder(); } public static final class Builder extends ConnectionConfiguration.Builder { private Builder() { } @Override public DummyConnectionConfiguration build() { return new DummyConnectionConfiguration(this); } @Override protected Builder getThis() { return this; } } } }