Package com.sun.mfwk.agent.appserv.lifecycle

Source Code of com.sun.mfwk.agent.appserv.lifecycle.AbstractListener$HandleNotificationThread

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License. You can obtain
* a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
* or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
* Sun designates this particular file as subject to the "Classpath" exception
* as provided by Sun in the GPL Version 2 section of the License file that
* accompanied this code.  If applicable, add the following below the License
* Header, with the fields enclosed by brackets [] replaced by your own
* identifying information: "Portions Copyrighted [year]
* [name of copyright owner]"
*
* Contributor(s):
*
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

/*
* Copyright 2005-2006 Sun Microsystems, Inc.  All rights reserved.
* Use is subject to license terms.
*/
package com.sun.mfwk.agent.appserv.lifecycle;

import java.io.InputStream;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;

import javax.management.InstanceNotFoundException;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanServerConnection;
import javax.management.MBeanServerNotification;
import javax.management.Notification;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
import javax.management.ObjectName;

import com.sun.mfwk.agent.appserv.lifecycle.beans.Mapping;
import com.sun.mfwk.agent.appserv.lifecycle.beans.Notifications;
import com.sun.mfwk.agent.appserv.modeler.ObjectNameHelper;
import com.sun.mfwk.agent.appserv.util.Constants;
import com.sun.mfwk.agent.appserv.util.BundleReader;
import com.sun.mfwk.agent.appserv.util.Utils;

/**
* Class used by ListenerManagerImpl to implement its APIs. Listens to specific
* mbean on the Server as specified by its derived class..
*/
abstract class AbstractListener implements NotificationListener {

   /**
    * Constructs the AbstractListener object to listen to notifications
    * from the given server for the given client.
    *
    * @param connection the mbean server connection to listen to
    * @param client     the client for which to listen to
    * @param filter     the object to filter out unwanted notifcations
    * @param handback   the object which is sent back along to the listener
    *                   along with the notification without any modifications
    */
    AbstractListener(MBeanServerConnection connection, String asInstance,
        String asDomain, NotificationListener client,
            NotificationFilter filter, Object handback){
        this.connection = connection;
        this.client = client;
        this.filter = filter;
        this.handback = handback;
        this.asInstance = asInstance;
        this.asDomain = asDomain;
        runtimeToMonitoring = new HashMap();
    }


   /**
    * Specifies whether the given notification is of interest.
    *
    * This method is used when null is provided for NotificationFilter in the
    * <code>LifecycleManager</code> API <code>addNotificationListener</code>
    * This method uses the information from notification.xml to figure out
    * whether the given notification is of interest to us. This method does
    * the following: Compares the input notification with each of the <object-name>
    * element of notification.xml till the match is found. On match, it returns
    * <code>true</code> else it returns <code>false</code>. Input notification is
    * compared with the <object-name> element by matching each of the name/value
    * pairs of <attribute> subelement with the property/value pair in the ObjectName
    * of the object sending the notification.
    *
    * @param notification the notification recieved
    *
    * @return boolean <code>true</code> if the input notification is of interest;
    *                 else <code>false</code>
    */
    private boolean isNotificationEnabled(Notification notification){
        ObjectName objectName = getObjectName(notification);
        assert(objectName != null);
        if(objectName != null){
            try{
                //Get the in-memory representation of the notification.xml.
    Notifications notifications = getNotifications();
                if(notifications != null) {
                    //Get the domain of interest from the notification.xml
                    //Consider notifications only from this domain.
              String domain = notifications.getDomain();
        if(domain.equals(objectName.getDomain())){
            com.sun.mfwk.agent.appserv.lifecycle.beans.ObjectName name = null;

                        //Return if notification is because of cascaded object.
                        //Plugin recieves two notifications for each monitoring object on the remote
                        //instance. One, when the monitoring object gets created on the remote server
                        //and the other when it gets cascaded to the DAS. This causes a problem when
                        //we have same Application or Module deployed to DAS and remote server.
                        //Cascaded object is overwriting the object instrumented by the remote server.
                        //To avoid this, plugin should not instrument CMM objects for cascaded AS mbeans.
                        if(!asInstance.equals(objectName.getKeyProperty(Constants.SERVER_NAME_KEY))) {
                            return false;
                        }

                        //for each of the <object-name> elements from notification.xml
      for(int i=0; i<notifications.sizeObjectName(); i++){
                            name = notifications.getObjectName(i);
          com.sun.mfwk.agent.appserv.lifecycle.beans.Attribute attribute = null;
          String attributeName = null;
          String attributeValue = null;
          String value = null;
          boolean ofInterest = true;
                            //for each of the <attribute> element of <object-name>
                            //  compare the <name> and <value> elements with the key/value
                            //  pairs in input notification object name.
          for(int j=0; j<name.sizeAttribute(); j++){
              attribute = name.getAttribute(j);
        attributeName = attribute.getName();
        attributeValue = attribute.getValue();
        value = objectName.getKeyProperty(attributeName);

                                if(attributeValue != null){
                                    if(!attributeValue.equals(value)){
                                        ofInterest = false;
                                        break;
                                    }
                                } else {
                                    //checking for equality in case of null values.
                                    //attributeValue and value are equal if both are null
                                    if(value != null){
                                        ofInterest = false;
                                        break;
                                    }
                                }
                }
          if(ofInterest == true){
                                return true;
          }
           }
              }
                }
            } catch(Exception ex){
                Utils.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
        return false;
    }


   /**
    * Recieves notifications from the server.
    *
    * This method does the following if the input notification is of interest.
    * If notification type is <code>JMX.mbean.unregistered</code>, forwards
    * to the client.
    * </p>
    * If notification type is <code>JMX.mbean.registered</code>, creates new
    * thread to handles the notification.
    *
    * @param notification     the notification recieved
    * @param handback   the handback object used when we registered this listener
    */
    public void handleNotification(Notification notification, Object handback){
        if(isNotificationEnabled(notification)){
            ObjectName objectName = getObjectName(notification);
            if(objectName != null){
                if(client != null){
                    notification.setUserData(objectName);
                    client.handleNotification(notification, handback);
                }
            }
        }
    }


    /**
     * Determines whether this object represents the given inputs.
     *
     * @return boolean <code>true</code> if this object represents given inputs;
     *                 else <code>false</code>
     */
    boolean isMatch(MBeanServerConnection connection,
                NotificationListener client) {
        if((connection.equals(this.connection)) &&
            (client.equals(this.client))) {
            return true;
        }
        return false;
    }


    /**
     * Determines whether this object represents the given inputs.
     *
     * @return boolean <code>true</code> if this object represents given inputs;
     *                 else <code>false</code>
     */
    boolean isMatch(MBeanServerConnection connection,
                NotificationListener client, NotificationFilter filter,
                    Object handback) {
        if(isMatch(connection, client)) {
            if((filter.equals(this.filter)) &&
                (handback.equals(this.handback))) {
                return true;
            }
        }
        return false;
    }


    /**
     * Registers listener on the registered object specified by the derived class.
     * Registers listener for a given client with given filter & handback object.
     * If provided filter is null, then this objects registers itself as a
     * listener.
     *
     * @thows  InstanceNotFoundException
     * @throws IOException
     */
    void registerListener() throws InstanceNotFoundException, IOException {
        ObjectName objectName = getObjectName(connection);
        if(objectName != null){
                assert (connection != null): "Connection not available";
                if((connection != null) && (client != null)){
                    if(filter != null){
                        connection.addNotificationListener(objectName, client, filter, handback);
                    } else {
                        connection.addNotificationListener(objectName, this, null, handback);
                    }
                } else {
                    Utils.log(Level.INFO, "Listener not registered. Invalid arguments");
                }
        } else {
            Utils.log(Level.INFO, "Not a valid registered Object Name");
        }
    }


    /**
     * Method that unregisters the listener on given mbean for
     * a specific client if this object is the one who registered it.
     *
     * @param connection the given connection object
     * @param client the given client object
     *
     * @thows  InstanceNotFoundException
     * @throws IOException
     */
    void unregisterListener(MBeanServerConnection connection,
            NotificationListener client) throws InstanceNotFoundException,
            ListenerNotFoundException, IOException{
        ObjectName objectName = getObjectName(connection);
        if(objectName!= null){
            assert (connection != null): "Connection not available";
            connection.removeNotificationListener(objectName, client);
        } else {
            Utils.log(Level.INFO, "Not a valid registered Object Name");
        }
    }


    /**
     * Method that unregisters the listener on given mbean for
     * a specific client if this object is the one who registered it.
     *
     * @param connection the given connection object
     * @param client the given client object
     * @param filter the given filter object
     * @param handback the given handback object
     *
     * @thows  InstanceNotFoundException
     * @throws IOException
     */
    void unregisterListener(MBeanServerConnection connection,
            NotificationListener client, NotificationFilter filter, Object handback)
            throws InstanceNotFoundException, ListenerNotFoundException, IOException {
        ObjectName objectName = getObjectName(connection);
        if(objectName!= null){
            assert (connection != null): "Connection not available";
            if(filter != null) {
                connection.removeNotificationListener(objectName, client, filter, handback);
            } else {
                connection.removeNotificationListener(objectName, this, filter, handback);
            }
        } else {
            Utils.log(Level.INFO, "Not a valid registered Object Name");
        }
    }


    protected abstract String getObjectNameString();


   /**
    * Utility method to print the information of the given notification.
    */
    protected void printInfo(MBeanServerNotification notification){
        System.out.println(" Notification " + notification.toString());
        System.out.println("Sequence Number: " + notification.getSequenceNumber());
        System.out.println("Time Stamp: " + notification.getTimeStamp());
        System.out.println("MBean Name: " + notification.getMBeanName().getCanonicalName());
        System.out.println("Message: " + notification.getMessage());
        System.out.println("Source: " + notification.getSource().toString());
        System.out.println("Type: " + notification.getType());
        System.out.println("UserData: " + notification.getUserData());
    }


   /**
    * <code>Thread</code> that handles the Notification without blocking the
    * the main thread. It waits till the object sending the notification is
    * ready or times out after the specified time. It forwards the notification
    * to the client only if both the following conditions satisfies -
    *        the object sending the notification is ready
    *        corresponding monitoring mbean is registered on the registered
    * The second condition is required because the monitoring mbean may not get
    * created in case the monitoring level is off.
    */
    private final class HandleNotificationThread extends Thread
    {
        private final   long             timeOutSeconds;
        private final   int             startAfterSeconds;
        private boolean                 timeOutReached;
        private long                    startTime;
       
        private ObjectName              objectName;
        private String              monitoringObjectName;
        private MBeanServerConnection   connection;
       
        NotificationListener            client;
        Notification                    notification;
        Object                          handback;
        Integer                         status;

        public HandleNotificationThread(final long timeOutSeconds,
                final int startAfterSeconds, final ObjectName objectName,
                final String monitoringObjectName,
                final MBeanServerConnection connection,
                final NotificationListener client,
                final Notification notification, final Object handback) {
            this.timeOutSeconds     = timeOutSeconds;
            this.startAfterSeconds  = startAfterSeconds;
            this.objectName         = objectName;
            this.monitoringObjectName = monitoringObjectName;
            this.connection         = connection;
            this.timeOutReached     = false;
            this.client             = client;
            this.notification       = notification;
            this.handback           = handback;
        }


       /**
        * Waits till the one of the follwoing happens - notification object is
        * ready or specified time interval is past or notification object gets
        * into failed state. In case of ready state of notification object, this
        * methods checks if the corresponding monitoring mbean is registered or
        * not. If monitoring mbean is registered then this methods sets the
        * monitoring mbeanname as UserData in notification and forwards the
        * notification to the client.
        */
        public void run() {
            startTime = System.currentTimeMillis();
            try
            {
                Thread.currentThread().sleep(startAfterSeconds * 1000);
                while (!timeOutReached() && keepWaiting()){
                    try {
                        //sleep for 30 seconds
                        Thread.currentThread().sleep(30000);
                        computeTimeOut();
                    }
                    catch (InterruptedException ie){
                        timeOutReached = true;
                    }
                }
            }
            catch (Exception e){
                timeOutReached = true;
            }

            if((status.intValue() == RUNNING_STATE) && (client != null)){
                if(monitoringObjectName != null){
                    try{
                        ObjectName objectName = ObjectName.getInstance(monitoringObjectName);
                        if(connection != null){
                            //sleep for 30 seconds
                            Thread.currentThread().sleep(30000);
                            if (connection.isRegistered( new ObjectName( monitoringObjectName )  )){
                                notification.setUserData(new ObjectName(monitoringObjectName));
                                client.handleNotification(notification, handback);
                            }
                        }
                    }catch(Exception ex){
                        ex.printStackTrace();
                    }
                } else {
                    client.handleNotification(notification, handback);
                }
            }
        }


        private boolean timeOutReached(){
            return timeOutReached;
        }

        private void computeTimeOut(){
            long currentTime = System.currentTimeMillis();
            timeOutReached =
                ((currentTime - startTime) >= (timeOutSeconds * 1000));
        }

        private boolean keepWaiting(){
            boolean returnValue = true;
            status = null;
            if((objectName != null) && (connection != null)){
                try{
                    status = (Integer)connection.getAttribute(objectName, "state");   //NOI18N
                    if((status.intValue() == RUNNING_STATE) || (status.intValue() == FAILED_STATE)){
                        returnValue = false;
                    }
                }
                catch(Exception ex){
                    status = null;
                    returnValue = false;
                }
            }
            return returnValue;
        }
    }


   /**
    * Method that froms the objectname for the monitoring mbean from the objectname
    * of the runtime mbean and <object-name> element of <code>notification.xml</code>.
    * This method this stores runtime mbean objectname and monitoring mbean
    * objectname into the map for later use.
    *
    * @param domain the domain the monitoring mbean domain
    * @param name the in-memory representation of <object-name> element of <code>notification.xml</code>.
    * @param objectName the runtime mbean <code>ObjectName</code>
    */
    private void updateObjectNameMap(String domain,
            com.sun.mfwk.agent.appserv.lifecycle.beans.ObjectName name,
                ObjectName objectName){
        String template = name.getMonitoringMbeanNameTemplate();
        if(template != null){
            template = domain + ":" + template;                 //NOI18N

            Mapping mapping = null;
            String property = null;
            String value = null;
            Map keyValueMap = new HashMap();
            for(int i=0; i<name.sizeMapping(); i++){
                mapping = name.getMapping(i);
                value = objectName.getKeyProperty(mapping.getRuntimeMbeanAttributeName());
                property = mapping.getMonitoringMbeanAttributeValue();

                //In case of web-modules, the name key vaule of runtime mbean
                //object name is different from the one in monitoring mbean
                //object name. In runtime mbean object name, the name
                //key value is context + name. We need to account for this.
                if(value.startsWith("//")){
                    value = value.substring(value.lastIndexOf('/') + 1);
                }
                keyValueMap.put(property, value);
            }
            String monitoringMBeanObjectName;
            try{
                monitoringMBeanObjectName = ObjectNameHelper.tokenize(template, keyValueMap);
                runtimeToMonitoring.put(objectName, monitoringMBeanObjectName);
            }catch(NoSuchFieldException e){
                //do nothing
            }
        }
    }


   /**
    * Returns ObjectName of the object that sent the gvien <code>Notification</code>
    *
    * @returns ObjectName the ObjectName extracted from the given <code>notification</code> parameter
    */
    private ObjectName getObjectName(Notification notification){
        ObjectName objectName = null;
        if(notification.getClass().getName().equals("javax.management.MBeanServerNotification")){  //NOI18N
            MBeanServerNotification msn = (MBeanServerNotification)notification;
            //printInfo(msn);
            String canonicalName = msn.getMBeanName().getCanonicalName();
            try {
                objectName = new ObjectName(canonicalName);
            } catch(javax.management.MalformedObjectNameException ex){
                Utils.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
        return objectName;
    }


   /**
    * Returns the registered ObjectName for the given <code>MBeanServerConnection</code>.
    * To be specific it gets the object name from the derived class, forms the ObjectName
    * object from it and returns it if and only if, its registered object on the given
    * connection.
    *
    * @returns ObjectName the registered ObjectName on the given connection.
    */
    private ObjectName getObjectName(MBeanServerConnection connection) {
        String objectNameString = getObjectNameString();
        if((objectNameString != null) && (objectNameString.length() > 0)){
            try{
                ObjectName objectName = ObjectName.getInstance(objectNameString);
                if(connection != null){
                    if (connection.isRegistered( new ObjectName( objectNameString )  )){
                        return objectName;
                    }
                }
            }catch(Exception ex){
                Utils.log(Level.WARNING, ex.getMessage(), ex);
            }
        }
        return null;
    }


   /**
    * Returns Notifications object; in-memory representation of
    * com/sun/mfwk/agent/appserv/lifecycle/notifications.xml.
    *
    * @returns Notifications the in-memory representation of
    * com/sun/mfwk/agent/appserv/lifecycle/notifications.xml
    */
    static private Notifications getNotifications(){
        if(notifications == null){
            InputStream inputStream = Utils.getInputStream(notificationsFile);
        if(inputStream != null) {
          try
                    notifications = Notifications.read(inputStream);
    } catch(Exception e) {
                    Utils.log(Level.WARNING, e.getMessage(), e);
    }
            } else {
                String format =
                BundleReader.getValue("MSG_Unable_to_use_file");        //NOI18N
                Object[] arguments = new Object[]{notificationsFile };
                Utils.log(Level.WARNING, MessageFormat.format(format, arguments));
            }
        }
  return notifications;
    }


    private static String notificationsFile =
        "com/sun/mfwk/agent/appserv/lifecycle/dtds/notifications.xml";


    private static Notifications notifications = null;
    private MBeanServerConnection connection = null;
    private NotificationListener client = null;
    private NotificationFilter filter = null;
    private Object handback = null;
    private Map runtimeToMonitoring;
    private String asInstance = null;
    private String asDomain = null;

    public static final int STARTING_STATE = 0;
    public static final int RUNNING_STATE = 1;
    public static final int STOPPING_STATE = 2;
    public static final int STOPPED_STATE = 3;
    public static final int FAILED_STATE = 4;
}
TOP

Related Classes of com.sun.mfwk.agent.appserv.lifecycle.AbstractListener$HandleNotificationThread

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.