001/** 002 * 003 * Copyright the original author or authors 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smack.debugger; 018 019import org.jivesoftware.smack.ConnectionListener; 020import org.jivesoftware.smack.PacketListener; 021import org.jivesoftware.smack.XMPPConnection; 022import org.jivesoftware.smack.packet.Packet; 023import org.jivesoftware.smack.util.*; 024 025import java.io.Reader; 026import java.io.Writer; 027import java.text.SimpleDateFormat; 028import java.util.Date; 029 030/** 031 * Very simple debugger that prints to the console (stdout) the sent and received stanzas. Use 032 * this debugger with caution since printing to the console is an expensive operation that may 033 * even block the thread since only one thread may print at a time.<p> 034 * <p/> 035 * It is possible to not only print the raw sent and received stanzas but also the interpreted 036 * packets by Smack. By default interpreted packets won't be printed. To enable this feature 037 * just change the <tt>printInterpreted</tt> static variable to <tt>true</tt>. 038 * 039 * @author Gaston Dombiak 040 */ 041public class ConsoleDebugger implements SmackDebugger { 042 043 public static boolean printInterpreted = false; 044 private SimpleDateFormat dateFormatter = new SimpleDateFormat("hh:mm:ss aaa"); 045 046 private XMPPConnection connection = null; 047 048 private PacketListener listener = null; 049 private ConnectionListener connListener = null; 050 051 private Writer writer; 052 private Reader reader; 053 private ReaderListener readerListener; 054 private WriterListener writerListener; 055 056 public ConsoleDebugger(XMPPConnection connection, Writer writer, Reader reader) { 057 this.connection = connection; 058 this.writer = writer; 059 this.reader = reader; 060 createDebug(); 061 } 062 063 /** 064 * Creates the listeners that will print in the console when new activity is detected. 065 */ 066 private void createDebug() { 067 // Create a special Reader that wraps the main Reader and logs data to the GUI. 068 ObservableReader debugReader = new ObservableReader(reader); 069 readerListener = new ReaderListener() { 070 public void read(String str) { 071 System.out.println( 072 dateFormatter.format(new Date()) + " RCV (" + connection.hashCode() + 073 "): " + 074 str); 075 } 076 }; 077 debugReader.addReaderListener(readerListener); 078 079 // Create a special Writer that wraps the main Writer and logs data to the GUI. 080 ObservableWriter debugWriter = new ObservableWriter(writer); 081 writerListener = new WriterListener() { 082 public void write(String str) { 083 System.out.println( 084 dateFormatter.format(new Date()) + " SENT (" + connection.hashCode() + 085 "): " + 086 str); 087 } 088 }; 089 debugWriter.addWriterListener(writerListener); 090 091 // Assign the reader/writer objects to use the debug versions. The packet reader 092 // and writer will use the debug versions when they are created. 093 reader = debugReader; 094 writer = debugWriter; 095 096 // Create a thread that will listen for all incoming packets and write them to 097 // the GUI. This is what we call "interpreted" packet data, since it's the packet 098 // data as Smack sees it and not as it's coming in as raw XML. 099 listener = new PacketListener() { 100 public void processPacket(Packet packet) { 101 if (printInterpreted) { 102 System.out.println( 103 dateFormatter.format(new Date()) + " RCV PKT (" + 104 connection.hashCode() + 105 "): " + 106 packet.toXML()); 107 } 108 } 109 }; 110 111 connListener = new ConnectionListener() { 112 public void connected(XMPPConnection connection) { 113 System.out.println(dateFormatter.format(new Date()) + " XMPPConnection connected (" 114 + connection.hashCode() + ")"); 115 } 116 public void authenticated(XMPPConnection connection) { 117 System.out.println(dateFormatter.format(new Date()) 118 + " XMPPConnection authenticated (" + connection.hashCode() + ")"); 119 } 120 public void connectionClosed() { 121 System.out.println( 122 dateFormatter.format(new Date()) + " XMPPConnection closed (" + 123 connection.hashCode() + 124 ")"); 125 } 126 127 public void connectionClosedOnError(Exception e) { 128 System.out.println( 129 dateFormatter.format(new Date()) + 130 " XMPPConnection closed due to an exception (" + 131 connection.hashCode() + 132 ")"); 133 e.printStackTrace(); 134 } 135 public void reconnectionFailed(Exception e) { 136 System.out.println( 137 dateFormatter.format(new Date()) + 138 " Reconnection failed due to an exception (" + 139 connection.hashCode() + 140 ")"); 141 e.printStackTrace(); 142 } 143 public void reconnectionSuccessful() { 144 System.out.println( 145 dateFormatter.format(new Date()) + " XMPPConnection reconnected (" + 146 connection.hashCode() + 147 ")"); 148 } 149 public void reconnectingIn(int seconds) { 150 System.out.println( 151 dateFormatter.format(new Date()) + " XMPPConnection (" + 152 connection.hashCode() + 153 ") will reconnect in " + seconds); 154 } 155 }; 156 } 157 158 public Reader newConnectionReader(Reader newReader) { 159 ((ObservableReader)reader).removeReaderListener(readerListener); 160 ObservableReader debugReader = new ObservableReader(newReader); 161 debugReader.addReaderListener(readerListener); 162 reader = debugReader; 163 return reader; 164 } 165 166 public Writer newConnectionWriter(Writer newWriter) { 167 ((ObservableWriter)writer).removeWriterListener(writerListener); 168 ObservableWriter debugWriter = new ObservableWriter(newWriter); 169 debugWriter.addWriterListener(writerListener); 170 writer = debugWriter; 171 return writer; 172 } 173 174 public void userHasLogged(String user) { 175 boolean isAnonymous = "".equals(StringUtils.parseName(user)); 176 String title = 177 "User logged (" + connection.hashCode() + "): " 178 + (isAnonymous ? "" : StringUtils.parseBareAddress(user)) 179 + "@" 180 + connection.getServiceName() 181 + ":" 182 + connection.getPort(); 183 title += "/" + StringUtils.parseResource(user); 184 System.out.println(title); 185 // Add the connection listener to the connection so that the debugger can be notified 186 // whenever the connection is closed. 187 connection.addConnectionListener(connListener); 188 } 189 190 public Reader getReader() { 191 return reader; 192 } 193 194 public Writer getWriter() { 195 return writer; 196 } 197 198 public PacketListener getReaderListener() { 199 return listener; 200 } 201 202 public PacketListener getWriterListener() { 203 return null; 204 } 205}