001/** 002 * 003 * Copyright 2014 Vyacheslav Blinov 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 */ 017 018package org.jivesoftware.smackx.debugger.slf4j; 019 020import java.io.Reader; 021import java.io.Writer; 022import java.util.concurrent.atomic.AtomicBoolean; 023 024import org.jivesoftware.smack.AbstractXMPPConnection; 025import org.jivesoftware.smack.ReconnectionManager; 026import org.jivesoftware.smack.SmackConfiguration; 027import org.jivesoftware.smack.XMPPConnection; 028import org.jivesoftware.smack.debugger.SmackDebugger; 029import org.jivesoftware.smack.packet.TopLevelStreamElement; 030import org.jivesoftware.smack.util.ObservableReader; 031import org.jivesoftware.smack.util.ObservableWriter; 032 033import org.jxmpp.jid.EntityFullJid; 034import org.slf4j.Logger; 035import org.slf4j.LoggerFactory; 036 037 038/** 039 * Implementation of SmackDebugger that writes log messages using SLF4J API. 040 * Use in conjunction with your SLF4J bindings of choice. 041 * See SLF4J manual for more details about bindings usage. 042 */ 043public class SLF4JSmackDebugger extends SmackDebugger { 044 045 private static final java.util.logging.Logger LOGGER = java.util.logging.Logger.getLogger(SLF4JSmackDebugger.class.getName()); 046 047 public static final String LOGGER_NAME = "SMACK"; 048 private static final Logger logger = LoggerFactory.getLogger(LOGGER_NAME); 049 public static final AtomicBoolean printInterpreted = new AtomicBoolean(true); 050 051 public static final String SENT_TAG = "SENT"; 052 public static final String RECEIVED_TAG = "RECV"; 053 054 private final SLF4JRawXmlListener slf4JRawXmlListener = new SLF4JRawXmlListener(logger); 055 056 private ObservableWriter writer; 057 private ObservableReader reader; 058 059 /** 060 * Makes Smack use this Debugger. 061 */ 062 public static void enable() { 063 SmackConfiguration.DEBUG = true; 064 SmackConfiguration.setDefaultSmackDebuggerFactory(SLF4JDebuggerFactory.INSTANCE); 065 } 066 067 /** 068 * Create new SLF4J Smack Debugger instance. 069 * @param connection Smack connection to debug 070 */ 071 SLF4JSmackDebugger(XMPPConnection connection) { 072 super(connection); 073 this.writer = new ObservableWriter(writer); 074 this.writer.addWriterListener(slf4JRawXmlListener); 075 this.reader = new ObservableReader(Validate.notNull(reader)); 076 this.reader.addReaderListener(slf4JRawXmlListener); 077 078 final SLF4JLoggingConnectionListener loggingConnectionListener = new SLF4JLoggingConnectionListener(connection, logger); 079 this.connection.addConnectionListener(loggingConnectionListener); 080 081 if (connection instanceof AbstractXMPPConnection) { 082 AbstractXMPPConnection abstractXmppConnection = (AbstractXMPPConnection) connection; 083 ReconnectionManager.getInstanceFor(abstractXmppConnection).addReconnectionListener(loggingConnectionListener); 084 } else { 085 LOGGER.info("The connection instance " + connection 086 + " is not an instance of AbstractXMPPConnection, thus we can not install the ReconnectionListener"); 087 } 088 } 089 090 @Override 091 public Reader newConnectionReader(Reader newReader) { 092 reader.removeReaderListener(slf4JRawXmlListener); 093 reader = new ObservableReader(newReader); 094 reader.addReaderListener(slf4JRawXmlListener); 095 return reader; 096 } 097 098 @Override 099 public Writer newConnectionWriter(Writer newWriter) { 100 writer.removeWriterListener(slf4JRawXmlListener); 101 writer = new ObservableWriter(newWriter); 102 writer.addWriterListener(slf4JRawXmlListener); 103 return writer; 104 } 105 106 @Override 107 public void userHasLogged(EntityFullJid user) { 108 if (logger.isDebugEnabled()) { 109 logger.debug("({}) User logged in {}", connection.hashCode(), user.toString()); 110 } 111 } 112 113 @Override 114 public void onIncomingStreamElement(TopLevelStreamElement streamElement) { 115 if (SLF4JSmackDebugger.printInterpreted.get() && logger.isDebugEnabled()) { 116 logger.debug("IN {}: {}", streamElement.getClass().getName(), streamElement.toXML(null)); 117 } 118 } 119 120 @Override 121 public void onOutgoingStreamElement(TopLevelStreamElement streamElement) { 122 if (SLF4JSmackDebugger.printInterpreted.get() && logger.isDebugEnabled()) { 123 logger.debug("OUT {}: {}", streamElement.getClass().getName(), streamElement.toXML(null)); 124 } 125 } 126 127}