org.cipango.callflow.diameter.JmxMessageLogger.java Source code

Java tutorial

Introduction

Here is the source code for org.cipango.callflow.diameter.JmxMessageLogger.java

Source

// ========================================================================
// Copyright 2010 NEXCOM Systems
// ------------------------------------------------------------------------
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at 
// http://www.apache.org/licenses/LICENSE-2.0
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ========================================================================
package org.cipango.callflow.diameter;

import java.io.File;
import java.io.FileInputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
import java.util.NoSuchElementException;

import org.apache.commons.jexl.Expression;
import org.apache.commons.jexl.ExpressionFactory;
import org.apache.commons.jexl.JexlContext;
import org.apache.commons.jexl.JexlHelper;
import org.cipango.callflow.JmxMessageLog;
import org.cipango.callflow.diameter.DiameterMessageFormator.Output;
import org.cipango.diameter.Dictionary;
import org.cipango.diameter.base.Accounting;
import org.cipango.diameter.base.Common;
import org.cipango.diameter.ims.Cx;
import org.cipango.diameter.ims.IMS;
import org.cipango.diameter.ims.Sh;
import org.cipango.diameter.io.Codecs;
import org.cipango.diameter.log.DiameterMessageListener;
import org.cipango.diameter.node.DiameterConnection;
import org.cipango.diameter.node.DiameterMessage;
import org.eclipse.jetty.io.Buffer;
import org.eclipse.jetty.io.ByteArrayBuffer;
import org.eclipse.jetty.util.component.AbstractLifeCycle;
import org.eclipse.jetty.util.log.Log;
import org.eclipse.jetty.util.log.Logger;

public class JmxMessageLogger extends AbstractLifeCycle implements DiameterMessageListener {
    private static final Logger LOG = Log.getLogger(JmxMessageLog.class);

    private static final int DEFAULT_MAX_MESSAGES = 50;

    public enum Direction {
        IN, OUT
    };

    private MessageInfo[] _messages;
    private int _maxMessages = DEFAULT_MAX_MESSAGES;
    private int _cursor;

    public int getMaxMessages() {
        return _maxMessages;
    }

    public void setMaxMessages(int maxMessages) {
        if (maxMessages <= 0)
            throw new IllegalArgumentException("Max message must be greater than 0");

        synchronized (this) {
            if (isRunning() && maxMessages != _maxMessages) {
                MessageInfo[] messages = new MessageInfo[maxMessages];
                ListIterator<MessageInfo> it = iterate(false);
                int index = maxMessages;
                while (it.hasPrevious()) {
                    messages[--index] = it.previous();
                    if (index == 0)
                        break;
                }
                _cursor = 0;
                _messages = messages;
            }
            _maxMessages = maxMessages;
        }
    }

    protected void doStart() throws Exception {
        _messages = new MessageInfo[_maxMessages];
        _cursor = 0;
        super.doStart();
    }

    protected void doStop() throws Exception {
        _messages = null;
        super.doStop();
    }

    public void messageReceived(DiameterMessage message, DiameterConnection connection) {
        doLog(message, Direction.IN, connection);
    }

    public void messageSent(DiameterMessage message, DiameterConnection connection) {
        doLog(message, Direction.OUT, connection);
    }

    public void doLog(DiameterMessage message, Direction direction, DiameterConnection connection) {
        if (_messages != null) {
            synchronized (this) {
                _messages[_cursor] = new MessageInfo(message, direction, connection);
                _cursor = getNextCursor();
            }

        }
    }

    public Object[][] getMessages(Integer maxMessages) throws Exception {
        return getMessages(maxMessages, null);
    }

    private ListIterator<MessageInfo> iterate(boolean start) {
        return new LogIterator(start);
    }

    private int getNextCursor() {
        return _cursor + 1 == _maxMessages ? 0 : _cursor + 1;
    }

    public void clear() {
        if (_messages == null)
            return;

        synchronized (this) {
            for (int i = 0; i < _messages.length; i++)
                _messages[i] = null;
            _cursor = 0;
        }
    }

    public Object[][] getMessages(Integer maxMessages, String msgFilter) throws Exception {
        List<MessageInfo> messages = getMessageList(maxMessages, msgFilter);
        Object[][] tab = new Object[messages.size()][5];
        for (int i = 0; i < tab.length; i++) {
            MessageInfo info = (MessageInfo) messages.get(i);
            tab[i][0] = generateInfoLine(info);
            Output output = DiameterMessageFormator.getPretty().newOutput();
            output.add(info.getMessage());
            tab[i][1] = output.toString();
            tab[i][2] = info.getRemote();
        }

        return tab;
    }

    public String generateInfoLine(MessageInfo messageInfo) {
        StringBuilder sb = new StringBuilder();
        sb.append(messageInfo.getFormatedDate());
        if (messageInfo.getDirection() == Direction.IN)
            sb.append(" IN  ");
        else
            sb.append(" OUT ");
        sb.append(messageInfo.getConnection().getLocalAddr());
        sb.append(':');
        sb.append(messageInfo.getConnection().getLocalPort());
        sb.append((messageInfo.getDirection() == Direction.IN ? " < " : " > "));
        sb.append(messageInfo.getConnection().getRemoteAddr());
        sb.append(':');
        sb.append(messageInfo.getConnection().getRemotePort());
        sb.append('\n');
        return sb.toString();
    }

    @SuppressWarnings("unchecked")
    private List<MessageInfo> getMessageList(Integer maxMessages, String msgFilter) throws Exception {
        if (_messages == null)
            return null;

        synchronized (this) {
            JexlContext jc = JexlHelper.createContext();
            Expression msgExpression = null;
            if (msgFilter != null && !msgFilter.trim().equals("")) {
                LOG.debug("Get messages with filter: " + msgFilter);
                msgExpression = ExpressionFactory.createExpression("log." + msgFilter);
            }

            List<MessageInfo> result = new ArrayList<MessageInfo>();
            ListIterator<MessageInfo> it = iterate(false);

            int i = 0;
            while (it.hasPrevious() && i < maxMessages) {
                MessageInfo info = it.previous();
                jc.getVars().put("log", info);
                jc.getVars().put("message", info.getMessage());

                if (msgExpression == null || ((Boolean) msgExpression.evaluate(jc)).booleanValue()) {
                    result.add(0, info);
                    i++;
                }
            }
            return result;
        }
    }

    public static void main(String[] args) throws Exception {
        Dictionary.getInstance().load(Common.class);
        Dictionary.getInstance().load(Accounting.class);
        Dictionary.getInstance().load(IMS.class);
        Dictionary.getInstance().load(Cx.class);
        Dictionary.getInstance().load(Sh.class);
        JmxMessageLogger logger = new JmxMessageLogger();
        logger.start();
        DiameterMessage message = Codecs.__message.decode(load("mar.dat"));
        message.getAVPs().add(Cx.CX_APPLICATION_ID.getAVP());
        //((DiameterAnswer) message).setResultCode(Common.DIAMETER_SUCCESS);
        Output output = DiameterMessageFormator.getPretty().newOutput();
        output.add(message);
        System.out.println(output.toString());
    }

    protected static Buffer load(String name) throws Exception {
        URL url = JmxMessageLogger.class.getClassLoader().getResource(name);
        File file = new File(url.toURI());
        FileInputStream fin = new FileInputStream(file);
        byte[] b = new byte[(int) file.length()];
        fin.read(b);

        return new ByteArrayBuffer(b);
    }

    private class LogIterator implements ListIterator<MessageInfo> {
        private int _itCursor;
        private boolean _start = true;

        public LogIterator(boolean start) {
            if (start)
                _itCursor = _messages[getNextCursor()] == null ? 0 : getNextCursor();
            else
                _itCursor = _cursor;
        }

        private int getNextItCursor() {
            return _itCursor + 1 == _maxMessages ? 0 : _itCursor + 1;
        }

        private int getPreviousItCursor() {
            return _itCursor == 0 ? _maxMessages - 1 : _itCursor - 1;
        }

        public boolean hasNext() {
            return _itCursor != _cursor && _messages[getNextItCursor()] != null;
        }

        public MessageInfo next() {
            if (!hasNext())
                throw new NoSuchElementException("No next");
            _itCursor = getNextItCursor();
            return _messages[_itCursor];
        }

        public void remove() {
            throw new UnsupportedOperationException("Read-only");
        }

        public void add(MessageInfo arg0) {
            throw new UnsupportedOperationException("Read-only");
        }

        public boolean hasPrevious() {
            return (_start || _itCursor != _cursor) && _messages[getPreviousItCursor()] != null;
        }

        public int nextIndex() {
            return 0;
        }

        public MessageInfo previous() {
            if (!hasPrevious())
                throw new NoSuchElementException("No previous");
            _start = false;
            _itCursor = getPreviousItCursor();
            return _messages[_itCursor];
        }

        public int previousIndex() {
            return 0;
        }

        public void set(MessageInfo arg0) {
            throw new UnsupportedOperationException("Read-only");
        }
    }

}