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 }