View Javadoc
1   // NAME
2   //      $RCSfile: AnnexModemStatusBean.java,v $
3   // DESCRIPTION
4   //      [given below in javadoc format]
5   // DELTA
6   //      $Revision: 1.22 $
7   // CREATED
8   //      $Date: 2006/03/23 14:54:09 $
9   // COPYRIGHT
10  //      Westhawk Ltd
11  // TO DO
12  //
13  
14  /*
15   * Copyright (C) 1998 - 2006 by Westhawk Ltd
16   *
17   * Permission to use, copy, modify, and distribute this software
18   * for any purpose and without fee is hereby granted, provided
19   * that the above copyright notices appear in all copies and that
20   * both the copyright notice and this permission notice appear in
21   * supporting documentation.
22   * This software is provided "as is" without express or implied
23   * warranty.
24   */
25  
26  package uk.co.westhawk.snmp.beans;
27  
28  /*-
29   * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
30   * SNMP Java Client
31   * ჻჻჻჻჻჻
32   * Copyright 2023 MetricsHub, Westhawk
33   * ჻჻჻჻჻჻
34   * This program is free software: you can redistribute it and/or modify
35   * it under the terms of the GNU Lesser General Public License as
36   * published by the Free Software Foundation, either version 3 of the
37   * License, or (at your option) any later version.
38   *
39   * This program is distributed in the hope that it will be useful,
40   * but WITHOUT ANY WARRANTY; without even the implied warranty of
41   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
42   * GNU General Lesser Public License for more details.
43   *
44   * You should have received a copy of the GNU General Lesser Public
45   * License along with this program.  If not, see
46   * <http://www.gnu.org/licenses/lgpl-3.0.html>.
47   * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
48   */
49  
50  import uk.co.westhawk.snmp.stack.*;
51  import uk.co.westhawk.snmp.pdu.*;
52  
53  import javax.swing.tree.*;
54  import java.awt.*;
55  import java.util.*;
56  import java.text.*;
57  import java.lang.*;
58  import java.io.*;
59  import java.beans.*;
60  
61  /**
62   * <p>
63   * This bean is written for 
64   * <a href="http://www.nortelnetworks.com/link/remote_annex_2000">
65   * Remote Annex 2000</a>
66   * access server.
67   * </p>
68   *
69   * <p>
70   * The server comes with the Xylogics specific MIBs, you can
71   * find them in the Annex software installation, I couldn't find them on
72   * the Web. I did not use them for this bean, however. 
73   * </p>
74   *
75   * <p>
76   * This bean uses the 
77   * <a href="http://www.ietf.org/rfc/rfc1658.txt">CHARACTER-MIB</a>
78   * and 
79   * <a href="http://www.ietf.org/rfc/rfc1659.txt">RS-232-MIB</a>.
80   * </p>
81   *
82   * <p>
83   * This bean collects information about the modem status,
84   * connected to the server. 
85   * It will only collect those modems (see charPortOperStatus) that are
86   * "up". It will then show if the modem is in use of not (see
87   * rs232InSigState).
88   * </p>
89   *
90   * <p>
91   * You can get the data via the getModemIndexes() and 
92   * getPortStatus(Long index) methods. This way you can visualise
93   * the data yourself. 
94   * </p>
95   *
96   * <p>
97   * You can also use the Swing JTree to visualise the modems.
98   * This bean implements the Swing TreeNode interface. 
99   * The user has to set the setDefaultTreeModel, so this class can update all
100  * the nodes that are added, removed of changed.
101  * If this class is <em>not</em> the root of the JTree, you have to set
102  * the (TreeNode) parent of this class.
103  * </p>
104  *
105  * <p>
106  * The properties in the parent classes should be set, before calling
107  * the action() method. Via a TreeModelEvent the application/applet
108  * will be notified. 
109  * </p>
110  *
111  * <p>
112  * We only have one Annex server, so I don't know how and if it
113  * works with more than 1. Please let us know if it doesn't work.
114  * </p>
115  *
116  * @see SNMPBean#setHost
117  * @see SNMPBean#setPort
118  * @see SNMPBean#setCommunityName
119  * @see SNMPRunBean#setUpdateInterval
120  * @see SNMPBean#addPropertyChangeListener
121  * @see SNMPBean#action
122  * @see GetNextPdu_vec
123  * 
124  * @author <a href="mailto:snmp@westhawk.co.uk">Birgit Arkesteijn</a>
125  * @version $Revision: 1.22 $ $Date: 2006/03/23 14:54:09 $
126  */
127 public class AnnexModemStatusBean extends SNMPRunBean
128         implements Observer, TreeNode {
129     private static final String version_id = "@(#)$Id: AnnexModemStatusBean.java,v 1.22 2006/03/23 14:54:09 birgit Exp $ Copyright Westhawk Ltd";
130 
131     /**
132      * A unique value for each character port. This perhaps
133      * corresponding to the same value of ifIndex when the
134      * character port is associated with a hardware port
135      * represented by an ifIndex.
136      *
137      * <p>
138      * Syntax: INTEGER
139      * </p>
140      *
141      * See the CHARACTER-MIB.
142      */
143     public final static String charPortIndex = "1.3.6.1.2.1.19.2.1.1";
144     /**
145      * An administratively assigned name for the port, typically with
146      * some local significance.
147      * 
148      * <p>
149      * Syntax: DisplayString
150      * </p>
151      *
152      * See <a href="http://www.ietf.org/rfc/rfc1658.txt">CHARACTER-MIB</a>.
153      */
154     public final static String charPortName = "1.3.6.1.2.1.19.2.1.2";
155 
156     /**
157      * The port's actual, operational state, independent
158      * of flow control.
159      * <ol>
160      * <li>
161      * 'up' indicates able to function normally.</li>
162      * <li>
163      * 'down' indicates inability to function for administrative or
164      * operational reasons.</li>
165      * <li>
166      * 'maintenance' indicates a maintenance mode, exclusive of normal
167      * operation, such as running a test.</li>
168      * <li>
169      * 'absent' indicates that port hardware is not present.</li>
170      * <li>
171      * 'active' indicates up with a user present (e.g. logged in).</li>
172      * </ol>
173      *
174      * <p>
175      * 'up' and 'active' correspond to ifOperStatus (rfc2863.mib) 'up'.
176      * 'down' and 'absent' correspond to ifOperStatus 'down'.
177      * 'maintenance' corresponds to ifOperStatus 'test'.
178      * </p>
179      *
180      * <p>
181      * Syntax: INTEGER
182      * </p>
183      *
184      * See <a href="http://www.ietf.org/rfc/rfc1658.txt">CHARACTER-MIB</a>
185      * and <a href="http://www.ietf.org/rfc/rfc2863.txt">IF-MIB-MIB</a>.
186      */
187     public final static String charPortOperStatus = "1.3.6.1.2.1.19.2.1.7";
188 
189     /**
190      * The current signal state.
191      *
192      * <p>
193      * Syntax: INTEGER
194      * </p>
195      *
196      * See <a href="http://www.ietf.org/rfc/rfc1659.txt">RS-232-MIB</a>.
197      */
198     public final static String rs232InSigState = "1.3.6.1.2.1.10.33.5.1.3";
199 
200     private final static int NR_PORT_OID = 3;
201 
202     /** charPortOperStatus up. */
203     public final static int portUP = 1;
204     /** charPortOperStatus down. */
205     public final static int portDOWN = 2;
206     /** charPortOperStatus maintenance. */
207     public final static int portMAINTENANCE = 3;
208     /** charPortOperStatus absent. */
209     public final static int portABSENT = 4;
210     /** charPortOperStatus active. */
211     public final static int portACTIVE = 5;
212 
213     /**
214      * One of rs232InSigName values. If the dcd of rs232InSigState is
215      * on, that means that there is contact.
216      */
217     public final static int DCD = 6;
218 
219     /** rs232InSigState none. */
220     public final static int sigNONE = 1;
221     /** rs232InSigState on. */
222     public final static int sigON = 2;
223     /** rs232InSigState off. */
224     public final static int sigOFF = 3;
225 
226     public final static String[] sig_state = {
227             "unknown",
228             "none",
229             "in use",
230             "not in use"
231     };
232 
233     private GetNextPdu_vec pduGetNext;
234     private Hashtable modemIndexStatusHash;
235     private Hashtable modemHash;
236 
237     private TreeNode parent;
238     private DefaultTreeModel treeModel;
239 
240     private boolean isGetNextInFlight;
241     private Date lastUpdateDate = null;
242 
243     private int deviceType = 0;
244     private int openCount = 0;
245     private int modemStatus = 0;
246 
247     /**
248      * The default constructor.
249      */
250     public AnnexModemStatusBean() {
251         modemIndexStatusHash = new Hashtable();
252         modemHash = new Hashtable();
253     }
254 
255     /**
256      * The constructor that will set the host and the port no.
257      *
258      * @param h the hostname
259      * @param p the port no
260      * @see SNMPBean#setHost
261      * @see SNMPBean#setPort
262      */
263     public AnnexModemStatusBean(String h, int p) {
264         this(h, p, null);
265     }
266 
267     /**
268      * The constructor that will set the host, the port no and the local
269      * bind address.
270      *
271      * @param h the hostname
272      * @param p the port no
273      * @param b the local bind address
274      * @see SNMPBean#setHost
275      * @see SNMPBean#setPort
276      * @see SNMPBean#setBindAddress
277      *
278      * @since 4_14
279      */
280     public AnnexModemStatusBean(String h, int p, String b) {
281         this();
282         setHost(h);
283         setPort(p);
284         setBindAddress(b);
285     }
286 
287     /**
288      * Returns the date of the moment when this bean was last updated.
289      * This might be null when the first time the update was not finished.
290      *
291      * @return the last update date
292      */
293     public Date getLastUpdateDate() {
294         return lastUpdateDate;
295     }
296 
297     /**
298      * Returns the indexes (as Integers) of the voice modems that are
299      * open. Only the open voice modems of the card are saved.
300      * 
301      * Use getPortStatus() or getPortStatusString() to get the status
302      * of the modem.
303      *
304      * @see #getPortStatus
305      * @see #getPortStatusString
306      */
307     public Enumeration getModemIndexes() {
308         return modemIndexStatusHash.keys();
309     }
310 
311     /**
312      * Returns the number of voice modems in the table.
313      */
314     public synchronized int getModemCount() {
315         return modemIndexStatusHash.size();
316     }
317 
318     /**
319      * Returns the name of the port.
320      *
321      * @param index The index of the port
322      * @return The name
323      *
324      */
325     public String getPortName(Long index) {
326         String name = "";
327         Object obj = modemHash.get(index);
328         if (obj != null) {
329             PortInfo pInfo = (PortInfo) obj;
330             name = pInfo.getName();
331         }
332         return name;
333     }
334 
335     /**
336      * Returns the status of the modem as an int.
337      *
338      * @param index The index of the modem
339      * @return The status
340      *
341      * @see #getModemIndexes
342      */
343     public int getPortStatus(Long index) {
344         int status = 0;
345         Object obj = modemIndexStatusHash.get(index);
346         if (obj != null) {
347             status = ((Integer) obj).intValue();
348         }
349         return status;
350     }
351 
352     /**
353      * Returns the String representation of the status of the modem.
354      *
355      * @param index The index of the modem
356      * @return The status
357      *
358      * @see #getModemIndexes
359      */
360     public String getPortStatusString(Long index) {
361         int status = getPortStatus(index);
362         String str = sig_state[status];
363         return str;
364     }
365 
366     /**
367      * Returns the children of the reciever as an Enumeration.
368      */
369     public Enumeration children() {
370         return modemHash.elements();
371     }
372 
373     /**
374      * Returns the number of children <code>TreeNode</code>s the receiver
375      * contains.
376      */
377     public int getChildCount() {
378         int sz = modemHash.size();
379         return sz;
380     }
381 
382     /**
383      * Returns the child <code>TreeNode</code> at index
384      * <code>childIndex</code>.
385      */
386     public TreeNode getChildAt(int childIndex) {
387         TreeNode node = null;
388         if (childIndex < modemHash.size()) {
389             Enumeration e = modemHash.elements();
390             for (int i = 0; i <= childIndex; i++) {
391                 node = (TreeNode) e.nextElement();
392             }
393         }
394         return node;
395     }
396 
397     /**
398      * Returns the index of <code>node</code> in the receivers children.
399      * If the receiver does not contain <code>node</code>, -1 will be
400      * returned.
401      */
402     public int getIndex(TreeNode node) {
403         int ret = -1;
404         if (modemHash.contains(node)) {
405             boolean found = false;
406             Enumeration e = modemHash.elements();
407             while (e.hasMoreElements() && !found) {
408                 TreeNode n = (TreeNode) e.nextElement();
409                 found = (n == node);
410                 ret++;
411             }
412         }
413         return ret;
414     }
415 
416     /**
417      * Returns the parent <code>TreeNode</code> of the receiver.
418      */
419     public TreeNode getParent() {
420         return parent;
421     }
422 
423     /**
424      * Returns true if the receiver allows children.
425      */
426     public boolean getAllowsChildren() {
427         return true;
428     }
429 
430     /**
431      * Returns true if the receiver is a leaf.
432      */
433     public boolean isLeaf() {
434         return false;
435     }
436 
437     /**
438      * This method starts the action of the bean. It will initialises
439      * all variables before starting.
440      */
441     public void action() {
442         if (isHostPortReachable()) {
443             lastUpdateDate = new Date();
444             isGetNextInFlight = false;
445             setRunning(true);
446         }
447     }
448 
449     /**
450      * Implements the running of the bean.
451      *
452      * It will send the Pdu, if the previous one is not still in flight.
453      * 
454      * @see SNMPRunBean#isRunning()
455      */
456     public void run() {
457         while (context != null && isRunning()) {
458             if (isGetNextInFlight == false) {
459                 // start the GetNext loop again
460                 isGetNextInFlight = true;
461 
462                 pduGetNext = new GetNextPdu_vec(context, NR_PORT_OID);
463                 pduGetNext.addObserver(this);
464 
465                 pduGetNext.addOid(charPortIndex);
466                 pduGetNext.addOid(charPortName);
467                 pduGetNext.addOid(charPortOperStatus);
468                 try {
469                     pduGetNext.send();
470                 } catch (PduException exc) {
471                     System.out.println("PduException " + exc.getMessage());
472                 } catch (IOException exc) {
473                     System.out.println("IOException " + exc.getMessage());
474                 }
475             }
476 
477             try {
478                 Thread.sleep(interval);
479             } catch (InterruptedException ix) {
480                 ;
481             }
482         }
483     }
484 
485     /**
486      * This method is called when the Pdu response is received. When all
487      * answers are received it will fire the property change event.
488      *
489      */
490     public void update(Observable obs, Object ov) {
491         boolean loopHasEnded = false;
492 
493         if (obs instanceof GetNextPdu_vec) {
494             int portIndex, portStatus;
495             String portName;
496 
497             varbind[] var;
498             pduGetNext = (GetNextPdu_vec) obs;
499 
500             if (pduGetNext.isTimedOut() == false) {
501                 if (pduGetNext.getErrorStatus() == AsnObject.SNMP_ERR_NOERROR) {
502                     var = (varbind[]) ov;
503                     if (var[0].getOid().toString().startsWith(charPortIndex)) {
504                         portIndex = ((AsnInteger) var[0].getValue()).getValue();
505                         portName = ((AsnOctets) var[1].getValue()).getValue();
506                         portStatus = ((AsnInteger) var[2].getValue()).getValue();
507 
508                         Long indexInt = new Long(portIndex);
509                         if (portStatus == portUP) {
510                             // I've found a port that has status up
511                             // Store it for later use.
512 
513                             PortInfo pStatus = (PortInfo) modemHash.get(indexInt);
514 
515                             if (pStatus == null) {
516                                 pStatus = new PortInfo(portIndex, portName, this);
517                                 modemHash.put(indexInt, pStatus);
518                             }
519 
520                             // Now I have to find out its sigState
521                             String oid = rs232InSigState + "." + String.valueOf(portIndex)
522                                     + "." + String.valueOf(DCD);
523 
524                             try {
525                                 GetPdu pduGet = new GetPdu(context);
526                                 pduGet.addOid(oid);
527                                 pduGet.addObserver(this);
528                                 pduGet.send();
529                             } catch (PduException exc) {
530                                 System.out.println("PduException " + exc.getMessage());
531                             } catch (IOException exc) {
532                                 System.out.println("IOException " + exc.getMessage());
533                             }
534                         } else {
535                             // This port is not up, remove it from our info
536 
537                             modemIndexStatusHash.remove(indexInt);
538                             modemHash.remove(indexInt);
539                         }
540 
541                         // ask for the next modem
542                         pduGetNext = new GetNextPdu_vec(context, NR_PORT_OID);
543                         pduGetNext.addObserver(this);
544 
545                         pduGetNext.addOid(var[0].getOid().toString());
546                         pduGetNext.addOid(var[1].getOid().toString());
547                         pduGetNext.addOid(var[2].getOid().toString());
548                         try {
549                             pduGetNext.send();
550                         } catch (PduException exc) {
551                             System.out.println("PduException " + exc.getMessage());
552                         } catch (IOException exc) {
553                             System.out.println("IOException " + exc.getMessage());
554                         }
555                     } else {
556                         loopHasEnded = true;
557                     }
558                 } else {
559                     // Actually the loop is ended when
560                     // we have all the responses from pduGet's. Since I
561                     // cannot control that, I do it this way.
562 
563                     loopHasEnded = true;
564                 }
565             } else {
566                 modemIndexStatusHash.clear();
567                 modemHash.clear();
568                 loopHasEnded = true;
569             }
570         } else if (obs instanceof GetPdu) {
571             GetPdu pduGet = (GetPdu) obs;
572             if (pduGet.getErrorStatus() == AsnObject.SNMP_ERR_NOERROR) {
573                 varbind var = (varbind) ov;
574 
575                 AsnObjectId oid = var.getOid();
576                 int sigStatus = ((AsnInteger) var.getValue()).getValue();
577 
578                 // the index is the one-but-last element in the OID
579                 int len = oid.getSize();
580                 long portIndex = oid.getElementAt(len - 2);
581 
582                 Long indexInt = new Long(portIndex);
583                 modemIndexStatusHash.put(indexInt,
584                         new Integer(sigStatus));
585 
586                 PortInfo pStatus = (PortInfo) modemHash.get(indexInt);
587 
588                 if (pStatus != null) {
589                     pStatus.setStatus(sigStatus);
590                 }
591             }
592         }
593 
594         if (loopHasEnded) {
595             lastUpdateDate = new Date();
596             javax.swing.SwingUtilities.invokeLater(new TreeUpdate());
597             isGetNextInFlight = false;
598         }
599 
600     }
601 
602     /**
603      * Sets the parent for this TreeNode. If the parent is not set, this
604      * class should be the root of the TreeModel.
605      */
606     public void setParent(TreeNode p) {
607         parent = p;
608     }
609 
610     /**
611      * Sets the DefaultTreeModel for this TreeNode. The tree model is used
612      * for notifying when any of the nodes were added, removed or changed.
613      */
614     public void setDefaultTreeModel(DefaultTreeModel model) {
615         treeModel = model;
616     }
617 
618     /**
619      * Fire the property event.
620      *
621      * @see
622      *      DefaultTreeModel#nodeStructureChanged
623      */
624     protected void fireTreeModelChanged() {
625         if (treeModel != null) {
626             treeModel.nodeStructureChanged(this);
627         }
628     }
629 
630     class PortInfo extends Object implements TreeNode {
631         private TreeNode parent;
632         private int portIndex, sigStatus;
633         private String portName;
634 
635         public PortInfo(int ind, String nm, TreeNode par) {
636             this(ind, 0, nm, par);
637         }
638 
639         public PortInfo(int ind, int st, String nm, TreeNode par) {
640             portIndex = ind;
641             sigStatus = st;
642             portName = nm;
643             parent = par;
644         }
645 
646         public int getIndex() {
647             return portIndex;
648         }
649 
650         public int getStatus() {
651             return sigStatus;
652         }
653 
654         public void setStatus(int st) {
655             sigStatus = st;
656         }
657 
658         public String getName() {
659             return portName;
660         }
661 
662         public String toString() {
663             return "" + portIndex + " " + portName + " " + sig_state[sigStatus];
664         }
665 
666         /**
667          * Returns the children of the reciever as an Enumeration.
668          */
669         public Enumeration children() {
670             return null;
671         }
672 
673         /**
674          * Returns the number of children <code>TreeNode</code>s the receiver
675          * contains.
676          */
677         public int getChildCount() {
678             return 0;
679         }
680 
681         /**
682          * Returns the child <code>TreeNode</code> at index
683          * <code>childIndex</code>.
684          */
685         public TreeNode getChildAt(int childIndex) {
686             return null;
687         }
688 
689         /**
690          * Returns the index of <code>node</code> in the receivers children.
691          * If the receiver does not contain <code>node</code>, -1 will be
692          * returned.
693          */
694         public int getIndex(TreeNode node) {
695             return -1;
696         }
697 
698         /**
699          * Returns the parent <code>TreeNode</code> of the receiver.
700          */
701         public TreeNode getParent() {
702             return parent;
703         }
704 
705         /**
706          * Returns true if the receiver allows children.
707          */
708         public boolean getAllowsChildren() {
709             return true;
710         }
711 
712         /**
713          * Returns true if the receiver is a leaf.
714          */
715         public boolean isLeaf() {
716             return true;
717         }
718 
719     } // end class PortInfo
720 
721     class TreeUpdate implements Runnable {
722         public void run() {
723             fireTreeModelChanged();
724             firePropertyChange("modems", null, null);
725         }
726     }
727 
728 }