package vnet.sms.gateway.nettysupport.monitor.incoming; import static org.apache.commons.lang.Validate.notNull; import java.net.SocketAddress; import java.util.concurrent.atomic.AtomicLong; import javax.management.Notification; import org.jboss.netty.channel.Channel; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.jmx.export.annotation.ManagedNotification; import org.springframework.jmx.export.annotation.ManagedNotifications; import org.springframework.jmx.export.annotation.ManagedResource; import org.springframework.jmx.export.notification.NotificationPublisher; import org.springframework.jmx.export.notification.NotificationPublisherAware; import vnet.sms.gateway.nettysupport.Jmx; /** * @author obergner * */ @ManagedResource(objectName = InitialChannelEventsMonitor.OBJECT_NAME, description = "Monitors and publishes initial channel events OPEN, BOUND, CONNECTED") @ManagedNotifications({ @ManagedNotification(name = InitialChannelEventsMonitor.Events.OPENED, description = "A channel has been opened. It is not yet bound to a local address.", notificationTypes = InitialChannelEventsMonitor.Events.OPENED), @ManagedNotification(name = InitialChannelEventsMonitor.Events.BOUND, description = "A channel has been bound to a local address. It is not yet connected to a remote address.", notificationTypes = InitialChannelEventsMonitor.Events.BOUND), @ManagedNotification(name = InitialChannelEventsMonitor.Events.CONNECTED, description = "A channel has been connected to a remote address. It is ready to receive messages.", notificationTypes = InitialChannelEventsMonitor.Events.CONNECTED) }) public class InitialChannelEventsMonitor implements NotificationPublisherAware { private static final String TYPE = "Channels"; private static final String NAME = "initial-channel-events"; static final String OBJECT_NAME = Jmx.GROUP + ":type=" + TYPE + ",name=" + NAME; public static class Events { public static final String OPENED = "channel.opened"; public static final String BOUND = "channel.bound"; public static final String CONNECTED = "channel.connected"; } private final Logger log = LoggerFactory .getLogger(getClass()); private NotificationPublisher notificationPublisher; private final AtomicLong channelOpenedEventSequenceNumber = new AtomicLong( 1L); private final AtomicLong channelBoundEventSequenceNumber = new AtomicLong( 1L); private final AtomicLong channelConnectedEventSequenceNumber = new AtomicLong( 1L); public InitialChannelEventsMonitor() { // Noop } public InitialChannelEventsMonitor( final NotificationPublisher notificationPublisher) { notNull(notificationPublisher, "Argument 'notificationPublisher' must not be null"); this.notificationPublisher = notificationPublisher; } @Override public void setNotificationPublisher( final NotificationPublisher notificationPublisher) { notNull(notificationPublisher, "Argument 'notificationPublisher' must not be null"); this.notificationPublisher = notificationPublisher; } void channelOpened(final Channel channel) { this.log.info("Channel {} has been opened", channel); final Notification notification = new Notification(Events.OPENED, channel, this.channelOpenedEventSequenceNumber.getAndIncrement(), "Channel " + channel + " has been opened."); sendNotification(notification); } private void sendNotification(final Notification notification) { if (this.notificationPublisher == null) { throw new IllegalStateException( "No " + NotificationPublisher.class.getName() + " has been set. Did you remember to manually inject a NotificationPublisher when using this class outside a Spring context?"); } this.notificationPublisher.sendNotification(notification); } void channelBound(final Channel channel, final SocketAddress localAddress) { this.log.info("Channel {} has been bound to local address [{}]", channel, localAddress); final Notification notification = new Notification(Events.BOUND, channel, this.channelBoundEventSequenceNumber.getAndIncrement(), "Channel " + channel + " has been bound to local address " + localAddress); notification.setUserData(localAddress); sendNotification(notification); } void channelConnected(final Channel channel, final SocketAddress remoteAddress) { this.log.info("Channel {} has been connected to remote address [{}]", channel, remoteAddress); final Notification notification = new Notification(Events.CONNECTED, channel, this.channelConnectedEventSequenceNumber.getAndIncrement(), "Channel " + channel + " has been connected to remote address " + remoteAddress); notification.setUserData(remoteAddress); sendNotification(notification); } }