KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > snmp4j > agent > agentx > AgentX


1 /*_############################################################################
2   _##
3   _## SNMP4J-AgentX - AgentX.java
4   _##
5   _## Copyright (C) 2005-2007 Frank Fock (SNMP4J.org)
6   _##
7   _## This program is free software; you can redistribute it and/or modify
8   _## it under the terms of the GNU General Public License version 2 as
9   _## published by the Free Software Foundation.
10   _##
11   _## This program is distributed in the hope that it will be useful,
12   _## but WITHOUT ANY WARRANTY; without even the implied warranty of
13   _## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14   _## GNU General Public License for more details.
15   _##
16   _## You should have received a copy of the GNU General Public License
17   _## along with this program; if not, write to the Free Software
18   _## Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
19   _## MA 02110-1301 USA
20   _##
21   _##########################################################################*/

22
23 package org.snmp4j.agent.agentx;
24
25 import java.io.IOException JavaDoc;
26 import java.util.*;
27
28 import org.snmp4j.TransportMapping;
29 import org.snmp4j.log.LogAdapter;
30 import org.snmp4j.log.LogFactory;
31 import org.snmp4j.mp.PduHandle;
32 import org.snmp4j.mp.PduHandleCallback;
33
34 /**
35  * The <code>AgentX</code> class implements the AgentX protocol that sends
36  * and receives AgentX PDUs over one or more transport mappings.
37  *
38  * @author Frank Fock
39  * @version 1.0
40  */

41 public class AgentX implements AgentXCommandListener {
42
43   private static final LogAdapter logger = LogFactory.getLogger(AgentX.class);
44
45   private AgentXMessageDispatcher messageDispatcher;
46
47   /**
48    * The <code>pendingRequests</code> table contains pending requests
49    * accessed trough the key <code>PduHandle</code>
50    */

51   private Map pendingRequests = Collections.synchronizedMap(new HashMap(50));
52
53   /**
54    * The <code>asyncRequests</code> table contains pending requests
55    * accessed trough the key userObject
56    */

57   private Map asyncRequests = Collections.synchronizedMap(new HashMap(50));
58
59   // Timer for timing out pending requests
60
private Timer timer = new Timer(true);
61   private Vector commandListeners;
62
63   public AgentX(AgentXMessageDispatcher dispatcher) {
64     this.messageDispatcher = dispatcher;
65     this.messageDispatcher.addCommandListener(this);
66   }
67
68   public void addTransportMapping(TransportMapping transport) {
69     messageDispatcher.addTransportMapping(transport);
70     transport.addTransportListener(messageDispatcher);
71   }
72
73   public void removeTransportMapping(TransportMapping transport) {
74     messageDispatcher.removeTransportMapping(transport);
75     transport.removeTransportListener(messageDispatcher);
76   }
77
78   /**
79    * Removes a <code>AgentXCommandListener</code> from this AgentX session.
80    * @param listener
81    * a previously added <code>AgentXCommandListener</code> instance.
82    */

83   public synchronized void removeCommandResponder(AgentXCommandListener listener) {
84     if (commandListeners != null &&
85         commandListeners.contains(listener)) {
86       Vector v = (Vector) commandListeners.clone();
87       v.removeElement(listener);
88       commandListeners = v;
89     }
90   }
91
92   /**
93    * Adds a <code>AgentXCommandListener</code> to this AgentX session.
94    * The command responder will then be informed about incoming SNMP PDUs of
95    * any kind that are not related to any outstanding requests of this SNMP
96    * session.
97    *
98    * @param listener
99    * the <code>AgentXCommandListener</code> instance to be added.
100    */

101   public synchronized void addCommandResponder(AgentXCommandListener listener) {
102     Vector v = (commandListeners == null) ?
103         new Vector(2) : (Vector) commandListeners.clone();
104     if (!v.contains(listener)) {
105       v.addElement(listener);
106       commandListeners = v;
107     }
108   }
109
110   /**
111    * Sends a <code>AgentXPDU</code> to the given target and returns the response
112    * synchronously.
113    * @param pdu
114    * a <code>AgentXPDU</code> instance.
115    * @param target
116    * the AgentXTarget instance representing the target AgentX entity
117    * where to send the <code>pdu</code>.
118    * @param transport
119    * specifies the <code>TransportMapping</code> to be used when sending
120    * the PDU. If <code>transport</code> is <code>null</code>, the associated
121    * message dispatcher will try to determine the transport mapping by the
122    * <code>target</code>'s address.
123    * @return
124    * the received response encapsulated in a <code>AgentXResponseEvent</code>
125    * instance. To obtain the received response <code>AgentXPDU</code> call
126    * {@link AgentXResponseEvent#getResponse()}. If the request timed out,
127    * that method will return <code>null</code>.
128    * @throws IOException
129    * if the message could not be sent.
130    */

131   public AgentXResponseEvent send(AgentXPDU pdu, AgentXTarget target,
132                                   TransportMapping transport) throws IOException JavaDoc {
133     SyncResponseListener syncResponse = new SyncResponseListener();
134     if (!pdu.isConfirmedPDU()) {
135       sendMessage(pdu, target, transport, null);
136       return null;
137     }
138     synchronized (syncResponse) {
139       PendingRequest request =
140           new PendingRequest(null, syncResponse, target, pdu, target);
141       sendMessage(pdu, target, transport, request);
142       try {
143         syncResponse.wait();
144       }
145       catch (InterruptedException JavaDoc iex) {
146         logger.warn(iex);
147         // ignore
148
}
149     }
150     return syncResponse.response;
151   }
152
153   /**
154    * Sends a <code>AgentXPDU</code> to the given target and returns the response
155    * asynchronously.
156    * @param pdu
157    * a <code>AgentXPDU</code> instance.
158    * @param target
159    * the AgentXTarget instance representing the target AgentX entity
160    * where to send the <code>pdu</code>.
161    * @param transport
162    * specifies the <code>TransportMapping</code> to be used when sending
163    * the PDU. If <code>transport</code> is <code>null</code>, the associated
164    * message dispatcher will try to determine the transport mapping by the
165    * <code>target</code>'s address.
166    * @param userHandle
167    * an arbitrary user handle which is transparently returned to the response
168    * listener.
169    * @param listener
170    * the listener that should be informed about the reponse or timeout.
171    * @throws IOException
172    * if the message could not be sent.
173    */

174   public void send(AgentXPDU pdu, AgentXTarget target,
175                    TransportMapping transport,
176                    Object JavaDoc userHandle,
177                    AgentXResponseListener listener) throws IOException JavaDoc {
178     PendingRequest request =
179         new PendingRequest(null, listener, userHandle,
180                            pdu, target);
181     sendMessage(pdu, target, transport, request);
182   }
183
184   /**
185    * Actually sends a PDU to a target and returns a handle for the sent PDU.
186    * @param pdu
187    * the <code>PDU</code> instance to be sent.
188    * @param target
189    * a <code>AgentXTarget</code> instance denoting the target AgentX entity.
190    * @param transport
191    * the (optional) transport mapping to be used to send the request.
192    * If <code>transport</code> is <code>null</code> a suitable transport
193    * mapping is determined from the <code>target</code> address.
194    * @param pduHandleCallback
195    * an optional callback instance that is informed (if not
196    * <code>null</code>) about the newly assigned PduHandle just before the
197    * message is sent out.
198    * @throws IOException
199    * if the transport fails to send the PDU or the if the message cannot
200    * be BER encoded.
201    * @return PduHandle
202    * that uniquely identifies the sent PDU for further reference.
203    */

204   protected PduHandle sendMessage(AgentXPDU pdu, AgentXTarget target,
205                                   TransportMapping transport,
206                                   PduHandleCallback pduHandleCallback)
207       throws IOException JavaDoc
208   {
209     PduHandle handle =
210         messageDispatcher.send(transport, target.getAddress(), pdu,
211                                pduHandleCallback);
212     return handle;
213   }
214
215   public void processCommand(AgentXCommandEvent event) {
216     AgentXPDU pdu = event.getCommand();
217     PduHandle handle = new PduHandle(pdu.getPacketID());
218     if (pdu.getType() == AgentXPDU.AGENTX_RESPONSE_PDU) {
219       event.setProcessed(true);
220       PendingRequest request;
221       if (logger.isDebugEnabled()) {
222         logger.debug("Removing pending request with handle " + handle);
223       }
224       request = (PendingRequest) pendingRequests.remove(handle);
225       if (request == null) {
226         if (logger.isWarnEnabled()) {
227           logger.warn("Received response that cannot be matched to any " +
228                       "outstanding request, address=" +
229                       event.getPeerAddress() +
230                       ", packetID=" + pdu.getPacketID());
231         }
232       }
233       else {
234         // return response
235
request.finished = true;
236         request.listener.onResponse(new AgentXResponseEvent(this,
237             request.target,
238             event.getPeerAddress(),
239             request.pdu,
240             (AgentXResponsePDU)pdu,
241             request.userObject));
242       }
243     }
244     else {
245       if (logger.isDebugEnabled()) {
246         logger.debug("Fire process PDU event: " + event.toString());
247       }
248       fireProcessPdu(event);
249     }
250   }
251
252   /**
253    * Fires a <code>CommandResponderEvent</code> event to inform listeners about
254    * a received PDU. If a listener has marked the event as processed further
255    * listeners will not be informed about the event.
256    * @param event
257    * a <code>CommandResponderEvent</code>.
258    */

259   protected void fireProcessPdu(AgentXCommandEvent event) {
260     if (commandListeners != null) {
261       Vector listeners = commandListeners;
262       int count = listeners.size();
263       for (int i = 0; i < count; i++) {
264         ((AgentXCommandListener) listeners.elementAt(i)).processCommand(event);
265         // if event is marked as processed the event is not forwarded to
266
// remaining listeners
267
if (event.isProcessed()) {
268           return;
269         }
270       }
271     }
272   }
273
274
275   class AsyncRequestKey {
276     private AgentXPDU request;
277     private AgentXResponseListener listener;
278
279     public AsyncRequestKey(AgentXPDU request, AgentXResponseListener listener) {
280       this.request = request;
281       this.listener = listener;
282     }
283
284     /**
285      * Indicates whether some other object is "equal to" this one.
286      *
287      * @param obj the reference object with which to compare.
288      * @return <code>true</code> if this object is the same as the obj argument;
289      * <code>false</code> otherwise.
290      */

291     public boolean equals(Object JavaDoc obj) {
292       if (obj instanceof AsyncRequestKey) {
293         AsyncRequestKey other = (AsyncRequestKey) obj;
294         return (request.equals(other.request) && listener.equals(other.listener));
295       }
296       return false;
297     }
298
299     public int hashCode() {
300       return request.hashCode();
301     }
302   }
303
304   class PendingRequest extends TimerTask implements PduHandleCallback {
305
306     protected PduHandle key;
307     protected AgentXResponseListener listener;
308     protected Object JavaDoc userObject;
309
310     protected AgentXPDU pdu;
311     protected AgentXTarget target;
312
313     private volatile boolean finished = false;
314
315
316     public PendingRequest(PduHandle key,
317                           AgentXResponseListener listener,
318                           Object JavaDoc userObject,
319                           AgentXPDU pdu,
320                           AgentXTarget target) {
321       this.key = key;
322       this.userObject = userObject;
323       this.listener = listener;
324       this.pdu = pdu;
325       this.target = target;
326     }
327
328     protected void registerRequest(PduHandle handle) {
329     }
330
331     public synchronized void run() {
332       pendingRequests.remove(key);
333       // request timed out
334
if (!finished) {
335         if (logger.isDebugEnabled()) {
336           logger.debug("AgentX request timed out: " + key.getTransactionID());
337         }
338         finished = true;
339         listener.onResponse(new AgentXResponseEvent(AgentX.this, target, null,
340             pdu, null, userObject));
341       }
342     }
343
344     public synchronized boolean setFinished() {
345       boolean currentState = finished;
346       this.finished = true;
347       return currentState;
348     }
349
350     public synchronized void pduHandleAssigned(PduHandle handle, Object JavaDoc pdu) {
351       if (key == null) {
352         key = handle;
353         if (logger.isDebugEnabled()) {
354           logger.debug("New pending request "+pdu+" with handle " + handle);
355         }
356         registerRequest(handle);
357         pendingRequests.put(handle, this);
358         long delay = target.getTimeout();
359         timer.schedule(this, delay);
360       }
361     }
362   }
363
364   class AsyncPendingRequest extends PendingRequest {
365
366     public AsyncPendingRequest(PduHandle key,
367                                AgentXResponseListener listener,
368                                Object JavaDoc userObject,
369                                AgentXPDU pdu,
370                                AgentXTarget target) {
371       super(key, listener, userObject, pdu, target);
372     }
373
374     protected void registerRequest(PduHandle handle) {
375       asyncRequests.put(new AsyncRequestKey(pdu, listener), handle);
376     }
377   }
378
379   class SyncResponseListener implements AgentXResponseListener {
380
381     private AgentXResponseEvent response = null;
382
383     public synchronized void onResponse(AgentXResponseEvent event) {
384       this.response = event;
385       this.notify();
386     }
387
388     public AgentXResponseEvent getResponse() {
389       return response;
390     }
391
392   }
393
394   public AgentXMessageDispatcher getMessageDispatcher() {
395     return messageDispatcher;
396   }
397 }
398
Popular Tags