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