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 org.jivesoftware.smack.StanzaListener;
021import org.jivesoftware.smack.SmackConfiguration;
022import org.jivesoftware.smack.XMPPConnection;
023import org.jivesoftware.smack.debugger.SmackDebugger;
024import org.jivesoftware.smack.util.ObservableReader;
025import org.jivesoftware.smack.util.ObservableWriter;
026import org.jxmpp.util.XmppStringUtils;
027import org.slf4j.Logger;
028import org.slf4j.LoggerFactory;
029
030import java.io.Reader;
031import java.io.Writer;
032import java.util.concurrent.atomic.AtomicBoolean;
033
034
035/**
036 * Implementation of SmackDebugger that writes log messages using SLF4J API.
037 * Use in conjunction with your SLF4J bindings of choice.
038 * See SLF4J manual for more details about bindings usage.
039 */
040public class SLF4JSmackDebugger implements SmackDebugger  {
041    public static final String LOGGER_NAME = "SMACK";
042    private static final Logger logger = LoggerFactory.getLogger(LOGGER_NAME);
043    public static final AtomicBoolean printInterpreted = new AtomicBoolean(true);
044
045    public static final String SENT_TAG = "SENT";
046    public static final String RECEIVED_TAG = "RECV";
047
048    private final XMPPConnection connection;
049
050    private final StanzaListener receivedListener = new SLF4JLoggingPacketListener(logger, RECEIVED_TAG);
051    private final StanzaListener sentListener = new SLF4JLoggingPacketListener(logger, SENT_TAG);
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.setDebuggerFactory(new SLF4JDebuggerFactory());
062    }
063
064    /**
065     * Create new SLF4J Smack Debugger instance
066     * @param connection Smack connection to debug
067     * @param writer connection data writer to observe
068     * @param reader connection data reader to observe
069     */
070    public SLF4JSmackDebugger(XMPPConnection connection, Writer writer, Reader reader) {
071        this.connection = connection;
072        this.writer = new ObservableWriter(writer);
073        this.writer.addWriterListener(slf4JRawXmlListener);
074        this.reader = new ObservableReader(Validate.notNull(reader));
075        this.reader.addReaderListener(slf4JRawXmlListener);
076        this.connection.addConnectionListener(new SLF4JLoggingConnectionListener(connection, logger));
077    }
078
079    @Override
080    public Reader newConnectionReader(Reader newReader) {
081        reader.removeReaderListener(slf4JRawXmlListener);
082        reader = new ObservableReader(newReader);
083        reader.addReaderListener(slf4JRawXmlListener);
084        return reader;
085    }
086
087    @Override
088    public Writer newConnectionWriter(Writer newWriter) {
089        writer.removeWriterListener(slf4JRawXmlListener);
090        writer = new ObservableWriter(newWriter);
091        writer.addWriterListener(slf4JRawXmlListener);
092        return writer;
093    }
094
095    @Override
096    public void userHasLogged(String user) {
097        if (logger.isDebugEnabled()) {
098            String userTitle = getUserTitle(user);
099            logger.debug("({}) User logged in {}", connection.hashCode(), userTitle);
100        }
101    }
102
103    private String getUserTitle(String user) {
104        if (("@" + connection.getServiceName()).equals(XmppStringUtils.parseBareJid(user))) {
105            return "<Anonymous>@" + connection.getServiceName();
106        } else {
107            return user;
108        }
109    }
110
111    @Override
112    public Reader getReader() {
113        return reader;
114    }
115
116    @Override
117    public Writer getWriter() {
118        return writer;
119    }
120
121    @Override
122    public StanzaListener getReaderListener() {
123        return receivedListener;
124    }
125
126    @Override
127    public StanzaListener getWriterListener() {
128        return sentListener;
129    }
130}