View Javadoc

1   /*
2    *  Copyright 2010 Felix Roethenbacher
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  package ch.syabru.nagios.broker.jmx;
17  
18  import java.io.IOException;
19  
20  import javax.management.ListenerNotFoundException;
21  import javax.management.MBeanServerConnection;
22  import javax.management.Notification;
23  import javax.management.NotificationListener;
24  import javax.management.ObjectName;
25  import javax.management.remote.JMXConnectionNotification;
26  import javax.management.remote.JMXConnector;
27  import javax.management.remote.JMXConnectorFactory;
28  import javax.management.remote.JMXServiceURL;
29  
30  import org.apache.commons.lang.Validate;
31  import org.slf4j.Logger;
32  import org.slf4j.LoggerFactory;
33  
34  import ch.syabru.nagios.broker.Message;
35  import ch.syabru.nagios.broker.MessageHandler;
36  import ch.syabru.nagios.broker.MessageListener;
37  import ch.syabru.nagios.broker.MessageListenerManager;
38  
39  /**
40   * JMX message listener implementation.
41   *
42   * @author Felix Roethenbacher
43   *
44   */
45  public class JmxMessageListener
46  implements MessageListener, NotificationListener
47  {
48      private final Logger logger = LoggerFactory.getLogger(this.getClass());
49  
50      private MessageListenerManager messageListenerManager;
51      private MessageHandler messageHandler;
52      private JMXServiceURL jmxServiceUrl;
53      private ObjectName objectName;
54  
55      private JMXConnector connector;
56      private String id;
57  
58      /**
59       * C'tor.
60       * @param messageListenerManager Message listener manager.
61       * @param messageHandler Message handler.
62       * @param jmxServiceUrl JMX service URL.
63       * @param objectName Object name.
64       */
65      public JmxMessageListener(MessageListenerManager messageListenerManager,
66              MessageHandler messageHandler, JMXServiceURL jmxServiceUrl,
67              ObjectName objectName)
68      {
69          Validate.notNull(messageListenerManager,
70                  "messageListenerManager must not be null");
71          Validate.notNull(messageHandler, "messageHandler must not be null");
72          Validate.notNull(jmxServiceUrl, "jmxServiceUrl must not be null");
73          Validate.notNull(objectName, "objectName must not be null");
74          this.messageListenerManager = messageListenerManager;
75          this.messageHandler = messageHandler;
76          this.jmxServiceUrl = jmxServiceUrl;
77          this.objectName = objectName;
78          this.id = "JMX listener " + jmxServiceUrl + ", " +
79                  objectName.toString();
80      }
81  
82      @Override
83      public String getId() {
84          return id;
85      }
86  
87      @Override
88      public void registerListener()
89      {
90          try {
91              connector = JMXConnectorFactory.connect(jmxServiceUrl);
92              connector.addConnectionNotificationListener(this, null, null);
93              MBeanServerConnection con = connector.getMBeanServerConnection();
94              con.addNotificationListener(objectName, this, null, null);
95              logger.info("Registered JMX notification listener [{}]", getId());
96          } catch (Exception e) {
97              logger.warn("Failed to register JMX notification listener. " +
98                      "Will retry later. [{}] [{}]", new Object[] {getId(),
99                      e.getMessage()});
100             messageListenerManager.addForReconnect(this);
101         }
102     }
103 
104     /**
105      * Remove notification listeners.
106      */
107     @Override
108     public void unregisterListener() {
109         if (connector != null) {
110             try {
111                 connector.removeConnectionNotificationListener(this);
112             } catch (ListenerNotFoundException e) {
113                 logger.debug("Error removing connection notification " +
114                         "listener", e);
115             }
116             try {
117                 MBeanServerConnection con =
118                     connector.getMBeanServerConnection();
119                 con.removeNotificationListener(objectName, this);
120                 logger.debug("Unregistered notification listener [{}]",
121                         getId());
122             } catch (ListenerNotFoundException e) {
123                 // Do nothing. MBean probably already unregistered.
124             } catch (Exception e) {
125                 logger.debug("Error removing notification listener", e);
126             }
127             try {
128                 connector.close();
129             } catch (IOException e) {
130                 logger.debug("Error closing JMX connection", e);
131             }
132         }
133     }
134 
135     @Override
136     public void handleNotification(Notification notification, Object handback)
137     {
138         // Connection notifications.
139         if (notification instanceof JMXConnectionNotification) {
140             JMXConnectionNotification connNotification =
141                 (JMXConnectionNotification) notification;
142             if (connNotification.getType().equals(
143                     JMXConnectionNotification.CLOSED))
144             {
145                 logger.warn("Connection closed. Will retry later to " +
146                         "re-register listener. [{}]", getId());
147                 messageListenerManager.addForReconnect(this);
148             } else if (connNotification.getType().equals(
149                     JMXConnectionNotification.FAILED))
150             {
151                 logger.warn("Connection failed. Will retry later to " +
152                         "re-register listener. [{}]", getId());
153                 messageListenerManager.addForReconnect(this);
154             }
155         } else {
156             try {
157                 Message message = new JmxMessage(notification);
158                 // TODO Move this to separate thread as call should end as
159                 // quick as possible.
160                 messageHandler.messageReceived(message);
161             } catch (Exception e) {
162                 logger.error("Error handling JMX notification", e);
163             }
164         }
165     }
166 }