From 255f7a1ad5912da6384532bf2b041da7788e98a8 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Fri, 21 Nov 2014 18:21:54 +0100 Subject: [PATCH] Add AbstractDebugger and JulDebugger there was a lot of duplicate code in ConsoleDebugger and AndroidDebugger, which resides now in AbstractDebugger. Those two and the new JulDebugger subclass AbstractDebugger. --- .../debugger/android/AndroidDebugger.java | 151 ++------------- .../smack/SmackConfiguration.java | 19 ++ .../smack/SmackInitialization.java | 17 +- .../smack/debugger/AbstractDebugger.java | 172 +++++++++++++++++ .../smack/debugger/ConsoleDebugger.java | 177 +----------------- .../smack/debugger/JulDebugger.java | 49 +++++ .../debugger/ReflectionDebuggerFactory.java | 5 + 7 files changed, 268 insertions(+), 322 deletions(-) create mode 100644 smack-core/src/main/java/org/jivesoftware/smack/debugger/AbstractDebugger.java create mode 100644 smack-core/src/main/java/org/jivesoftware/smack/debugger/JulDebugger.java 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 5c5aa9b3c..d164c943d 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,16 +16,8 @@ */ package org.jivesoftware.smackx.debugger.android; -import org.jivesoftware.smack.debugger.SmackDebugger; -import org.jivesoftware.smack.AbstractConnectionListener; -import org.jivesoftware.smack.ConnectionListener; -import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.debugger.AbstractDebugger; import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.packet.Packet; -import org.jivesoftware.smack.util.ObservableReader; -import org.jivesoftware.smack.util.ObservableWriter; -import org.jivesoftware.smack.util.ReaderListener; -import org.jivesoftware.smack.util.WriterListener; import android.util.Log; @@ -33,145 +25,24 @@ import java.io.Reader; import java.io.Writer; /** - * Very simple debugger that prints to the android log the sent and received stanzas. Use - * this debugger with caution since printing to the console is an expensive operation that may - * even block the thread since only one thread may print at a time.

- *

+ * Very simple debugger that prints to the android log the sent and received stanzas. + *

+ * Only use this debugger if really required, Android has a good java.util.logging + * implementation, therefore {@link org.jivesoftware.smack.debugger.JulDebugger} is preferred. + *

* It is possible to not only print the raw sent and received stanzas but also the interpreted * packets by Smack. By default interpreted packets won't be printed. To enable this feature * just change the printInterpreted static variable to true. * */ -public class AndroidDebugger implements SmackDebugger { - - public static boolean printInterpreted = false; - - private XMPPConnection connection = null; - - private PacketListener listener = null; - private ConnectionListener connListener = null; - - private Writer writer; - private Reader reader; - private ReaderListener readerListener; - private WriterListener writerListener; +public class AndroidDebugger extends AbstractDebugger { public AndroidDebugger(XMPPConnection connection, Writer writer, Reader reader) { - this.connection = connection; - this.writer = writer; - this.reader = reader; - createDebug(); + super(connection, writer, reader); } - /** - * Creates the listeners that will print in the console when new activity is detected. - */ - private void createDebug() { - // Create a special Reader that wraps the main Reader and logs data to the GUI. - ObservableReader debugReader = new ObservableReader(reader); - readerListener = new ReaderListener() { - public void read(String str) { - Log.d("SMACK", "RCV (" + connection.getConnectionCounter() + - "): " + str); - } - }; - debugReader.addReaderListener(readerListener); - - // Create a special Writer that wraps the main Writer and logs data to the GUI. - ObservableWriter debugWriter = new ObservableWriter(writer); - writerListener = new WriterListener() { - public void write(String str) { - Log.d("SMACK", "SENT (" + connection.getConnectionCounter() + - "): " + str); - } - }; - debugWriter.addWriterListener(writerListener); - - // Assign the reader/writer objects to use the debug versions. The packet reader - // 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 PacketListener() { - public void processPacket(Packet packet) { - if (printInterpreted) { - Log.d("SMACK", "RCV PKT (" + connection.getConnectionCounter() + - "): " + packet.toXML()); - } - } - }; - - connListener = new AbstractConnectionListener() { - public void connectionClosed() { - Log.d("SMACK", "Connection closed (" + connection.getConnectionCounter() + ")"); - } - - public void connectionClosedOnError(Exception e) { - Log.d("SMACK", "Connection closed due to an exception (" + - connection.getConnectionCounter() + ")"); - } - public void reconnectionFailed(Exception e) { - Log.d("SMACK", "Reconnection failed due to an exception (" + - connection.getConnectionCounter() + ")"); - } - public void reconnectionSuccessful() { - Log.d("SMACK", "Connection reconnected (" + - connection.getConnectionCounter() + ")"); - } - public void reconnectingIn(int seconds) { - Log.d("SMACK", "Connection (" + connection.getConnectionCounter() + - ") will reconnect in " + seconds); - } - }; - } - - public Reader newConnectionReader(Reader newReader) { - ((ObservableReader)reader).removeReaderListener(readerListener); - ObservableReader debugReader = new ObservableReader(newReader); - debugReader.addReaderListener(readerListener); - reader = debugReader; - return reader; - } - - public Writer newConnectionWriter(Writer newWriter) { - ((ObservableWriter)writer).removeWriterListener(writerListener); - ObservableWriter debugWriter = new ObservableWriter(newWriter); - debugWriter.addWriterListener(writerListener); - writer = debugWriter; - return writer; - } - - public void userHasLogged(String user) { - String title = - "User logged (" + connection.getConnectionCounter() + "): " - + user - + "@" - + connection.getServiceName() - + ":" - + connection.getPort(); - Log.d("SMACK", title); - // Add the connection listener to the connection so that the debugger can be notified - // whenever the connection is closed. - connection.addConnectionListener(connListener); - } - - public Reader getReader() { - return reader; - } - - public Writer getWriter() { - return writer; - } - - public PacketListener getReaderListener() { - return listener; - } - - public PacketListener getWriterListener() { - return null; + @Override + protected void log(String logMessage) { + Log.d("SMACK", logMessage); } } - 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 37e4b9b5f..7cfb2e963 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackConfiguration.java @@ -296,6 +296,25 @@ public final class SmackConfiguration { disabledSmackClasses.add(className); } + public static boolean isDisabledSmackClass(String className) { + for (String disabledClassOrPackage : disabledSmackClasses) { + if (disabledClassOrPackage.equals(className)) { + return true; + } + int lastDotIndex = disabledClassOrPackage.lastIndexOf('.'); + // Security check to avoid NPEs if someone entered 'foo.bar.' + if (disabledClassOrPackage.length() > lastDotIndex + // disabledClassOrPackage is not an Class + && !Character.isUpperCase(disabledClassOrPackage.charAt(lastDotIndex + 1)) + // classToLoad startsWith the package disabledClassOrPackage disables + && className.startsWith(disabledClassOrPackage)) { + // Skip the class because the whole package was disabled + return true; + } + } + return false; + } + /** * Check if Smack was successfully initialized. * diff --git a/smack-core/src/main/java/org/jivesoftware/smack/SmackInitialization.java b/smack-core/src/main/java/org/jivesoftware/smack/SmackInitialization.java index d047edda5..b2b065612 100644 --- a/smack-core/src/main/java/org/jivesoftware/smack/SmackInitialization.java +++ b/smack-core/src/main/java/org/jivesoftware/smack/SmackInitialization.java @@ -188,21 +188,8 @@ public final class SmackInitialization { name = parser.getName(); if (eventType == XmlPullParser.START_TAG && "className".equals(name)) { String classToLoad = parser.nextText(); - for (String disabledClassOrPackage : SmackConfiguration.disabledSmackClasses) { - if (disabledClassOrPackage.equals(classToLoad)) { - // Skip disabled class - continue outerloop; - } - int lastDotIndex = disabledClassOrPackage.lastIndexOf('.'); - // Security check to avoid NPEs if someone entered 'foo.bar.' - if (disabledClassOrPackage.length() > lastDotIndex - // disabledClassOrPackage is not an Class - && !Character.isUpperCase(disabledClassOrPackage.charAt(lastDotIndex + 1)) - // classToLoad startsWith the package disabledClassOrPackage disables - && classToLoad.startsWith(disabledClassOrPackage)) { - // Skip the class because the whole package was disabled - continue outerloop; - } + if (SmackConfiguration.isDisabledSmackClass(classToLoad)) { + continue outerloop; } try { 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 new file mode 100644 index 000000000..16bd0f42e --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/debugger/AbstractDebugger.java @@ -0,0 +1,172 @@ +/** + * + * Copyright the original author or authors + * + * 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.debugger; + +import org.jivesoftware.smack.ConnectionListener; +import org.jivesoftware.smack.PacketListener; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.packet.Packet; +import org.jivesoftware.smack.util.ObservableReader; +import org.jivesoftware.smack.util.ObservableWriter; +import org.jivesoftware.smack.util.ReaderListener; +import org.jivesoftware.smack.util.WriterListener; +import org.jxmpp.util.XmppStringUtils; + +import java.io.Reader; +import java.io.Writer; + +public abstract class AbstractDebugger implements SmackDebugger { + + public static boolean printInterpreted = false; + + private final XMPPConnection connection; + + private final PacketListener listener; + private final ConnectionListener connListener; + private final ReaderListener readerListener; + private final WriterListener writerListener; + + private ObservableWriter writer; + private ObservableReader reader; + + public AbstractDebugger(final XMPPConnection connection, Writer writer, Reader reader) { + this.connection = connection; + + // Create a special Reader that wraps the main Reader and logs data to the GUI. + this.reader = new ObservableReader(reader); + readerListener = new ReaderListener() { + public void read(String str) { + log("RECV (" + connection.getConnectionCounter() + "): " + str); + } + }; + this.reader.addReaderListener(readerListener); + + // Create a special Writer that wraps the main Writer and logs data to the GUI. + this.writer = new ObservableWriter(writer); + writerListener = new WriterListener() { + public void write(String str) { + log("SENT (" + connection.getConnectionCounter() + "): " + str); + } + }; + 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 PacketListener() { + public void processPacket(Packet packet) { + if (printInterpreted) { + log("RCV PKT (" + connection.getConnectionCounter() + "): " + packet.toXML()); + } + } + }; + + connListener = new ConnectionListener() { + public void connected(XMPPConnection connection) { + log("XMPPConnection connected (" + + connection.getConnectionCounter() + ")"); + } + public void authenticated(XMPPConnection connection) { + log("XMPPConnection authenticated (" + connection.getConnectionCounter() + ")"); + } + public void connectionClosed() { + log( + "XMPPConnection closed (" + + connection.getConnectionCounter() + + ")"); + } + + public void connectionClosedOnError(Exception e) { + log( + "XMPPConnection closed due to an exception (" + + connection.getConnectionCounter() + + ")"); + e.printStackTrace(); + } + public void reconnectionFailed(Exception e) { + log( + "Reconnection failed due to an exception (" + + connection.getConnectionCounter() + + ")"); + e.printStackTrace(); + } + public void reconnectionSuccessful() { + log( + "XMPPConnection reconnected (" + + connection.getConnectionCounter() + + ")"); + } + public void reconnectingIn(int seconds) { + log( + "XMPPConnection (" + + connection.getConnectionCounter() + + ") will reconnect in " + seconds); + } + }; + } + + protected abstract void log(String logMessage); + + public Reader newConnectionReader(Reader newReader) { + reader.removeReaderListener(readerListener); + ObservableReader debugReader = new ObservableReader(newReader); + debugReader.addReaderListener(readerListener); + reader = debugReader; + return reader; + } + + public Writer newConnectionWriter(Writer newWriter) { + writer.removeWriterListener(writerListener); + ObservableWriter debugWriter = new ObservableWriter(newWriter); + debugWriter.addWriterListener(writerListener); + writer = debugWriter; + return writer; + } + + public void userHasLogged(String user) { + String localpart = XmppStringUtils.parseLocalpart(user); + boolean isAnonymous = "".equals(localpart); + String title = + "User logged (" + connection.getConnectionCounter() + "): " + + (isAnonymous ? "" : localpart) + + "@" + + connection.getServiceName() + + ":" + + connection.getPort(); + title += "/" + XmppStringUtils.parseResource(user); + log(title); + // Add the connection listener to the connection so that the debugger can be notified + // whenever the connection is closed. + connection.addConnectionListener(connListener); + } + + public Reader getReader() { + return reader; + } + + public Writer getWriter() { + return writer; + } + + public PacketListener getReaderListener() { + return listener; + } + + public PacketListener 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 79cfe5240..871a2b454 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 @@ -16,15 +16,7 @@ */ package org.jivesoftware.smack.debugger; -import org.jivesoftware.smack.ConnectionListener; -import org.jivesoftware.smack.PacketListener; import org.jivesoftware.smack.XMPPConnection; -import org.jivesoftware.smack.packet.Packet; -import org.jivesoftware.smack.util.ObservableReader; -import org.jivesoftware.smack.util.ObservableWriter; -import org.jivesoftware.smack.util.ReaderListener; -import org.jivesoftware.smack.util.WriterListener; -import org.jxmpp.util.XmppStringUtils; import java.io.Reader; import java.io.Writer; @@ -42,169 +34,20 @@ import java.util.Date; * * @author Gaston Dombiak */ -public class ConsoleDebugger implements SmackDebugger { - - public static boolean printInterpreted = false; - private SimpleDateFormat dateFormatter = new SimpleDateFormat("hh:mm:ss aaa"); - - private XMPPConnection connection = null; - - private PacketListener listener = null; - private ConnectionListener connListener = null; - - private Writer writer; - private Reader reader; - private ReaderListener readerListener; - private WriterListener writerListener; +public class ConsoleDebugger extends AbstractDebugger { + private final SimpleDateFormat dateFormatter = new SimpleDateFormat("hh:mm:ss aaa"); public ConsoleDebugger(XMPPConnection connection, Writer writer, Reader reader) { - this.connection = connection; - this.writer = writer; - this.reader = reader; - createDebug(); + super(connection, writer, reader); } - /** - * Creates the listeners that will print in the console when new activity is detected. - */ - private void createDebug() { - // Create a special Reader that wraps the main Reader and logs data to the GUI. - ObservableReader debugReader = new ObservableReader(reader); - readerListener = new ReaderListener() { - public void read(String str) { - System.out.println( - dateFormatter.format(new Date()) + " RCV (" + connection.hashCode() + - "): " + - str); - } - }; - debugReader.addReaderListener(readerListener); - - // Create a special Writer that wraps the main Writer and logs data to the GUI. - ObservableWriter debugWriter = new ObservableWriter(writer); - writerListener = new WriterListener() { - public void write(String str) { - System.out.println( - dateFormatter.format(new Date()) + " SENT (" + connection.hashCode() + - "): " + - str); - } - }; - debugWriter.addWriterListener(writerListener); - - // Assign the reader/writer objects to use the debug versions. The packet reader - // 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 PacketListener() { - public void processPacket(Packet packet) { - if (printInterpreted) { - System.out.println( - dateFormatter.format(new Date()) + " RCV PKT (" + - connection.hashCode() + - "): " + - packet.toXML()); - } - } - }; - - connListener = new ConnectionListener() { - public void connected(XMPPConnection connection) { - System.out.println(dateFormatter.format(new Date()) + " XMPPConnection connected (" - + connection.hashCode() + ")"); - } - public void authenticated(XMPPConnection connection) { - System.out.println(dateFormatter.format(new Date()) - + " XMPPConnection authenticated (" + connection.hashCode() + ")"); - } - public void connectionClosed() { - System.out.println( - dateFormatter.format(new Date()) + " XMPPConnection closed (" + - connection.hashCode() + - ")"); - } - - public void connectionClosedOnError(Exception e) { - System.out.println( - dateFormatter.format(new Date()) + - " XMPPConnection closed due to an exception (" + - connection.hashCode() + - ")"); - e.printStackTrace(); - } - public void reconnectionFailed(Exception e) { - System.out.println( - dateFormatter.format(new Date()) + - " Reconnection failed due to an exception (" + - connection.hashCode() + - ")"); - e.printStackTrace(); - } - public void reconnectionSuccessful() { - System.out.println( - dateFormatter.format(new Date()) + " XMPPConnection reconnected (" + - connection.hashCode() + - ")"); - } - public void reconnectingIn(int seconds) { - System.out.println( - dateFormatter.format(new Date()) + " XMPPConnection (" + - connection.hashCode() + - ") will reconnect in " + seconds); - } - }; + @Override + protected void log(String logMessage) { + String formatedDate; + synchronized (dateFormatter) { + formatedDate = dateFormatter.format(new Date()); + } + System.out.println(formatedDate + ' ' + logMessage); } - public Reader newConnectionReader(Reader newReader) { - ((ObservableReader)reader).removeReaderListener(readerListener); - ObservableReader debugReader = new ObservableReader(newReader); - debugReader.addReaderListener(readerListener); - reader = debugReader; - return reader; - } - - public Writer newConnectionWriter(Writer newWriter) { - ((ObservableWriter)writer).removeWriterListener(writerListener); - ObservableWriter debugWriter = new ObservableWriter(newWriter); - debugWriter.addWriterListener(writerListener); - writer = debugWriter; - return writer; - } - - public void userHasLogged(String user) { - String localpart = XmppStringUtils.parseLocalpart(user); - boolean isAnonymous = "".equals(localpart); - String title = - "User logged (" + connection.hashCode() + "): " - + (isAnonymous ? "" : localpart) - + "@" - + connection.getServiceName() - + ":" - + connection.getPort(); - title += "/" + XmppStringUtils.parseResource(user); - System.out.println(title); - // Add the connection listener to the connection so that the debugger can be notified - // whenever the connection is closed. - connection.addConnectionListener(connListener); - } - - public Reader getReader() { - return reader; - } - - public Writer getWriter() { - return writer; - } - - public PacketListener getReaderListener() { - return listener; - } - - public PacketListener getWriterListener() { - return null; - } } 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 new file mode 100644 index 000000000..defc1d4a9 --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/debugger/JulDebugger.java @@ -0,0 +1,49 @@ +/** + * + * Copyright 2014 Florian Schmaus + * + * 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.debugger; + +import org.jivesoftware.smack.XMPPConnection; + +import java.io.Reader; +import java.io.Writer; +import java.util.logging.Logger; + +/** + * Very simple debugger that prints to the console (stdout) the sent and received stanzas. Use + * this debugger with caution since printing to the console is an expensive operation that may + * even block the thread since only one thread may print at a time.

+ *

+ * It is possible to not only print the raw sent and received stanzas but also the interpreted + * packets by Smack. By default interpreted packets won't be printed. To enable this feature + * just change the printInterpreted static variable to true. + * + * @author Gaston Dombiak + */ +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); + } + + @Override + protected void log(String logMessage) { + LOGGER.fine(logMessage); + } + +} 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 4244aa0f3..2c4c72c7e 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 @@ -18,6 +18,7 @@ package org.jivesoftware.smack.debugger; +import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.XMPPConnection; import java.io.Reader; @@ -36,6 +37,7 @@ public class ReflectionDebuggerFactory implements SmackDebuggerFactory { */ private static final String[] DEFAULT_DEBUGGERS = new String[] { "org.jivesoftware.smackx.debugger.EnhancedDebugger", + "org.jivesoftware.smack.debugger.JulDebugger", "org.jivesoftware.smackx.debugger.android.AndroidDebugger", "org.jivesoftware.smack.debugger.LiteDebugger", "org.jivesoftware.smack.debugger.ConsoleDebugger" }; @@ -103,6 +105,9 @@ public class ReflectionDebuggerFactory implements SmackDebuggerFactory { @SuppressWarnings("unchecked") private static Class getOneOfDefaultDebuggerClasses() { for (String debugger : DEFAULT_DEBUGGERS) { + if (SmackConfiguration.isDisabledSmackClass(debugger)) { + continue; + } try { return (Class) Class.forName(debugger); } catch (ClassNotFoundException cnfe) {