diff --git a/documentation/developer/integrationtest.md b/documentation/developer/integrationtest.md index 89d0941b4..fc6684a3e 100644 --- a/documentation/developer/integrationtest.md +++ b/documentation/developer/integrationtest.md @@ -53,7 +53,7 @@ service=example.org ```bash service=example.org serviceTlsPin=CERTSHA256:2F:92:C9:4D:30:58:E1:05:21:9A:57:59:5F:6E:25:9A:0F:BF:FF:64:1A:C3:4B:EC:06:7D:4A:6F:0A:D5:21:85 -debug=true +debugger=console ``` ### Framework properties @@ -72,7 +72,7 @@ debug=true | accountTwoPassword | Password of the second XMPP account | | accountThreeUsername | Username of the third XMPP account | | accountThreePassword | Password of the third XMPP account | -| debug | 'true' to enable debug output | +| debugger | 'console' for console debugger, 'enhanced' for the enhanced debugger | | enabledTests | List of enabled tests | | disabledTests | List of disabled tests | | testPackages | List of packages with tests | diff --git a/smack-android/src/main/java/org/jivesoftware/smackx/debugger/android/AndroidDebugger.java b/smack-android/src/main/java/org/jivesoftware/smackx/debugger/android/AndroidDebugger.java index a00a9e0c2..45b45c5f8 100644 --- a/smack-android/src/main/java/org/jivesoftware/smackx/debugger/android/AndroidDebugger.java +++ b/smack-android/src/main/java/org/jivesoftware/smackx/debugger/android/AndroidDebugger.java @@ -16,9 +16,6 @@ */ package org.jivesoftware.smackx.debugger.android; -import java.io.Reader; -import java.io.Writer; - import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.debugger.AbstractDebugger; @@ -37,8 +34,8 @@ import android.util.Log; */ public class AndroidDebugger extends AbstractDebugger { - public AndroidDebugger(XMPPConnection connection, Writer writer, Reader reader) { - super(connection, writer, reader); + public AndroidDebugger(XMPPConnection connection) { + super(connection); } @Override diff --git a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java index 84637ec9c..0c72bd66b 100644 --- a/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java +++ b/smack-bosh/src/main/java/org/jivesoftware/smack/bosh/XMPPBOSHConnection.java @@ -161,16 +161,8 @@ public class XMPPBOSHConnection extends AbstractXMPPConnection { client.addBOSHClientResponseListener(new BOSHPacketReader()); // Initialize the debugger - if (config.isDebuggerEnabled()) { + if (debugger != null) { initDebugger(); - if (isFirstInitialization) { - if (debugger.getReaderListener() != null) { - addAsyncStanzaListener(debugger.getReaderListener(), null); - } - if (debugger.getWriterListener() != null) { - addPacketSendingListener(debugger.getWriterListener(), null); - } - } } // Send the session creation request diff --git a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java index cc5ffc813..a4f5ae88a 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/AbstractXMPPConnection.java @@ -54,6 +54,7 @@ import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.compress.packet.Compress; import org.jivesoftware.smack.compression.XMPPInputOutputStream; import org.jivesoftware.smack.debugger.SmackDebugger; +import org.jivesoftware.smack.debugger.SmackDebuggerFactory; import org.jivesoftware.smack.filter.IQReplyFilter; import org.jivesoftware.smack.filter.StanzaFilter; import org.jivesoftware.smack.filter.StanzaIdFilter; @@ -178,7 +179,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { /** * The SmackDebugger allows to log and debug XML traffic. */ - protected SmackDebugger debugger = null; + protected final SmackDebugger debugger; /** * The Reader which is used for the debugger. @@ -301,6 +302,12 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { protected AbstractXMPPConnection(ConnectionConfiguration configuration) { saslAuthentication = new SASLAuthentication(this, configuration); config = configuration; + SmackDebuggerFactory debuggerFactory = configuration.getDebuggerFactory(); + if (debuggerFactory != null) { + debugger = debuggerFactory.create(this); + } else { + debugger = null; + } // Notify listeners that a new connection has been established for (ConnectionCreationListener listener : XMPPConnectionRegistry.getConnectionCreationListeners()) { listener.connectionCreated(this); @@ -568,7 +575,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { // name we are now logged-in as. // If DEBUG was set to true AFTER the connection was created the debugger // will be null - if (config.isDebuggerEnabled() && debugger != null) { + if (debugger != null) { debugger.userHasLogged(user); } callConnectionAuthenticatedListener(resumed); @@ -872,6 +879,11 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { */ @SuppressWarnings("javadoc") protected void firePacketSendingListeners(final Stanza packet) { + final SmackDebugger debugger = this.debugger; + if (debugger != null) { + debugger.onOutgoingStreamElement(packet); + } + final List listenersToNotify = new LinkedList(); synchronized (sendListeners) { for (ListenerWrapper listenerWrapper : sendListeners.values()) { @@ -957,18 +969,10 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { throw new NullPointerException("Reader or writer isn't initialized."); } // If debugging is enabled, we open a window and write out all network traffic. - if (config.isDebuggerEnabled()) { - if (debugger == null) { - debugger = SmackConfiguration.createDebugger(this, writer, reader); - } - - if (debugger == null) { - LOGGER.severe("Debugging enabled but could not find debugger class"); - } else { - // Obtain new reader and writer from the existing debugger - reader = debugger.newConnectionReader(reader); - writer = debugger.newConnectionWriter(writer); - } + if (debugger != null) { + // Obtain new reader and writer from the existing debugger + reader = debugger.newConnectionReader(reader); + writer = debugger.newConnectionWriter(writer); } } @@ -1072,6 +1076,12 @@ public abstract class AbstractXMPPConnection implements XMPPConnection { */ protected void processStanza(final Stanza stanza) throws InterruptedException { assert (stanza != null); + + final SmackDebugger debugger = this.debugger; + if (debugger != null) { + debugger.onIncomingStreamElement(stanza); + } + lastStanzaReceived = System.currentTimeMillis(); // Deliver the incoming packet to listeners. executorService.executeBlocking(new Runnable() { diff --git a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java index 4585595e4..372a5316e 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/ConnectionConfiguration.java @@ -1,6 +1,6 @@ /** * - * Copyright 2003-2007 Jive Software. + * Copyright 2003-2007 Jive Software, 2017 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -30,6 +30,7 @@ import javax.net.ssl.SSLContext; import javax.net.ssl.X509TrustManager; import javax.security.auth.callback.CallbackHandler; +import org.jivesoftware.smack.debugger.SmackDebuggerFactory; import org.jivesoftware.smack.packet.Session; import org.jivesoftware.smack.proxy.ProxyInfo; import org.jivesoftware.smack.sasl.SASLMechanism; @@ -78,7 +79,7 @@ public abstract class ConnectionConfiguration { */ private final CallbackHandler callbackHandler; - private final boolean debuggerEnabled; + private final SmackDebuggerFactory debuggerFactory; // Holds the socket factory that is used to generate the socket in the connection private final SocketFactory socketFactory; @@ -158,7 +159,7 @@ public abstract class ConnectionConfiguration { hostnameVerifier = builder.hostnameVerifier; sendPresence = builder.sendPresence; legacySessionDisabled = builder.legacySessionDisabled; - debuggerEnabled = builder.debuggerEnabled; + debuggerFactory = builder.debuggerFactory; allowNullOrEmptyUsername = builder.allowEmptyOrNullUsername; enabledSaslMechanisms = builder.enabledSaslMechanisms; @@ -281,13 +282,12 @@ public abstract class ConnectionConfiguration { } /** - * Returns true if the new connection about to be establish is going to be debugged. By - * default the value of {@link SmackConfiguration#DEBUG} is used. + * Returns the Smack debugger factory. * - * @return true if the new connection about to be establish is going to be debugged. + * @return the Smack debugger factory or null */ - public boolean isDebuggerEnabled() { - return debuggerEnabled; + public SmackDebuggerFactory getDebuggerFactory() { + return debuggerFactory; } /** @@ -519,7 +519,7 @@ public abstract class ConnectionConfiguration { private boolean legacySessionDisabled = false; private ProxyInfo proxy; private CallbackHandler callbackHandler; - private boolean debuggerEnabled = SmackConfiguration.DEBUG; + private SmackDebuggerFactory debuggerFactory; private SocketFactory socketFactory; private DomainBareJid xmppServiceDomain; private InetAddress hostAddress; @@ -531,6 +531,9 @@ public abstract class ConnectionConfiguration { private X509TrustManager customX509TrustManager; protected Builder() { + if (SmackConfiguration.DEBUG) { + enableDefaultDebugger(); + } } /** @@ -808,15 +811,20 @@ public abstract class ConnectionConfiguration { return getThis(); } + public B enableDefaultDebugger() { + this.debuggerFactory = SmackConfiguration.getDefaultSmackDebuggerFactory(); + assert this.debuggerFactory != null; + return getThis(); + } + /** - * Sets if the new connection about to be establish is going to be debugged. By - * default the value of {@link SmackConfiguration#DEBUG} is used. - * - * @param debuggerEnabled if the new connection about to be establish is going to be debugged. + * Set the Smack debugger factory used to construct Smack debuggers. + * + * @param debuggerFactory the Smack debugger factory. * @return a reference to this builder. */ - public B setDebuggerEnabled(boolean debuggerEnabled) { - this.debuggerEnabled = debuggerEnabled; + public B setDebuggerFactory(SmackDebuggerFactory debuggerFactory) { + this.debuggerFactory = debuggerFactory; return getThis(); } @@ -965,4 +973,5 @@ public abstract class ConnectionConfiguration { protected abstract B getThis(); } + } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java index 245e8f0e9..7bf89847f 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java @@ -17,8 +17,6 @@ package org.jivesoftware.smack; -import java.io.Reader; -import java.io.Writer; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -30,7 +28,6 @@ import javax.net.ssl.HostnameVerifier; import org.jivesoftware.smack.compression.XMPPInputOutputStream; import org.jivesoftware.smack.debugger.ReflectionDebuggerFactory; -import org.jivesoftware.smack.debugger.SmackDebugger; import org.jivesoftware.smack.debugger.SmackDebuggerFactory; import org.jivesoftware.smack.parsing.ExceptionThrowingCallback; import org.jivesoftware.smack.parsing.ParsingExceptionCallback; @@ -63,8 +60,6 @@ public final class SmackConfiguration { static boolean smackInitialized = false; - private static SmackDebuggerFactory debuggerFactory = new ReflectionDebuggerFactory(); - /** * Value that indicates whether debugging is enabled. When enabled, a debug * window will apear for each new connection that will contain the following @@ -80,6 +75,8 @@ public final class SmackConfiguration { */ public static boolean DEBUG = false; + private static SmackDebuggerFactory DEFAULT_DEBUGGER_FACTORY = ReflectionDebuggerFactory.INSTANCE; + /** * The default parsing exception callback is {@link ExceptionThrowingCallback} which will * throw an exception and therefore disconnect the active connection. @@ -148,6 +145,14 @@ public final class SmackConfiguration { defaultPacketReplyTimeout = timeout; } + public static void setDefaultSmackDebuggerFactory(SmackDebuggerFactory debuggerFactory) { + DEFAULT_DEBUGGER_FACTORY = Objects.requireNonNull(debuggerFactory, "Debugger factory must not be null"); + } + + public static SmackDebuggerFactory getDefaultSmackDebuggerFactory() { + return DEFAULT_DEBUGGER_FACTORY; + } + /** * Gets the default max size of a stanza(/packet) collector before it will delete * the older packets. @@ -190,43 +195,6 @@ public final class SmackConfiguration { } } - /** - * Sets Smack debugger factory. - * - * @param debuggerFactory new debugger factory implementation to be used by Smack - */ - public static void setDebuggerFactory(SmackDebuggerFactory debuggerFactory) { - SmackConfiguration.debuggerFactory = debuggerFactory; - } - - /** - * Get the debugger factory. - * - * @return a debugger factory or null - */ - public static SmackDebuggerFactory getDebuggerFactory() { - return debuggerFactory; - } - - /** - * Creates new debugger instance with given arguments as parameters. May - * return null if no DebuggerFactory is set or if the factory - * did not produce a debugger. - * - * @param connection - * @param writer - * @param reader - * @return a new debugger or null - */ - public static SmackDebugger createDebugger(XMPPConnection connection, Writer writer, Reader reader) { - SmackDebuggerFactory factory = getDebuggerFactory(); - if (factory == null) { - return null; - } else { - return factory.create(connection, writer, reader); - } - } - /** * Remove a SASL mechanism from the list to be used. * diff --git a/smack-core/src/main/java/org/jivesoftware/smack/debugger/AbstractDebugger.java b/smack-core/src/main/java/org/jivesoftware/smack/debugger/AbstractDebugger.java index 0bf5213bd..62ebeb959 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/debugger/AbstractDebugger.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/debugger/AbstractDebugger.java @@ -20,9 +20,8 @@ import java.io.Reader; import java.io.Writer; import org.jivesoftware.smack.ConnectionListener; -import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smack.packet.TopLevelStreamElement; import org.jivesoftware.smack.util.ObservableReader; import org.jivesoftware.smack.util.ObservableWriter; import org.jivesoftware.smack.util.ReaderListener; @@ -30,13 +29,10 @@ import org.jivesoftware.smack.util.WriterListener; import org.jxmpp.jid.EntityFullJid; -public abstract class AbstractDebugger implements SmackDebugger { +public abstract class AbstractDebugger extends SmackDebugger { public static boolean printInterpreted = false; - private final XMPPConnection connection; - - private final StanzaListener listener; private final ConnectionListener connListener; private final ReaderListener readerListener; private final WriterListener writerListener; @@ -44,8 +40,8 @@ public abstract class AbstractDebugger implements SmackDebugger { private ObservableWriter writer; private ObservableReader reader; - public AbstractDebugger(final XMPPConnection connection, Writer writer, Reader reader) { - this.connection = connection; + public AbstractDebugger(final XMPPConnection connection) { + super(connection); // Create a special Reader that wraps the main Reader and logs data to the GUI. this.reader = new ObservableReader(reader); @@ -67,18 +63,6 @@ public abstract class AbstractDebugger implements SmackDebugger { }; this.writer.addWriterListener(writerListener); - // Create a thread that will listen for all incoming packets and write them to - // the GUI. This is what we call "interpreted" packet data, since it's the packet - // data as Smack sees it and not as it's coming in as raw XML. - listener = new StanzaListener() { - @Override - public void processStanza(Stanza packet) { - if (printInterpreted) { - log("RCV PKT (" + connection.getConnectionCounter() + "): " + packet.toXML()); - } - } - }; - connListener = new ConnectionListener() { @Override public void connected(XMPPConnection connection) { @@ -173,22 +157,15 @@ public abstract class AbstractDebugger implements SmackDebugger { } @Override - public Reader getReader() { - return reader; + public void onIncomingStreamElement(TopLevelStreamElement streamElement) { + if (printInterpreted) { + log("RCV PKT (" + connection.getConnectionCounter() + "): " + streamElement.toXML()); + } } @Override - public Writer getWriter() { - return writer; + public void onOutgoingStreamElement(TopLevelStreamElement streamElement) { + // Does nothing (yet). } - @Override - public StanzaListener getReaderListener() { - return listener; - } - - @Override - public StanzaListener getWriterListener() { - return null; - } } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/debugger/ConsoleDebugger.java b/smack-core/src/main/java/org/jivesoftware/smack/debugger/ConsoleDebugger.java index 306c0603e..2f8a08d89 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/debugger/ConsoleDebugger.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/debugger/ConsoleDebugger.java @@ -17,9 +17,7 @@ package org.jivesoftware.smack.debugger; import java.io.PrintWriter; -import java.io.Reader; import java.io.StringWriter; -import java.io.Writer; import java.text.SimpleDateFormat; import java.util.Date; @@ -39,8 +37,8 @@ import org.jivesoftware.smack.XMPPConnection; public class ConsoleDebugger extends AbstractDebugger { private final SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss"); - public ConsoleDebugger(XMPPConnection connection, Writer writer, Reader reader) { - super(connection, writer, reader); + public ConsoleDebugger(XMPPConnection connection) { + super(connection); } @Override @@ -64,4 +62,17 @@ public class ConsoleDebugger extends AbstractDebugger { log(logMessage + sw); } + public static final class Factory implements SmackDebuggerFactory { + + public static final SmackDebuggerFactory INSTANCE = new Factory(); + + private Factory() { + } + + @Override + public SmackDebugger create(XMPPConnection connection) throws IllegalArgumentException { + return new ConsoleDebugger(connection); + } + + } } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/debugger/JulDebugger.java b/smack-core/src/main/java/org/jivesoftware/smack/debugger/JulDebugger.java index 2fbcfeee1..57e71a3d5 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/debugger/JulDebugger.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/debugger/JulDebugger.java @@ -1,6 +1,6 @@ /** * - * Copyright 2014 Florian Schmaus + * Copyright 2014-2017 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,8 +16,6 @@ */ package org.jivesoftware.smack.debugger; -import java.io.Reader; -import java.io.Writer; import java.util.logging.Level; import java.util.logging.Logger; @@ -38,8 +36,8 @@ public class JulDebugger extends AbstractDebugger { private static final Logger LOGGER = Logger.getLogger(JulDebugger.class.getName()); - public JulDebugger(XMPPConnection connection, Writer writer, Reader reader) { - super(connection, writer, reader); + public JulDebugger(XMPPConnection connection) { + super(connection); } @Override diff --git a/smack-core/src/main/java/org/jivesoftware/smack/debugger/ReflectionDebuggerFactory.java b/smack-core/src/main/java/org/jivesoftware/smack/debugger/ReflectionDebuggerFactory.java index 12fbeae4d..44447ad29 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/debugger/ReflectionDebuggerFactory.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/debugger/ReflectionDebuggerFactory.java @@ -1,6 +1,6 @@ /** * - * Copyright 2014 Vyacheslav Blinov + * Copyright 2014 Vyacheslav Blinov, 2017 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,12 +14,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - package org.jivesoftware.smack.debugger; -import java.io.Reader; -import java.io.Writer; import java.lang.reflect.Constructor; import java.util.logging.Level; import java.util.logging.Logger; @@ -27,10 +23,15 @@ import java.util.logging.Logger; import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.XMPPConnection; -public class ReflectionDebuggerFactory implements SmackDebuggerFactory { +public final class ReflectionDebuggerFactory implements SmackDebuggerFactory { private static final Logger LOGGER = Logger.getLogger(ReflectionDebuggerFactory.class.getName()); private static final String DEBUGGER_CLASS_PROPERTY_NAME = "smack.debuggerClass"; + public static final ReflectionDebuggerFactory INSTANCE = new ReflectionDebuggerFactory(); + + private ReflectionDebuggerFactory() { + } + /** * Possible default debugger implementations. The order of enumeration is the one in which we try * to instantiate these. @@ -76,14 +77,14 @@ public class ReflectionDebuggerFactory implements SmackDebuggerFactory { } @Override - public SmackDebugger create(XMPPConnection connection, Writer writer, Reader reader) throws IllegalArgumentException { + public SmackDebugger create(XMPPConnection connection) throws IllegalArgumentException { Class debuggerClass = getDebuggerClass(); if (debuggerClass != null) { // Create a new debugger instance using 3arg constructor try { Constructor constructor = debuggerClass - .getConstructor(XMPPConnection.class, Writer.class, Reader.class); - return constructor.newInstance(connection, writer, reader); + .getConstructor(XMPPConnection.class); + return constructor.newInstance(connection); } catch (Exception e) { throw new IllegalArgumentException("Can't initialize the configured debugger!", e); } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/debugger/SmackDebugger.java b/smack-core/src/main/java/org/jivesoftware/smack/debugger/SmackDebugger.java index 43ae57434..98a1debc8 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/debugger/SmackDebugger.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/debugger/SmackDebugger.java @@ -1,6 +1,6 @@ /** * - * Copyright 2003-2007 Jive Software. + * Copyright 2003-2007 Jive Software, 2017 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,7 +20,8 @@ package org.jivesoftware.smack.debugger; import java.io.Reader; import java.io.Writer; -import org.jivesoftware.smack.StanzaListener; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.packet.TopLevelStreamElement; import org.jxmpp.jid.EntityFullJid; @@ -33,7 +34,13 @@ import org.jxmpp.jid.EntityFullJid; * * @author Gaston Dombiak */ -public interface SmackDebugger { +public abstract class SmackDebugger { + + protected final XMPPConnection connection; + + protected SmackDebugger(XMPPConnection connection) { + this.connection = connection; + } /** * Called when a user has logged in to the server. The user could be an anonymous user, this @@ -42,22 +49,9 @@ public interface SmackDebugger { * * @param user the user@host/resource that has just logged in */ + // TODO: Should be replaced with a connection listener authenticed(). public abstract void userHasLogged(EntityFullJid user); - /** - * Returns the special Reader that wraps the main Reader and logs data to the GUI. - * - * @return the special Reader that wraps the main Reader and logs data to the GUI. - */ - public abstract Reader getReader(); - - /** - * Returns the special Writer that wraps the main Writer and logs data to the GUI. - * - * @return the special Writer that wraps the main Writer and logs data to the GUI. - */ - public abstract Writer getWriter(); - /** * Returns a new special Reader that wraps the new connection Reader. The connection * has been secured so the connection is using a new reader and writer. The debugger @@ -79,20 +73,23 @@ public interface SmackDebugger { public abstract Writer newConnectionWriter(Writer writer); /** - * Returns the thread that will listen for all incoming packets and write them to the GUI. - * This is what we call "interpreted" stanza(/packet) data, since it's the stanza(/packet) data as Smack sees - * it and not as it's coming in as raw XML. - * - * @return the PacketListener that will listen for all incoming packets and write them to - * the GUI + * Used by the connection to notify about an incoming top level stream element. + *

+ * This method is invoked right after the incoming stream was parsed. + *

+ * + * @param streamElement the incoming top level stream element. */ - public abstract StanzaListener getReaderListener(); + public abstract void onIncomingStreamElement(TopLevelStreamElement streamElement); /** - * Returns the thread that will listen for all outgoing packets and write them to the GUI. - * - * @return the PacketListener that will listen for all sent packets and write them to - * the GUI + * Used by the connection to notify about a outgoing top level stream element. + *

+ * This method is invoked right before the element is serialized to XML and put into the outgoing stream. + *

+ * + * @param streamElement the outgoing top level stream element. */ - public abstract StanzaListener getWriterListener(); + public abstract void onOutgoingStreamElement(TopLevelStreamElement streamElement); + } diff --git a/smack-core/src/main/java/org/jivesoftware/smack/debugger/SmackDebuggerFactory.java b/smack-core/src/main/java/org/jivesoftware/smack/debugger/SmackDebuggerFactory.java index 57d0aac84..e4cfc0580 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/debugger/SmackDebuggerFactory.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/debugger/SmackDebuggerFactory.java @@ -1,6 +1,6 @@ /** * - * Copyright 2014 Vyacheslav Blinov + * Copyright 2014 Vyacheslav Blinov, 2017 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,20 +14,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - - package org.jivesoftware.smack.debugger; -import java.io.Reader; -import java.io.Writer; - import org.jivesoftware.smack.XMPPConnection; public interface SmackDebuggerFactory { /** * Initialize the new SmackDebugger instance. * + * @param connection the XMPP connection this debugger is going to get attached to. * @throws IllegalArgumentException if the SmackDebugger can't be loaded. */ - SmackDebugger create(XMPPConnection connection, Writer writer, Reader reader) throws IllegalArgumentException; + SmackDebugger create(XMPPConnection connection) throws IllegalArgumentException; } diff --git a/smack-core/src/test/java/org/jivesoftware/smack/parsing/StandardExtensionElementParserTest.java b/smack-core/src/test/java/org/jivesoftware/smack/parsing/StandardExtensionElementParserTest.java index b00844092..8c38f08b4 100644 --- a/smack-core/src/test/java/org/jivesoftware/smack/parsing/StandardExtensionElementParserTest.java +++ b/smack-core/src/test/java/org/jivesoftware/smack/parsing/StandardExtensionElementParserTest.java @@ -1,6 +1,6 @@ /** * - * Copyright 2015 Florian Schmaus. + * Copyright 2015-2017 Florian Schmaus. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -46,6 +46,9 @@ public class StandardExtensionElementParserTest { assertEquals("attr2-value", barNs2Element.getAttributeValue("attr2")); assertEquals("another-element-text", parsedElement.getFirstElement("another-element").getText()); + + String parsedElementString = parsedElement.toXML().toString(); + assertEquals(elementString, parsedElementString); } @Test diff --git a/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JDebuggerFactory.java b/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JDebuggerFactory.java index 0cbd95581..904106b8e 100644 --- a/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JDebuggerFactory.java +++ b/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JDebuggerFactory.java @@ -17,9 +17,6 @@ package org.jivesoftware.smackx.debugger.slf4j; -import java.io.Reader; -import java.io.Writer; - import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.debugger.SmackDebugger; import org.jivesoftware.smack.debugger.SmackDebuggerFactory; @@ -27,9 +24,15 @@ import org.jivesoftware.smack.debugger.SmackDebuggerFactory; /** * Implementation of SmackDebuggerFactory which always creates instance of SLF4JSmackDebugger. */ -public class SLF4JDebuggerFactory implements SmackDebuggerFactory { +public final class SLF4JDebuggerFactory implements SmackDebuggerFactory { + + public static final SLF4JDebuggerFactory INSTANCE = new SLF4JDebuggerFactory(); + + private SLF4JDebuggerFactory() { + } + @Override - public SmackDebugger create(XMPPConnection connection, Writer writer, Reader reader) throws IllegalArgumentException { - return new SLF4JSmackDebugger(connection, writer, reader); + public SmackDebugger create(XMPPConnection connection) throws IllegalArgumentException { + return new SLF4JSmackDebugger(connection); } } diff --git a/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JLoggingPacketListener.java b/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JLoggingPacketListener.java deleted file mode 100644 index db25a7f55..000000000 --- a/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JLoggingPacketListener.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * - * Copyright 2014 Vyacheslav Blinov - * - * 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.smackx.debugger.slf4j; - -import org.jivesoftware.smack.StanzaListener; -import org.jivesoftware.smack.packet.Stanza; - -import org.slf4j.Logger; - - -class SLF4JLoggingPacketListener implements StanzaListener { - private final Logger logger; - private final String prefix; - - public SLF4JLoggingPacketListener(Logger logger, String prefix) { - this.logger = Validate.notNull(logger); - this.prefix = Validate.notNull(prefix); - } - - @Override - public void processStanza(Stanza packet) { - if (SLF4JSmackDebugger.printInterpreted.get() && logger.isDebugEnabled()) { - logger.debug("{}: PKT [{}] '{}'", prefix, packet.getClass().getName(), packet.toXML()); - } - } -} diff --git a/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JSmackDebugger.java b/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JSmackDebugger.java index c3b683c37..7b10b38dd 100644 --- a/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JSmackDebugger.java +++ b/smack-debug-slf4j/src/main/java/org/jivesoftware/smackx/debugger/slf4j/SLF4JSmackDebugger.java @@ -22,9 +22,9 @@ import java.io.Writer; import java.util.concurrent.atomic.AtomicBoolean; import org.jivesoftware.smack.SmackConfiguration; -import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.debugger.SmackDebugger; +import org.jivesoftware.smack.packet.TopLevelStreamElement; import org.jivesoftware.smack.util.ObservableReader; import org.jivesoftware.smack.util.ObservableWriter; @@ -38,7 +38,8 @@ import org.slf4j.LoggerFactory; * Use in conjunction with your SLF4J bindings of choice. * See SLF4J manual for more details about bindings usage. */ -public class SLF4JSmackDebugger implements SmackDebugger { +public class SLF4JSmackDebugger extends SmackDebugger { + public static final String LOGGER_NAME = "SMACK"; private static final Logger logger = LoggerFactory.getLogger(LOGGER_NAME); public static final AtomicBoolean printInterpreted = new AtomicBoolean(true); @@ -46,10 +47,6 @@ public class SLF4JSmackDebugger implements SmackDebugger { public static final String SENT_TAG = "SENT"; public static final String RECEIVED_TAG = "RECV"; - private final XMPPConnection connection; - - private final StanzaListener receivedListener = new SLF4JLoggingPacketListener(logger, RECEIVED_TAG); - private final StanzaListener sentListener = new SLF4JLoggingPacketListener(logger, SENT_TAG); private final SLF4JRawXmlListener slf4JRawXmlListener = new SLF4JRawXmlListener(logger); private ObservableWriter writer; @@ -59,17 +56,16 @@ public class SLF4JSmackDebugger implements SmackDebugger { * Makes Smack use this Debugger. */ public static void enable() { - SmackConfiguration.setDebuggerFactory(new SLF4JDebuggerFactory()); + SmackConfiguration.DEBUG = true; + SmackConfiguration.setDefaultSmackDebuggerFactory(SLF4JDebuggerFactory.INSTANCE); } /** * Create new SLF4J Smack Debugger instance. * @param connection Smack connection to debug - * @param writer connection data writer to observe - * @param reader connection data reader to observe */ - public SLF4JSmackDebugger(XMPPConnection connection, Writer writer, Reader reader) { - this.connection = connection; + SLF4JSmackDebugger(XMPPConnection connection) { + super(connection); this.writer = new ObservableWriter(writer); this.writer.addWriterListener(slf4JRawXmlListener); this.reader = new ObservableReader(Validate.notNull(reader)); @@ -101,22 +97,17 @@ public class SLF4JSmackDebugger implements SmackDebugger { } @Override - public Reader getReader() { - return reader; + public void onIncomingStreamElement(TopLevelStreamElement streamElement) { + if (SLF4JSmackDebugger.printInterpreted.get() && logger.isDebugEnabled()) { + logger.debug("IN {}: {}", streamElement.getClass().getName(), streamElement.toXML()); + } } @Override - public Writer getWriter() { - return writer; + public void onOutgoingStreamElement(TopLevelStreamElement streamElement) { + if (SLF4JSmackDebugger.printInterpreted.get() && logger.isDebugEnabled()) { + logger.debug("OUT {}: {}", streamElement.getClass().getName(), streamElement.toXML()); + } } - @Override - public StanzaListener getReaderListener() { - return receivedListener; - } - - @Override - public StanzaListener getWriterListener() { - return sentListener; - } } diff --git a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java index c9ad9909d..989a5681a 100644 --- a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java +++ b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebugger.java @@ -72,13 +72,14 @@ import javax.xml.transform.stream.StreamSource; import org.jivesoftware.smack.AbstractConnectionListener; import org.jivesoftware.smack.ConnectionListener; import org.jivesoftware.smack.SmackException.NotConnectedException; -import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.debugger.SmackDebugger; +import org.jivesoftware.smack.debugger.SmackDebuggerFactory; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.Message; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smack.packet.TopLevelStreamElement; import org.jivesoftware.smack.util.ObservableReader; import org.jivesoftware.smack.util.ObservableWriter; import org.jivesoftware.smack.util.ReaderListener; @@ -97,7 +98,7 @@ import org.jxmpp.jid.Jid; * * @author Gaston Dombiak */ -public class EnhancedDebugger implements SmackDebugger { +public class EnhancedDebugger extends SmackDebugger { private static final Logger LOGGER = Logger.getLogger(EnhancedDebugger.class.getName()); @@ -149,10 +150,6 @@ public class EnhancedDebugger implements SmackDebugger { private JFormattedTextField userField = null; private JFormattedTextField statusField = null; - private XMPPConnection connection = null; - - private StanzaListener packetReaderListener = null; - private StanzaListener packetWriterListener = null; private ConnectionListener connListener = null; private Writer writer; @@ -177,18 +174,9 @@ public class EnhancedDebugger implements SmackDebugger { JTabbedPane tabbedPane; - public EnhancedDebugger(XMPPConnection connection, Writer writer, Reader reader) { - this.connection = connection; - this.writer = writer; - this.reader = reader; - createDebug(); - EnhancedDebuggerWindow.addDebugger(this); - } + public EnhancedDebugger(XMPPConnection connection) { + super(connection); - /** - * Creates the debug process, which is a GUI window that displays XML traffic. - */ - private void createDebug() { // We'll arrange the UI into six tabs. The first tab contains all data, the second // client generated XML, the third server generated XML, the fourth allows to send // ad-hoc messages and the fifth contains connection information. @@ -203,41 +191,6 @@ public class EnhancedDebugger implements SmackDebugger { // Add the connection information panel addInformationPanel(); - // Create a thread that will listen for all incoming packets and write them to - // the GUI. This is what we call "interpreted" packet data, since it's the packet - // data as Smack sees it and not as it's coming in as raw XML. - packetReaderListener = new StanzaListener() { - SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss:SS"); - - @Override - public void processStanza(final Stanza packet) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - addReadPacketToTable(dateFormatter, packet); - } - }); - - } - }; - - // Create a thread that will listen for all outgoing packets and write them to - // the GUI. - packetWriterListener = new StanzaListener() { - SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss:SS"); - - @Override - public void processStanza(final Stanza packet) { - SwingUtilities.invokeLater(new Runnable() { - @Override - public void run() { - addSentPacketToTable(dateFormatter, packet); - } - }); - - } - }; - // Create a thread that will listen for any connection closed event connListener = new AbstractConnectionListener() { @Override @@ -294,6 +247,8 @@ public class EnhancedDebugger implements SmackDebugger { }); } }; + + EnhancedDebuggerWindow.addDebugger(this); } private void addBasicPanels() { @@ -793,26 +748,6 @@ public class EnhancedDebugger implements SmackDebugger { } - @Override - public Reader getReader() { - return reader; - } - - @Override - public Writer getWriter() { - return writer; - } - - @Override - public StanzaListener getReaderListener() { - return packetReaderListener; - } - - @Override - public StanzaListener getWriterListener() { - return packetWriterListener; - } - /** * Updates the statistics table */ @@ -839,12 +774,21 @@ public class EnhancedDebugger implements SmackDebugger { * @param dateFormatter the SimpleDateFormat to use to format Dates * @param packet the read stanza(/packet) to add to the table */ - private void addReadPacketToTable(final SimpleDateFormat dateFormatter, final Stanza packet) { + private void addReadPacketToTable(final SimpleDateFormat dateFormatter, final TopLevelStreamElement packet) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { String messageType; - Jid from = packet.getFrom(); + Jid from; + String stanzaId; + if (packet instanceof Stanza) { + Stanza stanza = (Stanza) packet; + from = stanza.getFrom(); + stanzaId = stanza.getStanzaId(); + } else { + from = null; + stanzaId = "(Nonza)"; + } String type = ""; Icon packetTypeIcon; receivedPackets++; @@ -885,7 +829,7 @@ public class EnhancedDebugger implements SmackDebugger { packetReceivedIcon, packetTypeIcon, messageType, - packet.getStanzaId(), + stanzaId, type, "", from}); @@ -901,12 +845,21 @@ public class EnhancedDebugger implements SmackDebugger { * @param dateFormatter the SimpleDateFormat to use to format Dates * @param packet the sent stanza(/packet) to add to the table */ - private void addSentPacketToTable(final SimpleDateFormat dateFormatter, final Stanza packet) { + private void addSentPacketToTable(final SimpleDateFormat dateFormatter, final TopLevelStreamElement packet) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { String messageType; - Jid to = packet.getTo(); + Jid to; + String stanzaId; + if (packet instanceof Stanza) { + Stanza stanza = (Stanza) packet; + to = stanza.getTo(); + stanzaId = stanza.getStanzaId(); + } else { + to = null; + stanzaId = "(Nonza)"; + } String type = ""; Icon packetTypeIcon; sentPackets++; @@ -947,7 +900,7 @@ public class EnhancedDebugger implements SmackDebugger { packetSentIcon, packetTypeIcon, messageType, - packet.getStanzaId(), + stanzaId, type, to, ""}); @@ -1006,8 +959,6 @@ public class EnhancedDebugger implements SmackDebugger { */ void cancel() { connection.removeConnectionListener(connListener); - connection.removeAsyncStanzaListener(packetReaderListener); - connection.removePacketSendingListener(packetWriterListener); ((ObservableReader) reader).removeReaderListener(readerListener); ((ObservableWriter) writer).removeWriterListener(writerListener); messagesTable = null; @@ -1099,4 +1050,40 @@ public class EnhancedDebugger implements SmackDebugger { } } } + + @Override + public void onIncomingStreamElement(final TopLevelStreamElement streamElement) { + final SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss:SS"); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + addReadPacketToTable(dateFormatter, streamElement); + } + }); + } + + @Override + public void onOutgoingStreamElement(final TopLevelStreamElement streamElement) { + final SimpleDateFormat dateFormatter = new SimpleDateFormat("HH:mm:ss:SS"); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + addSentPacketToTable(dateFormatter, streamElement); + } + }); + } + + public static final class Factory implements SmackDebuggerFactory { + + public static final SmackDebuggerFactory INSTANCE = new Factory(); + + private Factory() { + } + + @Override + public SmackDebugger create(XMPPConnection connection) throws IllegalArgumentException { + return new EnhancedDebugger(connection); + } + + } } diff --git a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebuggerWindow.java b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebuggerWindow.java index f246d1f51..37af7e40c 100644 --- a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebuggerWindow.java +++ b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/EnhancedDebuggerWindow.java @@ -114,7 +114,7 @@ public final class EnhancedDebuggerWindow { * * @return the unique EnhancedDebuggerWindow instance */ - public static EnhancedDebuggerWindow getInstance() { + public synchronized static EnhancedDebuggerWindow getInstance() { if (instance == null) { instance = new EnhancedDebuggerWindow(); } @@ -345,7 +345,7 @@ public final class EnhancedDebuggerWindow { * * @param evt the event that indicates that the root window is closing */ - public void rootWindowClosing(WindowEvent evt) { + private synchronized void rootWindowClosing(WindowEvent evt) { // Notify to all the debuggers to stop debugging for (EnhancedDebugger debugger : debuggers) { debugger.cancel(); @@ -354,6 +354,8 @@ public final class EnhancedDebuggerWindow { debuggers.clear(); // Release the default instance instance = null; + frame = null; + notifyAll(); } /** @@ -393,4 +395,14 @@ public final class EnhancedDebuggerWindow { public boolean isVisible() { return frame != null && frame.isVisible(); } + + public synchronized void waitUntilClosed() throws InterruptedException { + if (frame == null) { + return; + } + + while (frame != null) { + wait(); + } + } } diff --git a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/LiteDebugger.java b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/LiteDebugger.java index cb43de6dd..0ce334e3b 100644 --- a/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/LiteDebugger.java +++ b/smack-debug/src/main/java/org/jivesoftware/smackx/debugger/LiteDebugger.java @@ -40,10 +40,9 @@ import javax.swing.JScrollPane; import javax.swing.JTabbedPane; import javax.swing.JTextArea; -import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.debugger.SmackDebugger; -import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smack.packet.TopLevelStreamElement; import org.jivesoftware.smack.util.ObservableReader; import org.jivesoftware.smack.util.ObservableWriter; import org.jivesoftware.smack.util.ReaderListener; @@ -57,24 +56,22 @@ import org.jxmpp.jid.EntityFullJid; * * @author Gaston Dombiak */ -public class LiteDebugger implements SmackDebugger { +public class LiteDebugger extends SmackDebugger { private static final String NEWLINE = "\n"; - private JFrame frame = null; - private XMPPConnection connection = null; + private final JTextArea interpretedText1 = new JTextArea(); + private final JTextArea interpretedText2 = new JTextArea(); - private StanzaListener listener = null; + private JFrame frame = null; private Writer writer; private Reader reader; private ReaderListener readerListener; private WriterListener writerListener; - public LiteDebugger(XMPPConnection connection, Writer writer, Reader reader) { - this.connection = connection; - this.writer = writer; - this.reader = reader; + public LiteDebugger(XMPPConnection connection) { + super(connection); createDebug(); } @@ -181,8 +178,6 @@ public class LiteDebugger implements SmackDebugger { menu.add(menuItem2); // Create UI elements for interpreted XML traffic. - final JTextArea interpretedText1 = new JTextArea(); - final JTextArea interpretedText2 = new JTextArea(); interpretedText1.setEditable(false); interpretedText2.setEditable(false); interpretedText1.setForeground(new Color(1, 94, 35)); @@ -267,19 +262,6 @@ public class LiteDebugger implements SmackDebugger { // and writer will use the debug versions when they are created. reader = debugReader; writer = debugWriter; - - // Create a thread that will listen for all incoming packets and write them to - // the GUI. This is what we call "interpreted" packet data, since it's the packet - // data as Smack sees it and not as it's coming in as raw XML. - listener = new StanzaListener() { - @Override - public void processStanza(Stanza packet) { - interpretedText1.append(packet.toXML().toString()); - interpretedText2.append(packet.toXML().toString()); - interpretedText1.append(NEWLINE); - interpretedText2.append(NEWLINE); - } - }; } /** @@ -289,7 +271,7 @@ public class LiteDebugger implements SmackDebugger { * @param evt the event that indicates that the root window is closing */ public void rootWindowClosing(WindowEvent evt) { - connection.removeAsyncStanzaListener(listener); + // TODO: Remove debugger from connection. ((ObservableReader) reader).removeReaderListener(readerListener); ((ObservableWriter) writer).removeWriterListener(writerListener); } @@ -348,22 +330,16 @@ public class LiteDebugger implements SmackDebugger { } @Override - public Reader getReader() { - return reader; + public void onIncomingStreamElement(TopLevelStreamElement streamElement) { + interpretedText1.append(streamElement.toXML().toString()); + interpretedText2.append(streamElement.toXML().toString()); + interpretedText1.append(NEWLINE); + interpretedText2.append(NEWLINE); } @Override - public Writer getWriter() { - return writer; + public void onOutgoingStreamElement(TopLevelStreamElement streamElement) { + // Does nothing. } - @Override - public StanzaListener getReaderListener() { - return listener; - } - - @Override - public StanzaListener getWriterListener() { - return null; - } } diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/adapter/JingleFileTransferAdapter.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/adapter/JingleFileTransferAdapter.java index 307a4d9d2..79a4fa211 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/adapter/JingleFileTransferAdapter.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/jft/adapter/JingleFileTransferAdapter.java @@ -18,13 +18,13 @@ package org.jivesoftware.smackx.jft.adapter; import java.util.List; +import org.jivesoftware.smack.packet.NamedElement; import org.jivesoftware.smackx.jft.component.JingleFileTransfer; import org.jivesoftware.smackx.jft.component.JingleIncomingFileOffer; import org.jivesoftware.smackx.jft.component.JingleIncomingFileRequest; import org.jivesoftware.smackx.jft.element.JingleFileTransferChildElement; import org.jivesoftware.smackx.jft.element.JingleFileTransferElement; import org.jivesoftware.smackx.jingle.adapter.JingleDescriptionAdapter; -import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionChildElement; import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionElement; import org.jivesoftware.smackx.jingle.element.JingleContentElement; @@ -37,9 +37,9 @@ public class JingleFileTransferAdapter implements JingleDescriptionAdapter childs = description.getJingleContentDescriptionChildren(); - assert childs.size() == 1; - JingleFileTransferChildElement file = (JingleFileTransferChildElement) childs.get(0); + List children = description.getJingleContentDescriptionChildren(); + assert children.size() == 1; + JingleFileTransferChildElement file = (JingleFileTransferChildElement) children.get(0); if (senders == JingleContentElement.Senders.initiator) { return new JingleIncomingFileOffer(file); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionElement.java index 780ad4a18..d34009314 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionElement.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentDescriptionElement.java @@ -20,6 +20,7 @@ import java.util.Collections; import java.util.List; import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.packet.NamedElement; import org.jivesoftware.smack.util.XmlStringBuilder; /** @@ -37,9 +38,9 @@ public abstract class JingleContentDescriptionElement implements ExtensionElemen public static final String ELEMENT = "description"; - private final List payloads; + private final List payloads; - protected JingleContentDescriptionElement(List payloads) { + protected JingleContentDescriptionElement(List payloads) { if (payloads != null) { this.payloads = Collections.unmodifiableList(payloads); } @@ -53,7 +54,7 @@ public abstract class JingleContentDescriptionElement implements ExtensionElemen return ELEMENT; } - public List getJingleContentDescriptionChildren() { + public List getJingleContentDescriptionChildren() { return payloads; } @@ -66,7 +67,7 @@ public abstract class JingleContentDescriptionElement implements ExtensionElemen } @Override - public final XmlStringBuilder toXML() { + public XmlStringBuilder toXML() { XmlStringBuilder xml = new XmlStringBuilder(this); addExtraAttributes(xml); xml.rightAngleBracket(); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentElement.java index 6df3a0375..c9a962a4d 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentElement.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentElement.java @@ -115,9 +115,8 @@ public final class JingleContentElement implements NamedElement { } /** - * Returns an Iterator for the JingleTransports in the packet. - * - * @return an Iterator for the JingleTransports in the packet. + * Return the transport of the content. + * @return transport. */ public JingleContentTransportElement getTransport() { return transport; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportElement.java index bc1d17899..5961f82ed 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportElement.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleContentTransportElement.java @@ -72,7 +72,7 @@ public abstract class JingleContentTransportElement implements ExtensionElement } @Override - public final XmlStringBuilder toXML() { + public XmlStringBuilder toXML() { XmlStringBuilder xml = new XmlStringBuilder(this); addExtraAttributes(xml); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleElement.java index febf0308b..40ef27735 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleElement.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/JingleElement.java @@ -136,6 +136,18 @@ public final class JingleElement extends IQ { return contents; } + public JingleContentElement getSoleContentOrThrow() { + if (contents.isEmpty()) { + return null; + } + + if (contents.size() == 1) { + return contents.get(0); + } + + throw new IllegalStateException("More than one content is present."); + } + @Override protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) { xml.optAttribute(INITIATOR_ATTRIBUTE_NAME, getInitiator()); diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentDescriptionElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentDescriptionElement.java new file mode 100644 index 000000000..282924588 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentDescriptionElement.java @@ -0,0 +1,49 @@ +/** + * + * Copyright 2017 Florian Schmaus, Paul Schaub. + * + * 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.smackx.jingle.element; + +import org.jivesoftware.smack.packet.StandardExtensionElement; +import org.jivesoftware.smack.util.XmlStringBuilder; + +public final class UnknownJingleContentDescriptionElement extends JingleContentDescriptionElement { + + private final StandardExtensionElement standardExtensionElement; + + public UnknownJingleContentDescriptionElement(StandardExtensionElement standardExtensionElement) { + super(standardExtensionElement.getElements()); + this.standardExtensionElement = standardExtensionElement; + } + + @Override + public String getElementName() { + return standardExtensionElement.getElementName(); + } + + @Override + public String getNamespace() { + return standardExtensionElement.getNamespace(); + } + + @Override + public XmlStringBuilder toXML() { + return standardExtensionElement.toXML(); + } + + public StandardExtensionElement getStandardExtensionElement() { + return standardExtensionElement; + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentTransportElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentTransportElement.java new file mode 100644 index 000000000..d92c6dc26 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/element/UnknownJingleContentTransportElement.java @@ -0,0 +1,61 @@ +/** + * + * Copyright 2017 Florian Schmaus, Paul Schaub. + * + * 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.smackx.jingle.element; + +import java.util.List; + +import org.jivesoftware.smack.packet.StandardExtensionElement; +import org.jivesoftware.smack.util.XmlStringBuilder; + +public final class UnknownJingleContentTransportElement extends JingleContentTransportElement { + + private final StandardExtensionElement standardExtensionElement; + + public UnknownJingleContentTransportElement(StandardExtensionElement standardExtensionElement) { + super(null, null); + this.standardExtensionElement = standardExtensionElement; + } + + @Override + public String getElementName() { + return standardExtensionElement.getElementName(); + } + + @Override + public String getNamespace() { + return standardExtensionElement.getNamespace(); + } + + @Override + public XmlStringBuilder toXML() { + return standardExtensionElement.toXML(); + } + + @Override + public List getCandidates() { + throw new UnsupportedOperationException(); + } + + @Override + public JingleContentTransportInfoElement getInfo() { + throw new UnsupportedOperationException(); + } + + public StandardExtensionElement getStandardExtensionElement() { + return standardExtensionElement; + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleProvider.java index fbc537313..a8bb4ab61 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/provider/JingleProvider.java @@ -18,16 +18,19 @@ package org.jivesoftware.smackx.jingle.provider; import java.util.logging.Logger; +import org.jivesoftware.smack.packet.StandardExtensionElement; +import org.jivesoftware.smack.parsing.StandardExtensionElementProvider; import org.jivesoftware.smack.provider.IQProvider; import org.jivesoftware.smack.util.ParserUtils; import org.jivesoftware.smackx.jingle.JingleManager; import org.jivesoftware.smackx.jingle.element.JingleAction; import org.jivesoftware.smackx.jingle.element.JingleContentDescriptionElement; import org.jivesoftware.smackx.jingle.element.JingleContentElement; -import org.jivesoftware.smackx.jingle.element.JingleContentSecurityElement; import org.jivesoftware.smackx.jingle.element.JingleContentTransportElement; import org.jivesoftware.smackx.jingle.element.JingleElement; import org.jivesoftware.smackx.jingle.element.JingleReasonElement; +import org.jivesoftware.smackx.jingle.element.UnknownJingleContentDescriptionElement; +import org.jivesoftware.smackx.jingle.element.UnknownJingleContentTransportElement; import org.jxmpp.jid.FullJid; import org.xmlpull.v1.XmlPullParser; @@ -117,48 +120,45 @@ public class JingleProvider extends IQProvider { outerloop: while (true) { int eventType = parser.next(); switch (eventType) { - case XmlPullParser.START_TAG: - String tagName = parser.getName(); - String namespace = parser.getNamespace(); - switch (tagName) { - case JingleContentDescriptionElement.ELEMENT: { - JingleContentDescriptionProvider provider = JingleManager.getJingleDescriptionProvider(namespace); - if (provider == null) { - // TODO handle this case (DefaultExtensionElement wrapped in something?) - break; - } - JingleContentDescriptionElement description = provider.parse(parser); - builder.setDescription(description); - break; - } - case JingleContentTransportElement.ELEMENT: { - JingleContentTransportProvider provider = JingleManager.getJingleTransportProvider(namespace); - if (provider == null) { - // TODO handle this case (DefaultExtensionElement wrapped in something?) - break; - } - JingleContentTransportElement transport = provider.parse(parser); - builder.setTransport(transport); - break; - } - case JingleContentSecurityElement.ELEMENT: { - JingleContentSecurityProvider provider = JingleManager.getJingleSecurityProvider(namespace); - if (provider == null) { - //TODO: handle this case (see above) - } - JingleContentSecurityElement security = provider.parse(parser); - builder.setSecurity(security); - break; - } - default: - LOGGER.severe("Unknown Jingle content element: " + tagName); - break; + case XmlPullParser.START_TAG: + String tagName = parser.getName(); + String namespace = parser.getNamespace(); + switch (tagName) { + case JingleContentDescriptionElement.ELEMENT: { + JingleContentDescriptionElement description; + JingleContentDescriptionProvider provider = JingleManager.getJingleDescriptionProvider(namespace); + if (provider == null) { + StandardExtensionElement standardExtensionElement = StandardExtensionElementProvider.INSTANCE.parse(parser); + description = new UnknownJingleContentDescriptionElement(standardExtensionElement); } + else { + description = provider.parse(parser); + } + builder.setDescription(description); break; - case XmlPullParser.END_TAG: - if (parser.getDepth() == initialDepth) { - break outerloop; + } + case JingleContentTransportElement.ELEMENT: { + JingleContentTransportElement transport; + JingleContentTransportProvider provider = JingleManager.getJingleTransportProvider(namespace); + if (provider == null) { + StandardExtensionElement standardExtensionElement = StandardExtensionElementProvider.INSTANCE.parse(parser); + transport = new UnknownJingleContentTransportElement(standardExtensionElement); } + else { + transport = provider.parse(parser); + } + builder.setTransport(transport); + break; + } + default: + LOGGER.severe("Unknown Jingle content element: " + tagName); + break; + } + break; + case XmlPullParser.END_TAG: + if (parser.getDepth() == initialDepth) { + break outerloop; + } } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportManager.java index 389ad3497..5537ad7a6 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportManager.java @@ -65,7 +65,7 @@ public final class JingleS5BTransportManager extends Manager implements JingleTr private List localStreamHosts = null; private List availableStreamHosts = null; - private static boolean useLocalCandidates = false; + private static boolean useLocalCandidates = true; private static boolean useExternalCandidates = true; static { @@ -222,19 +222,19 @@ public final class JingleS5BTransportManager extends Manager implements JingleTr } JingleElement createCandidateUsed(JingleS5BTransport transport, JingleS5BTransportCandidate candidate) { - return createTransportInfo(transport, JingleS5BTransportInfoElement.CandidateUsed(candidate.getCandidateId())); + return createTransportInfo(transport, new JingleS5BTransportInfoElement.CandidateUsed(candidate.getCandidateId())); } JingleElement createCandidateError(JingleS5BTransport transport) { - return createTransportInfo(transport, JingleS5BTransportInfoElement.CandidateError()); + return createTransportInfo(transport, JingleS5BTransportInfoElement.CandidateError.INSTANCE); } JingleElement createProxyError(JingleS5BTransport transport) { - return createTransportInfo(transport, JingleS5BTransportInfoElement.ProxyError()); + return createTransportInfo(transport, JingleS5BTransportInfoElement.ProxyError.INSTANCE); } JingleElement createCandidateActivated(JingleS5BTransport transport, JingleS5BTransportCandidate candidate) { - return createTransportInfo(transport, JingleS5BTransportInfoElement.CandidateActivated(candidate.getCandidateId())); + return createTransportInfo(transport, new JingleS5BTransportInfoElement.CandidateActivated(candidate.getCandidateId())); } public static void setUseLocalCandidates(boolean localCandidates) { diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportElement.java index f53853756..7a29adb27 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportElement.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportElement.java @@ -135,5 +135,23 @@ public class JingleS5BTransportElement extends JingleContentTransportElement { public JingleS5BTransportElement build() { return new JingleS5BTransportElement(streamId, candidates, info, dstAddr, mode); } + + public Builder setCandidateUsed(String candidateId) { + return setTransportInfo(new JingleS5BTransportInfoElement.CandidateUsed(candidateId)); + } + + public Builder setCandidateActivated(String candidateId) { + return setTransportInfo(new JingleS5BTransportInfoElement.CandidateActivated(candidateId)); + } + + public Builder setCandidateError() { + return setTransportInfo(JingleS5BTransportInfoElement.CandidateError.INSTANCE); + } + + public Builder setProxyError() { + return setTransportInfo(JingleS5BTransportInfoElement.ProxyError.INSTANCE); + } + } } + diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportInfoElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportInfoElement.java index 007873c6c..fc5acaa31 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportInfoElement.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/element/JingleS5BTransportInfoElement.java @@ -24,112 +24,76 @@ import org.jivesoftware.smackx.jingle.element.JingleContentTransportInfoElement; */ public abstract class JingleS5BTransportInfoElement extends JingleContentTransportInfoElement { - private static CandidateError CEI; - private static ProxyError PEI; - - public static CandidateUsed CandidateUsed(String candidateId) { - return new CandidateUsed(candidateId); - } - - public static CandidateActivated CandidateActivated(String candidateId) { - return new CandidateActivated(candidateId); - } - - public static CandidateError CandidateError() { - if (CEI == null) { - CEI = new CandidateError(); - } - return CEI; - } - - public static ProxyError ProxyError() { - if (PEI == null) { - PEI = new ProxyError(); - } - return PEI; - } - - public static final class CandidateActivated extends JingleS5BTransportInfoElement { - public static final String ELEMENT = "candidate-activated"; + public static abstract class JingleS5BCandidateTransportInfoElement extends JingleS5BTransportInfoElement { public static final String ATTR_CID = "cid"; private final String candidateId; + protected JingleS5BCandidateTransportInfoElement(String candidateId) { + this.candidateId = candidateId; + } + + public final String getCandidateId() { + return candidateId; + } + + @Override + public final XmlStringBuilder toXML() { + XmlStringBuilder xml = new XmlStringBuilder(); + xml.halfOpenElement(this); + xml.attribute(ATTR_CID, getCandidateId()); + xml.closeEmptyElement(); + return xml; + } + + @Override + public final boolean equals(Object other) { + if (!(other instanceof JingleS5BCandidateTransportInfoElement)) { + return false; + } + + JingleS5BCandidateTransportInfoElement otherCandidateTransportInfo = (JingleS5BCandidateTransportInfoElement) other; + return toXML().equals(otherCandidateTransportInfo.toXML()); + } + + @Override + public final int hashCode() { + return getCandidateId().hashCode(); + } + } + + public static final class CandidateActivated extends JingleS5BCandidateTransportInfoElement { + public static final String ELEMENT = "candidate-activated"; + public CandidateActivated(String candidateId) { - this.candidateId = candidateId; - } - - public String getCandidateId() { - return candidateId; + super(candidateId); } @Override public String getElementName() { return ELEMENT; } - - @Override - public CharSequence toXML() { - XmlStringBuilder xml = new XmlStringBuilder(); - xml.halfOpenElement(this); - xml.attribute(ATTR_CID, candidateId); - xml.closeEmptyElement(); - return xml; - } - - @Override - public boolean equals(Object other) { - return other instanceof CandidateActivated && - ((CandidateActivated) other).getCandidateId().equals(candidateId); - } - - @Override - public int hashCode() { - return toXML().toString().hashCode(); - } } - public static final class CandidateUsed extends JingleS5BTransportInfoElement { - public static final String ELEMENT = "candidate-used"; - public static final String ATTR_CID = "cid"; - private final String candidateId; + public static final class CandidateUsed extends JingleS5BCandidateTransportInfoElement { + public static final String ELEMENT = "candidate-used"; public CandidateUsed(String candidateId) { - this.candidateId = candidateId; - } - - public String getCandidateId() { - return candidateId; + super(candidateId); } @Override public String getElementName() { return ELEMENT; } - - @Override - public CharSequence toXML() { - XmlStringBuilder xml = new XmlStringBuilder(); - xml.halfOpenElement(this); - xml.attribute(ATTR_CID, candidateId); - xml.closeEmptyElement(); - return xml; - } - - @Override - public boolean equals(Object other) { - return other instanceof CandidateUsed && - ((CandidateUsed) other).getCandidateId().equals(candidateId); - } - - @Override - public int hashCode() { - return toXML().toString().hashCode(); - } } + public static final class CandidateError extends JingleS5BTransportInfoElement { + + public static final CandidateError INSTANCE = new CandidateError(); + public static final String ELEMENT = "candidate-error"; private CandidateError() { @@ -142,7 +106,7 @@ public abstract class JingleS5BTransportInfoElement extends JingleContentTranspo } @Override - public CharSequence toXML() { + public XmlStringBuilder toXML() { XmlStringBuilder xml = new XmlStringBuilder(); xml.halfOpenElement(this); xml.closeEmptyElement(); @@ -151,7 +115,7 @@ public abstract class JingleS5BTransportInfoElement extends JingleContentTranspo @Override public boolean equals(Object other) { - return other instanceof CandidateError; + return other == INSTANCE; } @Override @@ -160,7 +124,10 @@ public abstract class JingleS5BTransportInfoElement extends JingleContentTranspo } } + public static final class ProxyError extends JingleS5BTransportInfoElement { + public static final ProxyError INSTANCE = new ProxyError(); + public static final String ELEMENT = "proxy-error"; private ProxyError() { @@ -173,7 +140,7 @@ public abstract class JingleS5BTransportInfoElement extends JingleContentTranspo } @Override - public CharSequence toXML() { + public XmlStringBuilder toXML() { XmlStringBuilder xml = new XmlStringBuilder(); xml.halfOpenElement(this); xml.closeEmptyElement(); @@ -182,7 +149,7 @@ public abstract class JingleS5BTransportInfoElement extends JingleContentTranspo @Override public boolean equals(Object other) { - return other instanceof ProxyError; + return other == INSTANCE; } @Override diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/provider/JingleS5BTransportProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/provider/JingleS5BTransportProvider.java index af959b256..f065cfc01 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/provider/JingleS5BTransportProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/provider/JingleS5BTransportProvider.java @@ -85,23 +85,23 @@ public class JingleS5BTransportProvider extends JingleContentTransportProvider" + + "" + + "1969-07-21T02:56:15Z" + + "This is a test. If this were a real file..." + + "text/plain" + + "test.txt" + + "" + + "6144" + + "w0mcJylzCn+AfvuGdqkty2+KP48=" + + "" + + ""; + // @formatter:on + XmlPullParser parser = createTestJingle(unknownJingleContentDescription); + JingleElement jingle = (JingleElement) PacketParserUtils.parseIQ(parser); + + JingleContentDescriptionElement jingleContentDescription = jingle.getSoleContentOrThrow().getDescription(); + + String parsedUnknownJingleContentDescrptionNamespace = jingleContentDescription.getNamespace(); + assertEquals(unknownJingleContentDescriptionNamespace, parsedUnknownJingleContentDescrptionNamespace); + } + + @Test + public void testParseUnknownJingleContentTransport() throws Exception { + final String unknownJingleContentTransportNamespace = "urn:xmpp:jingle:unknown-transport:foo:1"; + final String unknownJingleContentTransport = + // @formatter:off + "" + + "" + + "" + + ""; + // @formatter:on + XmlPullParser parser = createTestJingle(unknownJingleContentTransport); + JingleElement jingle = (JingleElement) PacketParserUtils.parseIQ(parser); + + JingleContentTransportElement jingleContentTransport = jingle.getSoleContentOrThrow().getTransport(); + + String parsedUnknownJingleContentTransportNamespace = jingleContentTransport.getNamespace(); + assertEquals(unknownJingleContentTransportNamespace, parsedUnknownJingleContentTransportNamespace); + } + + private static XmlPullParser createTestJingle(String... childs) throws XmlPullParserException, IOException { + StringBuilder sb = new StringBuilder(); + sb.append(// @formatter:off + "" + + "" + + "" + // @formatter:on + ); + for (String child : childs) { + sb.append(child); + } + sb.append(// @formatter:off + "" + + "" + + "" + // @formatter:on + ); + + String jingleStanza = sb.toString(); + + XmlPullParser parser = PacketParserUtils.getParserFor(jingleStanza); + return parser; + } +} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportTest.java index 850f3aca7..272f6199a 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/jingle/transport/jingle_s5b/JingleS5BTransportTest.java @@ -163,7 +163,7 @@ public class JingleS5BTransportTest extends SmackTestSuite { assertNull(candidateErrorTransport.getDestinationAddress()); assertNotNull(candidateErrorTransport.getInfo()); assertEquals("vj3hs98y", candidateErrorTransport.getSid()); - assertEquals(JingleS5BTransportInfoElement.CandidateError(), + assertEquals(JingleS5BTransportInfoElement.CandidateError.INSTANCE, candidateErrorTransport.getInfo()); assertEquals(candidateError, candidateErrorTransport.toXML().toString()); @@ -177,7 +177,7 @@ public class JingleS5BTransportTest extends SmackTestSuite { assertNotNull(proxyErrorTransport.getInfo()); assertNotNull(candidateErrorTransport.getInfo()); assertEquals("vj3hs98y", proxyErrorTransport.getSid()); - assertEquals(JingleS5BTransportInfoElement.ProxyError(), + assertEquals(JingleS5BTransportInfoElement.ProxyError.INSTANCE, proxyErrorTransport.getInfo()); assertEquals(proxyError, proxyErrorTransport.toXML().toString()); @@ -188,7 +188,7 @@ public class JingleS5BTransportTest extends SmackTestSuite { JingleS5BTransportElement candidateUsedTransport = new JingleS5BTransportProvider() .parse(TestUtils.getParser(candidateUsed)); assertNotNull(candidateUsedTransport.getInfo()); - assertEquals(JingleS5BTransportInfoElement.CandidateUsed("hr65dqyd"), + assertEquals(new JingleS5BTransportInfoElement.CandidateUsed("hr65dqyd"), candidateUsedTransport.getInfo()); assertEquals("hr65dqyd", ((JingleS5BTransportInfoElement.CandidateUsed) @@ -204,7 +204,7 @@ public class JingleS5BTransportTest extends SmackTestSuite { assertNotNull(candidateActivatedTransport.getInfo()); assertNotNull(candidateErrorTransport.getInfo()); - assertEquals(JingleS5BTransportInfoElement.CandidateActivated("hr65dqyd"), + assertEquals(new JingleS5BTransportInfoElement.CandidateActivated("hr65dqyd"), candidateActivatedTransport.getInfo()); assertEquals("hr65dqyd", ((JingleS5BTransportInfoElement.CandidateActivated) diff --git a/smack-integration-test/build.gradle b/smack-integration-test/build.gradle index 07c3a10e0..65ff935e2 100644 --- a/smack-integration-test/build.gradle +++ b/smack-integration-test/build.gradle @@ -12,6 +12,7 @@ dependencies { compile project(':smack-extensions') compile project(':smack-experimental') compile project(':smack-omemo') + compile project(':smack-debug') compile 'org.reflections:reflections:0.9.9-RC1' compile 'eu.geekplace.javapinning:java-pinning-java7:1.1.0-alpha1' compile "junit:junit:$junitVersion" diff --git a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/Configuration.java b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/Configuration.java index e32f3beee..0e355abe6 100644 --- a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/Configuration.java +++ b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/Configuration.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map.Entry; import java.util.Properties; import java.util.Set; +import java.util.logging.Logger; import javax.net.ssl.SSLContext; @@ -41,12 +42,20 @@ import org.jxmpp.stringprep.XmppStringprepException; public final class Configuration { + private static final Logger LOGGER = Logger.getLogger(Configuration.class.getName()); + public enum AccountRegistration { disabled, inBandRegistration, serviceAdministration, } + public enum Debugger { + none, + console, + enhanced, + } + public final DomainBareJid service; public final String serviceTlsPin; @@ -75,7 +84,7 @@ public final class Configuration { public final String accountThreePassword; - public final boolean debug; + public final Debugger debugger; public final Set enabledTests; @@ -84,7 +93,7 @@ public final class Configuration { public final Set testPackages; private Configuration(DomainBareJid service, String serviceTlsPin, SecurityMode securityMode, int replyTimeout, - boolean debug, String accountOneUsername, String accountOnePassword, String accountTwoUsername, + Debugger debugger, String accountOneUsername, String accountOnePassword, String accountTwoUsername, String accountTwoPassword, String accountThreeUsername, String accountThreePassword, Set enabledTests, Set disabledTests, Set testPackages, String adminAccountUsername, String adminAccountPassword) throws KeyManagementException, NoSuchAlgorithmException { @@ -102,7 +111,7 @@ public final class Configuration { } else { this.replyTimeout = 60000; } - this.debug = debug; + this.debugger = debugger; if (StringUtils.isNotEmpty(adminAccountUsername, adminAccountPassword)) { accountRegistration = AccountRegistration.serviceAdministration; } @@ -162,7 +171,7 @@ public final class Configuration { public String accountThreePassword; - private boolean debug; + private Debugger debugger = Debugger.none; private Set enabledTests; @@ -247,9 +256,27 @@ public final class Configuration { return this; } - public Builder setDebug(String debugString) { - if (debugString != null) { - debug = Boolean.valueOf(debugString); + @SuppressWarnings("fallthrough") + public Builder setDebugger(String debuggerString) { + if (debuggerString == null) { + return this; + } + switch (debuggerString) { + case "false": // For backwards compatibility settings with previous boolean setting. + LOGGER.warning("Debug string \"" + debuggerString + "\" is deprecated, please use \"none\" instead"); + case "none": + debugger = Debugger.none; + break; + case "true": // For backwards compatibility settings with previous boolean setting. + LOGGER.warning("Debug string \"" + debuggerString + "\" is deprecated, please use \"console\" instead"); + case "console": + debugger = Debugger.console; + break; + case "enhanced": + debugger = Debugger.enhanced; + break; + default: + throw new IllegalArgumentException("Unrecognized debugger string: " + debuggerString); } return this; } @@ -291,7 +318,7 @@ public final class Configuration { } public Configuration build() throws KeyManagementException, NoSuchAlgorithmException { - return new Configuration(service, serviceTlsPin, securityMode, replyTimeout, debug, accountOneUsername, + return new Configuration(service, serviceTlsPin, securityMode, replyTimeout, debugger, accountOneUsername, accountOnePassword, accountTwoUsername, accountTwoPassword, accountThreeUsername, accountThreePassword, enabledTests, disabledTests, testPackages, adminAccountUsername, adminAccountPassword); } @@ -346,7 +373,12 @@ public final class Configuration { accountTwoPassword, accountThreeUsername, accountThreePassword); } - builder.setDebug(properties.getProperty("debug")); + String debugString = properties.getProperty("debug"); + if (debugString != null) { + LOGGER.warning("Usage of depreacted 'debug' option detected, please use 'debugger' instead"); + builder.setDebugger(debugString); + } + builder.setDebugger(properties.getProperty("debugger")); builder.setEnabledTests(properties.getProperty("enabledTests")); builder.setDisabledTests(properties.getProperty("disabledTests")); diff --git a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java index 4cbc87be8..dab2d9514 100644 --- a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java +++ b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java @@ -48,11 +48,14 @@ import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.XMPPException; +import org.jivesoftware.smack.debugger.ConsoleDebugger; import org.jivesoftware.smack.tcp.XMPPTCPConnection; import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration; import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration.Builder; import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smackx.debugger.EnhancedDebugger; +import org.jivesoftware.smackx.debugger.EnhancedDebuggerWindow; import org.jivesoftware.smackx.iqregister.AccountManager; import org.igniterealtime.smack.inttest.IntTestUtil.UsernameAndPassword; @@ -98,6 +101,8 @@ public class SmackIntegrationTestFramework { final int possibleTests = testRunResult.getNumberOfPossibleTests(); LOGGER.info("SmackIntegrationTestFramework[" + testRunResult.testRunId + ']' + ": Finished [" + successfulTests + '/' + possibleTests + "] (of " + availableTests + " available tests)"); + + int exitStatus; if (!testRunResult.failedIntegrationTests.isEmpty()) { final int failedTests = testRunResult.failedIntegrationTests.size(); LOGGER.warning("The following " + failedTests + " tests failed!"); @@ -108,11 +113,21 @@ public class SmackIntegrationTestFramework { final Throwable cause = failedTest.failureReason; LOGGER.severe(className + CLASS_METHOD_SEP + methodName + " failed: " + cause); } - System.exit(2); + exitStatus = 2; } else { LOGGER.info("All possible Smack Integration Tests completed successfully. \\o/"); + exitStatus = 0; } - System.exit(0); + + switch (config.debugger) { + case enhanced: + EnhancedDebuggerWindow.getInstance().waitUntilClosed(); + break; + default: + break; + } + + System.exit(exitStatus); } public SmackIntegrationTestFramework(Configuration configuration) { @@ -123,7 +138,7 @@ public class SmackIntegrationTestFramework { IOException, XMPPException, InterruptedException { testRunResult = new TestRunResult(); LOGGER.info("SmackIntegrationTestFramework [" + testRunResult.testRunId + ']' + ": Starting"); - if (config.debug) { + if (config.debugger != Configuration.Debugger.none) { // JUL Debugger will not print any information until configured to print log messages of // level FINE // TODO configure JUL for log? @@ -583,6 +598,19 @@ public class SmackIntegrationTestFramework { } builder.setSecurityMode(config.securityMode); builder.setXmppDomain(config.service); + + switch (config.debugger) { + case enhanced: + builder.setDebuggerFactory(EnhancedDebugger.Factory.INSTANCE); + break; + case console: + builder.setDebuggerFactory(ConsoleDebugger.Factory.INSTANCE); + break; + case none: + // Nothing to do :). + break; + } + XMPPTCPConnection connection = new XMPPTCPConnection(builder.build()); connection.connect(); UsernameAndPassword uap = IntTestUtil.registerAccount(connection, environment, connectionId); diff --git a/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/IoT.java b/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/IoT.java index 41f03858c..8c05383ba 100644 --- a/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/IoT.java +++ b/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/IoT.java @@ -67,11 +67,11 @@ public class IoT { final XMPPTCPConnectionConfiguration dataThingConnectionConfiguration = XMPPTCPConnectionConfiguration.builder() .setUsernameAndPassword(dataThingJid.getLocalpart(), dataThingPassword) .setXmppDomain(dataThingJid.asDomainBareJid()).setSecurityMode(SecurityMode.disabled) - .setDebuggerEnabled(true).build(); + .enableDefaultDebugger().build(); final XMPPTCPConnectionConfiguration readingThingConnectionConfiguration = XMPPTCPConnectionConfiguration .builder().setUsernameAndPassword(readingThingJid.getLocalpart(), readingThingPassword) .setXmppDomain(readingThingJid.asDomainBareJid()).setSecurityMode(SecurityMode.disabled) - .setDebuggerEnabled(true).build(); + .enableDefaultDebugger().build(); final XMPPTCPConnection dataThingConnection = new XMPPTCPConnection(dataThingConnectionConfiguration); final XMPPTCPConnection readingThingConnection = new XMPPTCPConnection(readingThingConnectionConfiguration); diff --git a/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/TlsTest.java b/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/TlsTest.java index 2ebcca496..6cf7ffe71 100644 --- a/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/TlsTest.java +++ b/smack-repl/src/main/java/org/igniterealtime/smack/smackrepl/TlsTest.java @@ -79,7 +79,9 @@ public class TlsTest { .setPort(port) .setSecurityMode(SecurityMode.required); // @formatter:on - builder.setDebuggerEnabled(DEBUG); + if (DEBUG) { + builder.enableDefaultDebugger(); + } if (StringUtils.isNotEmpty(tlsPin)) { SSLContext sslContext = Java7Pinning.forPin(tlsPin); diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java index fc3448024..9d598dd7e 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java @@ -636,15 +636,6 @@ public class XMPPTCPConnection extends AbstractXMPPConnection { if (isFirstInitialization) { packetWriter = new PacketWriter(); packetReader = new PacketReader(); - - // If debugging is enabled, we should start the thread that will listen for - // all packets and then log them. - if (config.isDebuggerEnabled()) { - addAsyncStanzaListener(debugger.getReaderListener(), null); - if (debugger.getWriterListener() != null) { - addPacketSendingListener(debugger.getWriterListener(), null); - } - } } // Start the packet writer. This will open an XMPP stream to the server packetWriter.init();