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.StanzaListener; 021import org.jivesoftware.smack.XMPPConnection; 022import org.jivesoftware.smack.packet.Stanza; 023import org.jivesoftware.smack.util.ObservableReader; 024import org.jivesoftware.smack.util.ObservableWriter; 025import org.jivesoftware.smack.util.ReaderListener; 026import org.jivesoftware.smack.util.WriterListener; 027import org.jxmpp.util.XmppStringUtils; 028 029import java.io.Reader; 030import java.io.Writer; 031 032public abstract class AbstractDebugger implements SmackDebugger { 033 034 public static boolean printInterpreted = false; 035 036 private final XMPPConnection connection; 037 038 private final StanzaListener listener; 039 private final ConnectionListener connListener; 040 private final ReaderListener readerListener; 041 private final WriterListener writerListener; 042 043 private ObservableWriter writer; 044 private ObservableReader reader; 045 046 public AbstractDebugger(final XMPPConnection connection, Writer writer, Reader reader) { 047 this.connection = connection; 048 049 // Create a special Reader that wraps the main Reader and logs data to the GUI. 050 this.reader = new ObservableReader(reader); 051 readerListener = new ReaderListener() { 052 public void read(String str) { 053 log("RECV (" + connection.getConnectionCounter() + "): " + str); 054 } 055 }; 056 this.reader.addReaderListener(readerListener); 057 058 // Create a special Writer that wraps the main Writer and logs data to the GUI. 059 this.writer = new ObservableWriter(writer); 060 writerListener = new WriterListener() { 061 public void write(String str) { 062 log("SENT (" + connection.getConnectionCounter() + "): " + str); 063 } 064 }; 065 this.writer.addWriterListener(writerListener); 066 067 // Create a thread that will listen for all incoming packets and write them to 068 // the GUI. This is what we call "interpreted" packet data, since it's the packet 069 // data as Smack sees it and not as it's coming in as raw XML. 070 listener = new StanzaListener() { 071 public void processPacket(Stanza packet) { 072 if (printInterpreted) { 073 log("RCV PKT (" + connection.getConnectionCounter() + "): " + packet.toXML()); 074 } 075 } 076 }; 077 078 connListener = new ConnectionListener() { 079 public void connected(XMPPConnection connection) { 080 log("XMPPConnection connected (" 081 + connection.getConnectionCounter() + ")"); 082 } 083 public void authenticated(XMPPConnection connection, boolean resumed) { 084 String logString = "XMPPConnection authenticated (" + connection.getConnectionCounter() + ")"; 085 if (resumed) { 086 logString += " and resumed"; 087 } 088 log(logString); 089 } 090 public void connectionClosed() { 091 log( 092 "XMPPConnection closed (" + 093 connection.getConnectionCounter() + 094 ")"); 095 } 096 097 public void connectionClosedOnError(Exception e) { 098 log( 099 "XMPPConnection closed due to an exception (" + 100 connection.getConnectionCounter() + 101 ")"); 102 e.printStackTrace(); 103 } 104 public void reconnectionFailed(Exception e) { 105 log( 106 "Reconnection failed due to an exception (" + 107 connection.getConnectionCounter() + 108 ")"); 109 e.printStackTrace(); 110 } 111 public void reconnectionSuccessful() { 112 log( 113 "XMPPConnection reconnected (" + 114 connection.getConnectionCounter() + 115 ")"); 116 } 117 public void reconnectingIn(int seconds) { 118 log( 119 "XMPPConnection (" + 120 connection.getConnectionCounter() + 121 ") will reconnect in " + seconds); 122 } 123 }; 124 } 125 126 protected abstract void log(String logMessage); 127 128 public Reader newConnectionReader(Reader newReader) { 129 reader.removeReaderListener(readerListener); 130 ObservableReader debugReader = new ObservableReader(newReader); 131 debugReader.addReaderListener(readerListener); 132 reader = debugReader; 133 return reader; 134 } 135 136 public Writer newConnectionWriter(Writer newWriter) { 137 writer.removeWriterListener(writerListener); 138 ObservableWriter debugWriter = new ObservableWriter(newWriter); 139 debugWriter.addWriterListener(writerListener); 140 writer = debugWriter; 141 return writer; 142 } 143 144 public void userHasLogged(String user) { 145 String localpart = XmppStringUtils.parseLocalpart(user); 146 boolean isAnonymous = "".equals(localpart); 147 String title = 148 "User logged (" + connection.getConnectionCounter() + "): " 149 + (isAnonymous ? "" : localpart) 150 + "@" 151 + connection.getServiceName() 152 + ":" 153 + connection.getPort(); 154 title += "/" + XmppStringUtils.parseResource(user); 155 log(title); 156 // Add the connection listener to the connection so that the debugger can be notified 157 // whenever the connection is closed. 158 connection.addConnectionListener(connListener); 159 } 160 161 public Reader getReader() { 162 return reader; 163 } 164 165 public Writer getWriter() { 166 return writer; 167 } 168 169 public StanzaListener getReaderListener() { 170 return listener; 171 } 172 173 public StanzaListener getWriterListener() { 174 return null; 175 } 176}