1package de.measite.smack;
2
3import org.jivesoftware.smack.debugger.SmackDebugger;
4import org.jivesoftware.smack.ConnectionListener;
5import org.jivesoftware.smack.PacketListener;
6import org.jivesoftware.smack.Connection;
7import org.jivesoftware.smack.packet.Packet;
8import org.jivesoftware.smack.util.*;
9
10import android.util.Log;
11
12import java.io.Reader;
13import java.io.Writer;
14import java.text.SimpleDateFormat;
15import java.util.Date;
16
17/**
18 * Very simple debugger that prints to the android log the sent and received stanzas. Use
19 * this debugger with caution since printing to the console is an expensive operation that may
20 * even block the thread since only one thread may print at a time.<p>
21 * <p/>
22 * It is possible to not only print the raw sent and received stanzas but also the interpreted
23 * packets by Smack. By default interpreted packets won't be printed. To enable this feature
24 * just change the <tt>printInterpreted</tt> static variable to <tt>true</tt>.
25 *
26 * @author Gaston Dombiak
27 */
28public class AndroidDebugger implements SmackDebugger {
29
30    public static boolean printInterpreted = false;
31    private SimpleDateFormat dateFormatter = new SimpleDateFormat("hh:mm:ss aaa");
32
33    private Connection connection = null;
34
35    private PacketListener listener = null;
36    private ConnectionListener connListener = null;
37
38    private Writer writer;
39    private Reader reader;
40    private ReaderListener readerListener;
41    private WriterListener writerListener;
42
43    public AndroidDebugger(Connection connection, Writer writer, Reader reader) {
44        this.connection = connection;
45        this.writer = writer;
46        this.reader = reader;
47        createDebug();
48    }
49
50    /**
51     * Creates the listeners that will print in the console when new activity is detected.
52     */
53    private void createDebug() {
54        // Create a special Reader that wraps the main Reader and logs data to the GUI.
55        ObservableReader debugReader = new ObservableReader(reader);
56        readerListener = new ReaderListener() {
57            public void read(String str) {
58            	Log.d("SMACK",
59                        dateFormatter.format(new Date()) + " RCV  (" + connection.hashCode() +
60                        "): " +
61                        str);
62            }
63        };
64        debugReader.addReaderListener(readerListener);
65
66        // Create a special Writer that wraps the main Writer and logs data to the GUI.
67        ObservableWriter debugWriter = new ObservableWriter(writer);
68        writerListener = new WriterListener() {
69            public void write(String str) {
70            	Log.d("SMACK",
71                        dateFormatter.format(new Date()) + " SENT (" + connection.hashCode() +
72                        "): " +
73                        str);
74            }
75        };
76        debugWriter.addWriterListener(writerListener);
77
78        // Assign the reader/writer objects to use the debug versions. The packet reader
79        // and writer will use the debug versions when they are created.
80        reader = debugReader;
81        writer = debugWriter;
82
83        // Create a thread that will listen for all incoming packets and write them to
84        // the GUI. This is what we call "interpreted" packet data, since it's the packet
85        // data as Smack sees it and not as it's coming in as raw XML.
86        listener = new PacketListener() {
87            public void processPacket(Packet packet) {
88                if (printInterpreted) {
89                	Log.d("SMACK",
90                            dateFormatter.format(new Date()) + " RCV PKT (" +
91                            connection.hashCode() +
92                            "): " +
93                            packet.toXML());
94                }
95            }
96        };
97
98        connListener = new ConnectionListener() {
99            public void connectionClosed() {
100                Log.d("SMACK",
101                        dateFormatter.format(new Date()) + " Connection closed (" +
102                        connection.hashCode() +
103                        ")");
104            }
105
106            public void connectionClosedOnError(Exception e) {
107                Log.d("SMACK",
108                        dateFormatter.format(new Date()) +
109                        " Connection closed due to an exception (" +
110                        connection.hashCode() +
111                        ")");
112                e.printStackTrace();
113            }
114            public void reconnectionFailed(Exception e) {
115                Log.d("SMACK",
116                        dateFormatter.format(new Date()) +
117                        " Reconnection failed due to an exception (" +
118                        connection.hashCode() +
119                        ")");
120                e.printStackTrace();
121            }
122            public void reconnectionSuccessful() {
123                Log.d("SMACK",
124                        dateFormatter.format(new Date()) + " Connection reconnected (" +
125                        connection.hashCode() +
126                        ")");
127            }
128            public void reconnectingIn(int seconds) {
129                Log.d("SMACK",
130                        dateFormatter.format(new Date()) + " Connection (" +
131                        connection.hashCode() +
132                        ") will reconnect in " + seconds);
133            }
134        };
135    }
136
137    public Reader newConnectionReader(Reader newReader) {
138        ((ObservableReader)reader).removeReaderListener(readerListener);
139        ObservableReader debugReader = new ObservableReader(newReader);
140        debugReader.addReaderListener(readerListener);
141        reader = debugReader;
142        return reader;
143    }
144
145    public Writer newConnectionWriter(Writer newWriter) {
146        ((ObservableWriter)writer).removeWriterListener(writerListener);
147        ObservableWriter debugWriter = new ObservableWriter(newWriter);
148        debugWriter.addWriterListener(writerListener);
149        writer = debugWriter;
150        return writer;
151    }
152
153    public void userHasLogged(String user) {
154        boolean isAnonymous = "".equals(StringUtils.parseName(user));
155        String title =
156                "User logged (" + connection.hashCode() + "): "
157                + (isAnonymous ? "" : StringUtils.parseBareAddress(user))
158                + "@"
159                + connection.getServiceName()
160                + ":"
161                + connection.getPort();
162        title += "/" + StringUtils.parseResource(user);
163        Log.d("SMACK", title);
164        // Add the connection listener to the connection so that the debugger can be notified
165        // whenever the connection is closed.
166        connection.addConnectionListener(connListener);
167    }
168
169    public Reader getReader() {
170        return reader;
171    }
172
173    public Writer getWriter() {
174        return writer;
175    }
176
177    public PacketListener getReaderListener() {
178        return listener;
179    }
180
181    public PacketListener getWriterListener() {
182        return null;
183    }
184}
185
186