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