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