001/*
002 * Copyright 2002-2012 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.jmx.export.notification;
018
019import javax.management.AttributeChangeNotification;
020import javax.management.MBeanException;
021import javax.management.Notification;
022import javax.management.ObjectName;
023import javax.management.modelmbean.ModelMBean;
024import javax.management.modelmbean.ModelMBeanNotificationBroadcaster;
025
026import org.springframework.util.Assert;
027
028/**
029 * {@link NotificationPublisher} implementation that uses the infrastructure
030 * provided by the {@link ModelMBean} interface to track
031 * {@link javax.management.NotificationListener javax.management.NotificationListeners}
032 * and send {@link Notification Notifications} to those listeners.
033 *
034 * @author Rob Harrop
035 * @author Juergen Hoeller
036 * @author Rick Evans
037 * @since 2.0
038 * @see javax.management.modelmbean.ModelMBeanNotificationBroadcaster
039 * @see NotificationPublisherAware
040 */
041public class ModelMBeanNotificationPublisher implements NotificationPublisher {
042
043        /**
044         * The {@link ModelMBean} instance wrapping the managed resource into which this
045         * {@code NotificationPublisher} will be injected.
046         */
047        private final ModelMBeanNotificationBroadcaster modelMBean;
048
049        /**
050         * The {@link ObjectName} associated with the {@link ModelMBean modelMBean}.
051         */
052        private final ObjectName objectName;
053
054        /**
055         * The managed resource associated with the {@link ModelMBean modelMBean}.
056         */
057        private final Object managedResource;
058
059
060        /**
061         * Create a new instance of the {@link ModelMBeanNotificationPublisher} class
062         * that will publish all {@link javax.management.Notification Notifications}
063         * to the supplied {@link ModelMBean}.
064         * @param modelMBean the target {@link ModelMBean}; must not be {@code null}
065         * @param objectName the {@link ObjectName} of the source {@link ModelMBean}
066         * @param managedResource the managed resource exposed by the supplied {@link ModelMBean}
067         * @throws IllegalArgumentException if any of the parameters is {@code null}
068         */
069        public ModelMBeanNotificationPublisher(
070                        ModelMBeanNotificationBroadcaster modelMBean, ObjectName objectName, Object managedResource) {
071
072                Assert.notNull(modelMBean, "'modelMBean' must not be null");
073                Assert.notNull(objectName, "'objectName' must not be null");
074                Assert.notNull(managedResource, "'managedResource' must not be null");
075                this.modelMBean = modelMBean;
076                this.objectName = objectName;
077                this.managedResource = managedResource;
078        }
079
080
081        /**
082         * Send the supplied {@link Notification} using the wrapped
083         * {@link ModelMBean} instance.
084         * @param notification the {@link Notification} to be sent
085         * @throws IllegalArgumentException if the supplied {@code notification} is {@code null}
086         * @throws UnableToSendNotificationException if the supplied {@code notification} could not be sent
087         */
088        @Override
089        public void sendNotification(Notification notification) {
090                Assert.notNull(notification, "Notification must not be null");
091                replaceNotificationSourceIfNecessary(notification);
092                try {
093                        if (notification instanceof AttributeChangeNotification) {
094                                this.modelMBean.sendAttributeChangeNotification((AttributeChangeNotification) notification);
095                        }
096                        else {
097                                this.modelMBean.sendNotification(notification);
098                        }
099                }
100                catch (MBeanException ex) {
101                        throw new UnableToSendNotificationException("Unable to send notification [" + notification + "]", ex);
102                }
103        }
104
105        /**
106         * From the {@link Notification javadoc}:
107         * <p><i>"It is strongly recommended that notification senders use the object name
108         * rather than a reference to the MBean object as the source."</i>
109         * @param notification the {@link Notification} whose
110         * {@link javax.management.Notification#getSource()} might need massaging
111         */
112        private void replaceNotificationSourceIfNecessary(Notification notification) {
113                if (notification.getSource() == null || notification.getSource().equals(this.managedResource)) {
114                        notification.setSource(this.objectName);
115                }
116        }
117
118}