Package org.cipango.callflow

Source Code of org.cipango.callflow.JmxMessageLog$ListenerInfo

// ========================================================================
// 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;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.NoSuchElementException;

import javax.management.ListenerNotFoundException;
import javax.management.MBeanNotificationInfo;
import javax.management.Notification;
import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;

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.server.SipConnection;
import org.cipango.server.SipMessage;
import org.cipango.server.log.AbstractMessageLog;
import org.eclipse.jetty.util.log.Log;

public class JmxMessageLog extends AbstractMessageLog implements NotificationEmitter
{
  private static final int DEFAULT_MAX_MESSAGES = 100;
 
  private MessageInfo[] _messages;
  private int _maxMessages = DEFAULT_MAX_MESSAGES;
  private int _cursor;
  private long _messageId = 0;
 
  private Map<String, String> _alias = new HashMap<String, String>();
 
  private List<ListenerInfo> _listeners = new ArrayList<JmxMessageLog.ListenerInfo>();
 
  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 doLog(SipMessage message, int direction, SipConnection connection)
  {
    if (_messages != null)
    {
      // Log only once message to loopback
      if (direction == OUT
          && connection.getLocalAddress().equals(connection.getRemoteAddress())
          && connection.getLocalPort() == connection.getRemotePort())
        return;
       
      MessageInfo messageInfo = new MessageInfo(message, direction, connection);
      synchronized (this)
      {
        _messages[_cursor] = messageInfo;
        _cursor = getNextCursor();
        _messageId++;
      }
      if (!_listeners.isEmpty())
      {
        String infoLine;
        synchronized (this)
        {
          infoLine = generateInfoLine(direction, connection, System.currentTimeMillis());
        }
        CallflowNotification notification = new CallflowNotification(messageInfo, _messageId, infoLine);
        sendNotification(notification);
      }
    }
  }
   
  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()][3];
    for (int i = 0; i < tab.length; i++)
    {
      MessageInfo info = (MessageInfo) messages.get(i);
      tab[i][0] = generateInfoLine(info.getDirection(), info.getConnection(), info.getDate());
      tab[i][1] = info.getMessage();
      tab[i][2] = info.getRemote();
    }
   
    return tab;
  }
 
  @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 byte[] generateGraph(Integer maxMessages, String msgFilter, String xslUri) throws Exception
  {
    return generateGraph(getMessageList(maxMessages, msgFilter), xslUri, false);
  }
 
  public byte[] generateGraph(Integer maxMessages, String msgFilter, String xslUri, Boolean includeMsg) throws Exception
  {
    return generateGraph(getMessageList(maxMessages, msgFilter), xslUri, includeMsg);
  }
 
  protected byte[] generateGraph(List<MessageInfo> messages, String xslUri, boolean includeMsg) throws IOException
  {
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    OutputStreamWriter out = new OutputStreamWriter(os);
    out.write("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
    if (xslUri != null)
      out.write("<?xml-stylesheet href=\"" + xslUri + "\" type=\"text/xsl\"?>\n");
    out.write("<data>\n");
    out.write("\t<hosts>\n");
    Map<String, Integer> hostsMap = new HashMap<String, Integer>();
    Iterator<MessageInfo> it = messages.iterator();
    int indexLocal = -1;
    int index = 1;
    while (it.hasNext())
    {
      MessageInfo info = it.next();
      if (!hostsMap.containsKey(info.getLocalKey()))
      {
        if (indexLocal == -1)
        {
          out.write("\t\t<host>");
          String alias = _alias.get(info.getLocalKey());
          out.write(alias == null ? "Cipango" : alias);
          out.write("</host>\n");
          indexLocal = index++;
        }
        hostsMap.put(info.getLocalKey(), indexLocal);
      }

      if (!hostsMap.containsKey(info.getRemoteKey()))
      {
        out.write("\t\t<host>");
        String alias = _alias.get(info.getRemoteKey());
        out.write(alias == null ? info.getRemote() : alias);
        out.write("</host>\n");
        hostsMap.put(info.getRemoteKey(), index++);
      }
    }
    out.write("\t</hosts>\n");
   
    it = messages.iterator();
    out.write("\t<messages>\n");
    while (it.hasNext())
    {
      MessageInfo info = it.next();
      out.write("\t\t<message from=\"");
      if (info.getDirection() == IN)
      {
        out.write(String.valueOf(hostsMap.get(info.getRemoteKey())));
        out.write("\" to=\"");
        out.write(String.valueOf(hostsMap.get(info.getLocalKey())));
        out.write("\">\n");
      }
      else
      {
        out.write(String.valueOf(hostsMap.get(info.getLocalKey())));
        out.write("\" to=\"");
        out.write(String.valueOf(hostsMap.get(info.getRemoteKey())));
        out.write("\">\n");
      }
      out.write("\t\t\t<name>");
      out.write(info.getShortName());
      out.write("</name>\n");
      out.write("\t\t\t<date>");
      out.write(info.getFormatedDate());
      out.write("</date>\n");
      if (includeMsg)
      {
        StringBuilder sb = new StringBuilder(info.getMessage().toString());
        replaceAll(sb, "<", "&lt;");
        replaceAll(sb, ">", "&gt;");
        String msg = sb.toString();
        int nbLines = 1;
        for (int i = 0; i < msg.length(); i++)
          if (msg.charAt(i) == '\n')
            nbLines++;
        out.write("\t\t\t<content nbLines=\"" + nbLines + "\">");
        out.write(msg);
        out.write("</content>\n");
      }
      out.write("\t\t</message>\n");
    }
    out.write("\t</messages>\n");
    out.write("</data>\n");
    out.flush();
    return os.toByteArray();
  }
 
  protected void replaceAll(StringBuilder sb, String toFind, Object toSet)
  {
    int index = 0;
    while ((index = sb.indexOf(toFind)) != -1)
      sb.replace(index, index + toFind.length(), toSet.toString());
  }
 
  public void addAlias(String host, int port, String name) throws UnknownHostException
  {
    InetAddress addr = InetAddress.getByName(host);
    _alias.put(addr.getHostAddress() + ":" + port, name);
  }
     
  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");
    }
  }

  public void addNotificationListener(NotificationListener listener, NotificationFilter filter,
      Object handback) throws IllegalArgumentException
  {
    synchronized (_listeners)
    {
      _listeners.add(new ListenerInfo(listener, filter, handback));
    }
  }

  public void removeNotificationListener(NotificationListener listener) throws ListenerNotFoundException
  {
    synchronized (_listeners)
    {
      Iterator<ListenerInfo> it = _listeners.iterator();
      while (it.hasNext())
      {
        JmxMessageLog.ListenerInfo info = it.next();
        if (info.listener.equals(listener))
        {
          it.remove();
          return;
        }
      }
    }
    throw new ListenerNotFoundException();
  }
 
  public void removeNotificationListener(NotificationListener listener, NotificationFilter filter,
      Object handback) throws ListenerNotFoundException
  {
    synchronized (_listeners)
    {
      Iterator<ListenerInfo> it = _listeners.iterator();
      while (it.hasNext())
      {
        JmxMessageLog.ListenerInfo info = it.next();
        if (info.listener.equals(listener) && info.filter == filter && info.handback == handback)
        {
          it.remove();
          return;
        }
      }
    }
    throw new ListenerNotFoundException();
  }

  public MBeanNotificationInfo[] getNotificationInfo()
  {
    String[] types = new String[] { "SIP" };
    String name = MBeanNotificationInfo.class.getName();
    String description = "SIP message notification";
    MBeanNotificationInfo info = new MBeanNotificationInfo(types, name, description);

    return new MBeanNotificationInfo[] { info };
  }

  private void sendNotification(Notification notification)
  {
    if (notification == null || _listeners.isEmpty())
      return;
   
    synchronized (_listeners)
    {
      for (ListenerInfo info : _listeners)
      {
        if (info.filter == null || info.filter.isNotificationEnabled(notification))
        {
          try
          {
            info.listener.handleNotification(notification, info.handback);
          }
          catch (Exception e)
          {
            Log.warn(e);
          }
        }
      }
    }
  }
 
 
  private class ListenerInfo
  {
    public NotificationListener listener;
    NotificationFilter filter;
    Object handback;

    public ListenerInfo(NotificationListener listener, NotificationFilter filter, Object handback)
    {
      this.listener = listener;
      this.filter = filter;
      this.handback = handback;
    }
  }

}



TOP

Related Classes of org.cipango.callflow.JmxMessageLog$ListenerInfo

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.