18f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenpackage de.measite.smack;
28f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
38f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport org.jivesoftware.smack.debugger.SmackDebugger;
48f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport org.jivesoftware.smack.ConnectionListener;
58f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport org.jivesoftware.smack.PacketListener;
68f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport org.jivesoftware.smack.Connection;
78f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport org.jivesoftware.smack.packet.Packet;
88f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport org.jivesoftware.smack.util.*;
98f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
108f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport android.util.Log;
118f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
128f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport java.io.Reader;
138f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport java.io.Writer;
148f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport java.text.SimpleDateFormat;
158f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenimport java.util.Date;
168f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
178f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen/**
188f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * Very simple debugger that prints to the android log the sent and received stanzas. Use
198f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * this debugger with caution since printing to the console is an expensive operation that may
208f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * even block the thread since only one thread may print at a time.<p>
218f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * <p/>
228f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * It is possible to not only print the raw sent and received stanzas but also the interpreted
238f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * packets by Smack. By default interpreted packets won't be printed. To enable this feature
248f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * just change the <tt>printInterpreted</tt> static variable to <tt>true</tt>.
258f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen *
268f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen * @author Gaston Dombiak
278f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen */
288f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chenpublic class AndroidDebugger implements SmackDebugger {
298f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
308f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    public static boolean printInterpreted = false;
318f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    private SimpleDateFormat dateFormatter = new SimpleDateFormat("hh:mm:ss aaa");
328f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
338f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    private Connection connection = null;
348f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
358f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    private PacketListener listener = null;
368f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    private ConnectionListener connListener = null;
378f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
388f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    private Writer writer;
398f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    private Reader reader;
408f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    private ReaderListener readerListener;
418f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    private WriterListener writerListener;
428f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
438f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    public AndroidDebugger(Connection connection, Writer writer, Reader reader) {
448f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        this.connection = connection;
458f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        this.writer = writer;
468f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        this.reader = reader;
478f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        createDebug();
488f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    }
498f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
508f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    /**
518f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen     * Creates the listeners that will print in the console when new activity is detected.
528f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen     */
538f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    private void createDebug() {
548f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        // Create a special Reader that wraps the main Reader and logs data to the GUI.
558f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        ObservableReader debugReader = new ObservableReader(reader);
568f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        readerListener = new ReaderListener() {
578f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            public void read(String str) {
588f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            	Log.d("SMACK",
598f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        dateFormatter.format(new Date()) + " RCV  (" + connection.hashCode() +
608f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        "): " +
618f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        str);
628f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            }
638f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        };
648f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        debugReader.addReaderListener(readerListener);
658f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
668f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        // Create a special Writer that wraps the main Writer and logs data to the GUI.
678f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        ObservableWriter debugWriter = new ObservableWriter(writer);
688f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        writerListener = new WriterListener() {
698f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            public void write(String str) {
708f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            	Log.d("SMACK",
718f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        dateFormatter.format(new Date()) + " SENT (" + connection.hashCode() +
728f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        "): " +
738f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        str);
748f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            }
758f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        };
768f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        debugWriter.addWriterListener(writerListener);
778f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
788f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        // Assign the reader/writer objects to use the debug versions. The packet reader
798f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        // and writer will use the debug versions when they are created.
808f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        reader = debugReader;
818f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        writer = debugWriter;
828f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
838f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        // Create a thread that will listen for all incoming packets and write them to
848f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        // the GUI. This is what we call "interpreted" packet data, since it's the packet
858f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        // data as Smack sees it and not as it's coming in as raw XML.
868f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        listener = new PacketListener() {
878f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            public void processPacket(Packet packet) {
888f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                if (printInterpreted) {
898f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                	Log.d("SMACK",
908f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                            dateFormatter.format(new Date()) + " RCV PKT (" +
918f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                            connection.hashCode() +
928f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                            "): " +
938f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                            packet.toXML());
948f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                }
958f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            }
968f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        };
978f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
988f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        connListener = new ConnectionListener() {
998f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            public void connectionClosed() {
1008f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                Log.d("SMACK",
1018f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        dateFormatter.format(new Date()) + " Connection closed (" +
1028f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        connection.hashCode() +
1038f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        ")");
1048f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            }
1058f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
1068f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            public void connectionClosedOnError(Exception e) {
1078f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                Log.d("SMACK",
1088f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        dateFormatter.format(new Date()) +
1098f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        " Connection closed due to an exception (" +
1108f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        connection.hashCode() +
1118f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        ")");
1128f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                e.printStackTrace();
1138f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            }
1148f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            public void reconnectionFailed(Exception e) {
1158f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                Log.d("SMACK",
1168f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        dateFormatter.format(new Date()) +
1178f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        " Reconnection failed due to an exception (" +
1188f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        connection.hashCode() +
1198f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        ")");
1208f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                e.printStackTrace();
1218f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            }
1228f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            public void reconnectionSuccessful() {
1238f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                Log.d("SMACK",
1248f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        dateFormatter.format(new Date()) + " Connection reconnected (" +
1258f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        connection.hashCode() +
1268f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        ")");
1278f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            }
1288f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            public void reconnectingIn(int seconds) {
1298f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                Log.d("SMACK",
1308f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        dateFormatter.format(new Date()) + " Connection (" +
1318f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        connection.hashCode() +
1328f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                        ") will reconnect in " + seconds);
1338f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen            }
1348f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        };
1358f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    }
1368f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
1378f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    public Reader newConnectionReader(Reader newReader) {
1388f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        ((ObservableReader)reader).removeReaderListener(readerListener);
1398f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        ObservableReader debugReader = new ObservableReader(newReader);
1408f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        debugReader.addReaderListener(readerListener);
1418f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        reader = debugReader;
1428f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        return reader;
1438f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    }
1448f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
1458f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    public Writer newConnectionWriter(Writer newWriter) {
1468f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        ((ObservableWriter)writer).removeWriterListener(writerListener);
1478f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        ObservableWriter debugWriter = new ObservableWriter(newWriter);
1488f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        debugWriter.addWriterListener(writerListener);
1498f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        writer = debugWriter;
1508f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        return writer;
1518f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    }
1528f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
1538f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    public void userHasLogged(String user) {
1548f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        boolean isAnonymous = "".equals(StringUtils.parseName(user));
1558f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        String title =
1568f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                "User logged (" + connection.hashCode() + "): "
1578f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                + (isAnonymous ? "" : StringUtils.parseBareAddress(user))
1588f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                + "@"
1598f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                + connection.getServiceName()
1608f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                + ":"
1618f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen                + connection.getPort();
1628f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        title += "/" + StringUtils.parseResource(user);
1638f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        Log.d("SMACK", title);
1648f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        // Add the connection listener to the connection so that the debugger can be notified
1658f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        // whenever the connection is closed.
1668f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        connection.addConnectionListener(connListener);
1678f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    }
1688f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
1698f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    public Reader getReader() {
1708f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        return reader;
1718f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    }
1728f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
1738f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    public Writer getWriter() {
1748f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        return writer;
1758f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    }
1768f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
1778f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    public PacketListener getReaderListener() {
1788f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        return listener;
1798f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    }
1808f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
1818f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    public PacketListener getWriterListener() {
1828f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen        return null;
1838f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen    }
1848f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen}
1858f4ce9ea0de51fee918bffe19c434612d6bbb2d7Shuyi Chen
186