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