001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.servicemix.snmp;
018
019 import javax.jbi.management.DeploymentException;
020 import javax.jbi.messaging.InOnly;
021 import javax.jbi.messaging.MessageExchange;
022 import javax.jbi.messaging.MessagingException;
023 import javax.jbi.messaging.NormalizedMessage;
024
025 import org.apache.commons.logging.Log;
026 import org.apache.commons.logging.LogFactory;
027 import org.apache.servicemix.common.endpoints.PollingEndpoint;
028 import org.apache.servicemix.snmp.marshaler.DefaultSnmpMarshaler;
029 import org.apache.servicemix.snmp.marshaler.SnmpMarshalerSupport;
030 import org.apache.servicemix.snmp.util.OIDList;
031 import org.snmp4j.CommunityTarget;
032 import org.snmp4j.PDU;
033 import org.snmp4j.Snmp;
034 import org.snmp4j.TransportMapping;
035 import org.snmp4j.event.ResponseEvent;
036 import org.snmp4j.event.ResponseListener;
037 import org.snmp4j.mp.MPv3;
038 import org.snmp4j.mp.SnmpConstants;
039 import org.snmp4j.security.SecurityModels;
040 import org.snmp4j.security.SecurityProtocols;
041 import org.snmp4j.security.USM;
042 import org.snmp4j.smi.Address;
043 import org.snmp4j.smi.GenericAddress;
044 import org.snmp4j.smi.OID;
045 import org.snmp4j.smi.OctetString;
046 import org.snmp4j.smi.VariableBinding;
047 import org.snmp4j.transport.DefaultUdpTransportMapping;
048
049 /**
050 * This is the polling endpoint for the snmp component.
051 *
052 * @org.apache.xbean.XBean element="poller"
053 * @author lhein
054 */
055 public class SnmpPollingEndpoint extends PollingEndpoint implements SnmpEndpointType, ResponseListener {
056 private static final transient Log LOG = LogFactory.getLog(SnmpPollingEndpoint.class);
057
058 public static final String DEFAULT_COMMUNITY = "public";
059 public static final int DEFAULT_SNMP_VERSION = SnmpConstants.version1;
060 public static final int DEFAULT_SNMP_RETRIES = 2;
061 public static final int DEFAULT_SNMP_TIMEOUT = 1500;
062
063 private Address targetAddress;
064 private TransportMapping transport;
065 private Snmp snmp;
066 private USM usm;
067 private CommunityTarget target;
068 private PDU pdu;
069
070 private OIDList oids = new OIDList();
071 private String address;
072 private int retries = DEFAULT_SNMP_RETRIES;
073 private int timeout = DEFAULT_SNMP_TIMEOUT;
074 private int snmpVersion = DEFAULT_SNMP_VERSION;
075 private String snmpCommunity = DEFAULT_COMMUNITY;
076
077 private SnmpMarshalerSupport marshaler = new DefaultSnmpMarshaler();
078
079 /*
080 * (non-Javadoc)
081 * @see org.apache.servicemix.common.endpoints.ConsumerEndpoint#activate()
082 */
083 @Override
084 public synchronized void activate() throws Exception {
085 super.activate();
086
087 this.targetAddress = GenericAddress.parse(this.address);
088 this.transport = new DefaultUdpTransportMapping();
089 this.snmp = new Snmp(transport);
090 this.usm = new USM(SecurityProtocols.getInstance(), new OctetString(MPv3.createLocalEngineID()), 0);
091 SecurityModels.getInstance().addSecurityModel(usm);
092
093 // setting up target
094 target = new CommunityTarget();
095 target.setCommunity(new OctetString(this.snmpCommunity));
096 target.setAddress(targetAddress);
097 target.setRetries(this.retries);
098 target.setTimeout(this.timeout);
099 target.setVersion(this.snmpVersion);
100
101 // creating PDU
102 this.pdu = new PDU();
103 }
104
105 /*
106 * (non-Javadoc)
107 * @see org.apache.servicemix.common.endpoints.PollingEndpoint#start()
108 */
109 @Override
110 public synchronized void start() throws Exception {
111 super.start();
112
113 // again listen to the transport
114 this.transport.listen();
115 }
116
117 /*
118 * (non-Javadoc)
119 * @see org.apache.servicemix.common.endpoints.PollingEndpoint#stop()
120 */
121 @Override
122 public synchronized void stop() throws Exception {
123 // stop listening to the transport
124 if (this.transport.isListening()) {
125 this.transport.close();
126 }
127
128 super.stop();
129 }
130
131 /*
132 * (non-Javadoc)
133 * @see org.apache.servicemix.common.endpoints.ConsumerEndpoint#validate()
134 */
135 @Override
136 public void validate() throws DeploymentException {
137 super.validate();
138
139 // check address not null
140 if (this.address == null) {
141 throw new DeploymentException("The address attribute has to be specified!");
142 }
143
144 // check if address is valid
145 try {
146 if (GenericAddress.parse(this.address) == null) {
147 throw new DeploymentException("The specified address " + address + " is not valid!");
148 }
149 } catch (IllegalArgumentException ex) {
150 throw new DeploymentException("The specified address " + address + " is not valid!");
151 }
152
153 // finally check if the oid vector contains values
154 if (this.oids == null || this.oids.size()<=0) {
155 // the poller would be unemployed
156 throw new DeploymentException("There are no OIDs defined to be polled. Check your oids attribute.");
157 }
158 }
159
160 /*
161 * (non-Javadoc)
162 * @see org.apache.servicemix.common.endpoints.PollingEndpoint#poll()
163 */
164 @Override
165 public void poll() throws Exception {
166 this.pdu.clear();
167 this.pdu.setType(PDU.GET);
168
169 // prepare the request items
170 for (OID oid : oids) {
171 this.pdu.add(new VariableBinding(oid));
172 }
173
174 // send the request
175 snmp.send(pdu, target, null, this);
176 }
177
178 /*
179 * (non-Javadoc)
180 * @see
181 * org.apache.servicemix.common.endpoints.AbstractEndpoint#process(javax
182 * .jbi.messaging.MessageExchange)
183 */
184 @Override
185 public void process(MessageExchange exchange) throws Exception {
186 // only DONE and ERROR states will be received here and this
187 // endpoint is not interested in such messages at all
188 }
189
190 /*
191 * (non-Javadoc)
192 * @see
193 * org.snmp4j.event.ResponseListener#onResponse(org.snmp4j.event.ResponseEvent
194 * )
195 */
196 public void onResponse(ResponseEvent event) {
197 // Always cancel async request when response has been received
198 // otherwise a memory leak is created! Not canceling a request
199 // immediately can be useful when sending a request to a broadcast
200 // address.
201 ((Snmp)event.getSource()).cancel(event.getRequest(), this);
202
203 // check for valid response
204 if (event.getRequest() == null || event.getResponse() == null) {
205 // ignore null requests/responses
206 LOG.debug("Received invalid snmp event. Request: " + event.getRequest() + " / Response: "
207 + event.getResponse());
208 return;
209 }
210
211 // now prepare the message and send it
212 sendSnmpDataMessage(event.getRequest(), event.getResponse());
213 }
214
215 /**
216 * sends the message to the bus
217 *
218 * @param request the request PDU
219 * @param response the response PDU
220 */
221 private void sendSnmpDataMessage(PDU request, PDU response) {
222 try {
223 // create a inOnly exchange
224 InOnly io = getExchangeFactory().createInOnlyExchange();
225
226 // configure the exchange target
227 configureExchangeTarget(io);
228
229 // create the in message
230 NormalizedMessage inMsg = io.createMessage();
231
232 // now let the marshaller convert the snmp data into a normalized
233 // message to send to jbi bus
234 this.marshaler.convertToJBI(io, inMsg, request, response);
235
236 // then put the in message into the inOnly exchange
237 io.setInMessage(inMsg);
238
239 // and use send to deliver it
240 getChannel().send(io);
241 } catch (MessagingException ex) {
242 LOG.error("Error while trying to send the snmp event to the jbi bus", ex);
243 }
244 }
245
246 public String getAddress() {
247 return this.address;
248 }
249
250 /**
251 * <p>Specifies the connection URI used to connect to a snmp capable device.
252 * <br /><br />
253 * <b><u>Template:</u></b> <br />
254 * <i><protocol>:<host>/<port></i>
255 * <br /><br />
256 * <b><u>Details:</u></b><br /><br/>
257 * <table border="0" cellpadding="0" cellspacing="0">
258 * <tr>
259 * <td width="40%" align="left"><b><u>Name</u></b></td>
260 * <td width="60%" align="left"><b><u>Description</u></b></td>
261 * </tr>
262 * <tr>
263 * <td>protocol</td>
264 * <td>the protocol to use (udp or tcp)</td>
265 * </tr>
266 * <tr>
267 * <td>host</td>
268 * <td>the name or ip address of the snmp capable device</td>
269 * </tr>
270 * <tr>
271 * <td>port</td>
272 * <td>the port number to use</td>
273 * </tr>
274 * </table>
275 * <br/>
276 * <b><u>Example:</u></b><br />
277 * <i>udp:192.168.2.122/161</i></p>
278 * <i> The default value is <b>null</b></i><br/><br/>
279 *
280 * @param address
281 * a <code>String</code> value containing the connection details
282 */
283 public void setAddress(String address) {
284 this.address = address;
285 }
286
287 public int getRetries() {
288 return this.retries;
289 }
290
291 /**
292 * <p>Specifies the connection retries.</p>
293 * <i> The default value is <b>2</b></i><br/><br/>
294 *
295 * @param retries
296 * a <code>int</code> value containing the retry count
297 */
298 public void setRetries(int retries) {
299 this.retries = retries;
300 }
301
302 public int getTimeout() {
303 return this.timeout;
304 }
305
306 /**
307 * <p>Specifies the connection time out in milliseconds.</p>
308 * <i> The default value is <b>1500</b></i><br/><br/>
309 *
310 * @param timeout
311 * a <code>int</code> value containing the time out in millis
312 */
313 public void setTimeout(int timeout) {
314 this.timeout = timeout;
315 }
316
317 public int getSnmpVersion() {
318 return this.snmpVersion;
319 }
320
321 /**
322 * <p>Specifies the snmp protocol version to use.</p>
323 * <i> The default value is <b>0 (version 1)</b></i><br/><br/>
324 *
325 * @param snmpVersion
326 * a <code>int</code> value containing the snmp version
327 */
328 public void setSnmpVersion(int snmpVersion) {
329 this.snmpVersion = snmpVersion;
330 }
331
332 public String getSnmpCommunity() {
333 return this.snmpCommunity;
334 }
335
336 /**
337 * <p>Specifies the snmp community to use.</p>
338 * <i> The default value is <b>"public"</b></i><br/><br/>
339 *
340 * @param snmpCommunity
341 * a <code>String</code> value containing the snmp community
342 */
343 public void setSnmpCommunity(String snmpCommunity) {
344 this.snmpCommunity = snmpCommunity;
345 }
346
347 public SnmpMarshalerSupport getMarshaler() {
348 return this.marshaler;
349 }
350
351 /**
352 * <p>Specifies a marshaler class which provides the logic for converting
353 * a snmp response into a normalized message. This class has to implement
354 * the <code>SnmpMarshalerSupport</code> interface. If you don't specify a
355 * marshaler, the <code>DefaultSnmpMarshaler</code> will be used.</p>
356 *
357 * @param marshaler
358 * a class which implements <code>SnmpMarshalerSupport</code>
359 */
360 public void setMarshaler(SnmpMarshalerSupport marshaler) {
361 this.marshaler = marshaler;
362 }
363
364 public OIDList getOids() {
365 return this.oids;
366 }
367
368 /**
369 * <p>Specifies a reference to a list of OID values which will be used for
370 * the snmp request. You have two possibilities how to specify the value:
371 * <br /><br />
372 * <i>a) referencing to a file containing a list of OID values separated by a line feed
373 * <br/> or<br/>
374 * <i>b) defining a coma (<b>,</b>) separated list of OID values
375 * <br /><br />
376 * <b><u>Examples:</u></b><br />
377 * <i>a) oids="classpath:myOids.txt"<br />
378 * oids="file:/home/lhein/snmp/device_a/oids.txt"<br/>
379 * <br />
380 * <i>b) oids="1.3.6.1.2.1.1.3.0 , 1.3.6.1.2.1.25.3.2.1.5.1 , 1.3.6.1.2.1.25.3.5.1.1.1 , 1.3.6.1.2.1.43.5.1.1.11.1"</i></p>
381 * <i> The default value is <b>null</b></i><br/><br/>
382 *
383 * @param oids
384 * a <code>OIDList</code> containing the OID values for the request
385 */
386 public void setOids(OIDList oids) {
387 this.oids = oids;
388 }
389 }