/*
 * JBoss, Home of Professional Open Source
 * Copyright 2005, JBoss Inc., and individual contributors as indicated
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.jboss.mx.remoting.tracker;

import org.jboss.logging.Logger;

import java.util.List;
import java.io.Serializable;
import javax.management.MBeanServer;
import javax.management.MBeanServerNotification;
import javax.management.AttributeChangeNotification;
import javax.management.Notification;
import javax.management.ObjectName;
import javax.management.MBeanServerFactory;
import javax.management.NotificationFilter;
import javax.management.InstanceNotFoundException;

/**
 * MBeanTrackerFilter
 *
 * @author <a href="mailto:jhaynie@vocalocity.net">Jeff Haynie</a>
 * @version $Revision: 1.1.2.3 $
 */
public class MBeanTrackerFilter implements NotificationFilter, Serializable
{
    private static final boolean VERBOSE = Boolean.getBoolean("jboss.mx.tracker.filter.debug");
    static final long serialVersionUID = 1L;
    private static final transient Logger log = Logger.getLogger(MBeanTrackerFilter.class.getName());
    protected final String classNames[];
    protected final String serverId;
    protected final boolean wantNotifications;

    public MBeanTrackerFilter (String serverId, String cn[], boolean wantNotifications)
    {
        this.serverId = serverId;
        this.classNames = cn;
        this.wantNotifications = wantNotifications;
    }

    public boolean isNotificationEnabled (Notification notification)
    {
        if (VERBOSE && log.isDebugEnabled()) log.debug("isNotificationEnabled for: "+notification+", serverId="+serverId+",wantNotifications="+wantNotifications);
        if (notification instanceof MBeanServerNotification)
        {
            MBeanServerNotification n=(MBeanServerNotification)notification;
            ObjectName mbean=n.getMBeanName();
            // find the server using the server id
            List list=MBeanServerFactory.findMBeanServer(serverId);
            if (list.isEmpty()==false)
            {
                MBeanServer server=(MBeanServer)list.get(0);
                if (notification.getType().equals(MBeanServerNotification.REGISTRATION_NOTIFICATION))
                {
                    if (classNames==null)
                    {
                        return true;
                    }
                    for (int c=0;c<classNames.length;c++)
                    {
                        try
                        {
                            if(server.isInstanceOf(mbean,classNames[c]))
                            {
                                // add an interest, since we can't call this same method later when
                                // the mbean is unregistered
                                return true;
                            }
                        }
                        catch (InstanceNotFoundException inf)
                        {
                            if (log.isDebugEnabled()) log.debug("applying filter for tracker and the instance wasn't found for notification: "+mbean);
                            return false;
                        }
                        catch (Exception ex)
                        {
                            if (log.isDebugEnabled()) log.debug("Error caught checking the instanceof the notification source for: "+notification,ex);
                        }
                    }
                }
                else if (notification.getType().equals(MBeanServerNotification.UNREGISTRATION_NOTIFICATION))
                {
                    // this is bad, but don't know of a better strategy but to attempt to cache the reg notices - but
                    // that's not very reliant - so, for now, we just allow all unreg notifications to come
                    // back - problem is that isInstanceOf only works while the mbean is registered  - JGH
                    return false==mbean.getDomain().equals("JMImplementation");
                }
            }

        }
        else if (notification instanceof AttributeChangeNotification)
        {
            // we want state changes directly
            AttributeChangeNotification ch=(AttributeChangeNotification)notification;
            if(ch.getAttributeName().equals("State") &&
              (ch.getAttributeType().equals(Integer.TYPE.getName())||ch.getAttributeType().equals(Integer.class.getName())))
            {
                return true;
            }
        }
        if (wantNotifications)
        {
            if (classNames==null)
            {
                return true;
            }
            Object src=notification.getSource();
            if (src instanceof ObjectName)
            {
                ObjectName obj=(ObjectName)src;
                // find the server using the server id
                List list=MBeanServerFactory.findMBeanServer(serverId);
//                log.debug("list of servers=="+list);
                if (list.isEmpty()==false)
                {
                    MBeanServer server=(MBeanServer)list.get(0);
                    for (int c=0;c<classNames.length;c++)
                    {
                        try
                        {
                            if(server.isInstanceOf(obj,classNames[c]))
                            {
                                // add an interest, since we can't call this same method later when
                                // the mbean is unregistered
                                return true;
                            }
                        }
                        catch (InstanceNotFoundException inf)
                        {
                            if (log.isDebugEnabled()) log.debug("applying filter for tracker and the instance wasn't found for notification: "+obj);
                            return false;
                        }
                        catch (Exception ex)
                        {
                            if (log.isDebugEnabled()) log.debug("Error caught checking the instanceof the notification source for: "+notification,ex);
                        }
                    }
                }
                else
                {
                    if (log.isDebugEnabled()) log.debug("Couldn't find the mbean server for id: "+serverId+", MBeanServerFactory returned:"+list);
                }
            }
            else
            {
                log.warn("notification: "+notification+" has a source that's not of type ObjectName - this notification will be rejected by the MBeanTracker");
            }
        }
        return false;
    }

}

