All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jppf.management.forwarding.ForwardingNotificationDispatcher Maven / Gradle / Ivy

The newest version!
/*
 * JPPF.
 * Copyright (C) 2005-2019 JPPF Team.
 * http://www.jppf.org
 *
 * 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.jppf.management.forwarding;

import java.util.*;
import java.util.concurrent.locks.*;

import javax.management.*;

import org.jppf.management.JMXNodeConnectionWrapper;
import org.jppf.server.nio.nodeserver.*;
import org.jppf.utils.*;
import org.slf4j.*;

/**
 * Instances of this class receive notifications from a single node and for any number of MBeans in that node,
 * and dispatch them to client notification listeners that registered.
 * 

The dispatch is performed via an event listener mechanism: for each notification rreceived from the node, * an event will be emitted and the listener(s) are in charge of forwarding the notifications. * @author Laurent Cohen * @exclude */ class ForwardingNotificationDispatcher { /** * Logger for this class. */ private static final Logger log = LoggerFactory.getLogger(ForwardingNotificationDispatcher.class); /** * Determines whether debug log statements are enabled. */ private static boolean debugEnabled = LoggingUtils.isDebugEnabled(log); /** * Constant for an empty array of event listeners. */ private static final ForwardingNotificationEventListener[] EMPTY_LISTENERS = new ForwardingNotificationEventListener[0]; /** * Connection to the node. */ private final BaseNodeContext node; /** * The node uuid. */ private final String nodeUuid; /** * Mapping of MBean names to corresponding notification listeners. */ private final Map handlerMap = new HashMap<>(); /** * The list of registered event listeners. */ private final List listenerList = new ArrayList<>(); /** * A temporary array used to avoid synchronization issues between addition/removal of listeners * and firing of events. */ private ForwardingNotificationEventListener[] listenerArray = EMPTY_LISTENERS; /** * Used to synchronize access to the mapping of MBean names to notification listeners. */ private final Lock lock = new ReentrantLock(); /** * Initialize this dispatcher with the specified node uuid. * @param node connection to the node. */ public ForwardingNotificationDispatcher(final BaseNodeContext node) { this.node = node; this.nodeUuid = node.getUuid(); } /** * Add a listener to the notifications emitted by the specified MBean. * @param mBeanName the name of the MBean from which to receive notifications. * @return true if the listener was sucessfully added, false otherwise. */ public boolean addNotificationListener(final String mBeanName) { lock.lock(); try { if (handlerMap.containsKey(mBeanName)) return false; final JMXNodeConnectionWrapper jmx = node.getJmxConnection(); if (jmx != null) { final ForwardingNotificationHandler handler = new ForwardingNotificationHandler(mBeanName); try { if (debugEnabled) log.debug("mBeanName={}, handler={}", mBeanName, handler); jmx.addNotificationListener(mBeanName, handler); handlerMap.put(mBeanName, handler); return true; } catch (final Exception e) { final String format = "failed to add notification listener for node={} : exception={}"; if (debugEnabled) log.debug(format, node, ExceptionUtils.getStackTrace(e)); else log.info(format, node, ExceptionUtils.getMessage(e)); } } else { if (debugEnabled) log.debug("cannot add {} notification listener for node = {} because the jmx connection is null", mBeanName, node.getUuid()); } } finally { lock.unlock(); } return false; } /** * Add a listener to the notifications emitted by the specified MBean. * @param mBeanName the name of the MBean from which to receive notifications. * @return true if the listener was sucessfully added, false otherwise. */ public boolean removeNotificationListener(final String mBeanName) { lock.lock(); try { final ForwardingNotificationHandler handler = handlerMap.remove(mBeanName); if (handler == null) return false; final JMXNodeConnectionWrapper jmx = node.getJmxConnection(); if (jmx != null) { try { jmx.removeNotificationListener(mBeanName, handler); return true; } catch (final Exception e) { final String message = String.format("error removing notification listener for node=%s, mBeanName=%s", nodeUuid, mBeanName); if (debugEnabled) log.debug(message, e); else log.info("{} : {}", message, ExceptionUtils.getMessage(e)); } } } finally { lock.unlock(); } return false; } /** * Determine whether this dispatcher is listening to notifications from any Mbean. * @return true if any notification listener is active, false otherwise. */ public boolean hasNotificationListener() { lock.lock(); try { return !handlerMap.isEmpty(); } finally { lock.unlock(); } } /** * Add a listner to the list of listeners. * @param listener the listener to add. */ public void addForwardingNotificationEventListener(final ForwardingNotificationEventListener listener) { synchronized (listenerList) { listenerList.add(listener); listenerArray = listenerList.toArray(new ForwardingNotificationEventListener[listenerList.size()]); } } /** * Remove a listner from the list of listeners. * @param listener the listener to add. */ public void removeForwardingNotificationEventListener(final ForwardingNotificationEventListener listener) { synchronized (listenerList) { if (listenerList.remove(listener)) listenerArray = listenerList.toArray(new ForwardingNotificationEventListener[listenerList.size()]); } } /** * Fire a notification event to all registered listeners. * @param mBeanName the name of the MBean form which the notification was received. * @param notification the notification to dispatch. */ public void fireNotificationEvent(final String mBeanName, final Notification notification) { final ForwardingNotificationEvent event = new ForwardingNotificationEvent(nodeUuid, mBeanName, notification); final ForwardingNotificationEventListener[] tmp; synchronized (listenerList) { tmp = listenerArray; } for (ForwardingNotificationEventListener listener : tmp) listener.notificationReceived(event); } /** * */ private class ForwardingNotificationHandler implements NotificationListener { /** * The name of the MBean to receive notifications from. */ private final String mBeanName; /** * Initiialize this listener with the specified MBean name. * @param mBeanName the name of the MBean to receive notifications from. */ public ForwardingNotificationHandler(final String mBeanName) { this.mBeanName = mBeanName; } @Override public void handleNotification(final Notification notification, final Object handback) { try { if (debugEnabled) log.debug(String.format("received notification from node=%s, mbean=%s, notification=%s, handback=%s", nodeUuid, mBeanName, notification, handback)); fireNotificationEvent(mBeanName, notification); } catch (final Exception e) { log.error(e.getMessage(), e); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy