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.StanzaListener; 028import org.jivesoftware.smack.XMPPConnection; 029import org.jivesoftware.smack.debugger.SmackDebugger; 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 implements 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 XMPPConnection connection; 055 056 private final StanzaListener receivedListener = new SLF4JLoggingPacketListener(logger, RECEIVED_TAG); 057 private final StanzaListener sentListener = new SLF4JLoggingPacketListener(logger, SENT_TAG); 058 private final SLF4JRawXmlListener slf4JRawXmlListener = new SLF4JRawXmlListener(logger); 059 060 private ObservableWriter writer; 061 private ObservableReader reader; 062 063 /** 064 * Makes Smack use this Debugger. 065 */ 066 public static void enable() { 067 SmackConfiguration.setDebuggerFactory(new SLF4JDebuggerFactory()); 068 } 069 070 /** 071 * Create new SLF4J Smack Debugger instance. 072 * @param connection Smack connection to debug 073 * @param writer connection data writer to observe 074 * @param reader connection data reader to observe 075 */ 076 public SLF4JSmackDebugger(XMPPConnection connection, Writer writer, Reader reader) { 077 this.connection = connection; 078 this.writer = new ObservableWriter(writer); 079 this.writer.addWriterListener(slf4JRawXmlListener); 080 this.reader = new ObservableReader(Validate.notNull(reader)); 081 this.reader.addReaderListener(slf4JRawXmlListener); 082 083 final SLF4JLoggingConnectionListener loggingConnectionListener = new SLF4JLoggingConnectionListener(connection, logger); 084 this.connection.addConnectionListener(loggingConnectionListener); 085 086 if (connection instanceof AbstractXMPPConnection) { 087 AbstractXMPPConnection abstractXmppConnection = (AbstractXMPPConnection) connection; 088 ReconnectionManager.getInstanceFor(abstractXmppConnection).addReconnectionListener(loggingConnectionListener); 089 } else { 090 LOGGER.info("The connection instance " + connection 091 + " is not an instance of AbstractXMPPConnection, thus we can not install the ReconnectionListener"); 092 } 093 } 094 095 @Override 096 public Reader newConnectionReader(Reader newReader) { 097 reader.removeReaderListener(slf4JRawXmlListener); 098 reader = new ObservableReader(newReader); 099 reader.addReaderListener(slf4JRawXmlListener); 100 return reader; 101 } 102 103 @Override 104 public Writer newConnectionWriter(Writer newWriter) { 105 writer.removeWriterListener(slf4JRawXmlListener); 106 writer = new ObservableWriter(newWriter); 107 writer.addWriterListener(slf4JRawXmlListener); 108 return writer; 109 } 110 111 @Override 112 public void userHasLogged(EntityFullJid user) { 113 if (logger.isDebugEnabled()) { 114 logger.debug("({}) User logged in {}", connection.hashCode(), user.toString()); 115 } 116 } 117 118 @Override 119 public Reader getReader() { 120 return reader; 121 } 122 123 @Override 124 public Writer getWriter() { 125 return writer; 126 } 127 128 @Override 129 public StanzaListener getReaderListener() { 130 return receivedListener; 131 } 132 133 @Override 134 public StanzaListener getWriterListener() { 135 return sentListener; 136 } 137}