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