1 // NAME
2 // $RCSfile: DialogChannelStatusBean.java,v $
3 // DESCRIPTION
4 // [given below in javadoc format]
5 // DELTA
6 // $Revision: 1.18 $
7 // CREATED
8 // $Date: 2006/02/02 15:49:39 $
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 * author <a href="mailto:snmp@westhawk.co.uk">Tim Panton</a>
25 */
26
27 package uk.co.westhawk.snmp.beans;
28
29 /*-
30 * ╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲
31 * SNMP Java Client
32 * ჻჻჻჻჻჻
33 * Copyright 2023 MetricsHub, Westhawk
34 * ჻჻჻჻჻჻
35 * This program is free software: you can redistribute it and/or modify
36 * it under the terms of the GNU Lesser General Public License as
37 * published by the Free Software Foundation, either version 3 of the
38 * License, or (at your option) any later version.
39 *
40 * This program is distributed in the hope that it will be useful,
41 * but WITHOUT ANY WARRANTY; without even the implied warranty of
42 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
43 * GNU General Lesser Public License for more details.
44 *
45 * You should have received a copy of the GNU General Lesser Public
46 * License along with this program. If not, see
47 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
48 * ╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱╲╱
49 */
50
51 import uk.co.westhawk.snmp.stack.*;
52 import uk.co.westhawk.snmp.pdu.*;
53
54 import javax.swing.tree.*;
55 import java.awt.*;
56 import java.util.*;
57 import java.text.*;
58 import java.lang.*;
59 import java.io.*;
60 import java.beans.*;
61
62 /**
63 * <p>
64 * This bean is written for a Dialogic card.
65 *
66 * The Dialogic MIBs come with their
67 * <a
68 * href="http://support.dialogic.com/Download/boardwatch/index.htm">BoardWatch
69 * package</a>. You will have to fill in a form before downloading it.
70 *
71 * <p>
72 * This bean collects information about the voice channel status of the
73 * Dialogic card. It will only collect those channels that are open.
74 * </p>
75 *
76 * <p>
77 * You can get the data via the getChannelIndexes() and
78 * getChannelStatus(Integer index) methods. This way you can visualise
79 * the data yourself.
80 * </p>
81 *
82 * <p>
83 * You can also use the Swing JTree to visualise the channels.
84 * This bean implements the Swing TreeNode interface.
85 * The user has to set the setDefaultTreeModel, so this class can update all
86 * the nodes that are added, removed of changed.
87 * If this class is <em>not</em> the root of the JTree, you have to set
88 * the (TreeNode) parent of this class.
89 * </p>
90 *
91 * <p>
92 * The properties in the parent classes should be set, before calling
93 * the action() method. Via a TreeModelEvent the application/applet
94 * will be notified.
95 * </p>
96 *
97 * <p>
98 * We only have one (1) Dialogics card, so I don't know how and if it
99 * works with more than 1 card. Please let us know if it doesn't work.
100 * </p>
101 *
102 * @see SNMPBean#setHost
103 * @see SNMPBean#setPort
104 * @see SNMPBean#setCommunityName
105 * @see SNMPRunBean#setUpdateInterval
106 * @see SNMPBean#addPropertyChangeListener
107 * @see SNMPBean#action
108 * @see GetNextPdu_vec
109 *
110 * @author <a href="mailto:snmp@westhawk.co.uk">Birgit Arkesteijn</a>
111 * @version $Revision: 1.18 $ $Date: 2006/02/02 15:49:39 $
112 *
113 */
114 public class DialogChannelStatusBean extends SNMPRunBean
115 implements Observer, TreeNode {
116 private static final String version_id = "@(#)$Id: DialogChannelStatusBean.java,v 1.18 2006/02/02 15:49:39 birgit Exp $ Copyright Westhawk Ltd";
117
118 /**
119 * A unique value for each R4 device contained by the
120 * host. The value for each R4 device must remain
121 * constant at least from one re-initialization of the
122 * agent to the next re-initialization.
123 *
124 * See the dlgr4dev.mib.
125 */
126 public final static String dlgR4DeviceIndex = "1.3.6.1.4.1.3028.2.1.1.2.1.1.1";
127
128 /**
129 * Release 4 Device Name. This is the name the application will
130 * use when opening the device (e.g. dxxxB1C1, dtiB1T1, msiB1C1)
131 * See the dlgr4dev.mib.
132 */
133 public final static String dlgR4DeviceName = "1.3.6.1.4.1.3028.2.1.1.2.1.1.2";
134
135 /**
136 * An indication of the type of the device.
137 * <ol>
138 * <li>
139 * other - some other type of device unknown to the agent.</li>
140 * <li>
141 * voice - A voice channel device. An entry exits in the
142 * dlgR4VoiceTable for this device.</li>
143 * <li>
144 * dti - A DTI timeslot device. An entry exits in the
145 * dlgR4DTITable for this device.</li>
146 * <li>
147 * isdn - An ISDN B-Channel device. An entry exits in the
148 * dlgR4ISDNTable for this device.</li>
149 * <li>
150 * msi - An MSI station set device. An entry exits in the
151 * dlgR4MSITable for this device.</li>
152 * </ol>
153 *
154 * See the dlgr4dev.mib.
155 */
156 public final static String dlgR4DeviceType = "1.3.6.1.4.1.3028.2.1.1.2.1.1.3";
157
158 /**
159 * An indication of how many instances of this device is currently
160 * opened.
161 * See the dlgr4dev.mib.
162 */
163 public final static String dlgR4DeviceOpenCount = "1.3.6.1.4.1.3028.2.1.1.2.1.1.5";
164
165 /**
166 * Indicates current activity status on the (voice) channel.
167 * See the dlgr4dev.mib.
168 */
169 public final static String dlgR4VoiceChannelStatus = "1.3.6.1.4.1.3028.2.1.1.2.2.1.2";
170
171 private final static int NR_OID = 5;
172
173 // dlgR4DeviceType values
174 public final static int unknown = 1;
175 public final static int voice = 2;
176 public final static int dti = 3;
177 public final static int isdn = 4;
178 public final static int msi = 5;
179
180 // dlgR4VoiceChannelStatus values
181 public final static int idle = 1;
182 public final static int playing = 2;
183 public final static int recording = 3;
184 public final static int gettingDigits = 5;
185 public final static int blocked = 16;
186
187 public final static int dialing = 4;
188 public final static int playTone = 6;
189 public final static int sendingFax = 8;
190 public final static int receivingFax = 9;
191 public final static int betweenFAXPages = 10;
192 public final static int hookState = 11;
193 public final static int winking = 12;
194 public final static int callProgess = 13;
195 public final static int gettingR2MF = 14;
196
197 public final static String vch_status[] = {
198 "",
199 "Channel not active",
200 "Playing Audio Data",
201 "Recording Audio Data",
202 "Dialing Digits",
203 "Collecting DTMF digits",
204 "Playing a tone",
205 "",
206 "Sending a FAX (VFX boards)",
207 "Receiving a FAX (VFX boards)",
208 "Between FAX pages (VFX boards)",
209 "Changing hook status to onhook or offhook",
210 "Performing a wink",
211 "Performing Call progress analysis",
212 "Retrieving R2MF digits",
213 "",
214 "Blocked"
215 };
216
217 private GetNextPdu_vec pdu;
218 private Hashtable channelIndexStatusHash;
219 private Hashtable channelHash;
220
221 private TreeNode parent;
222 private DefaultTreeModel treeModel;
223
224 private boolean isGetNextInFlight;
225 private Date lastUpdateDate = null;
226
227 private int deviceType = 0;
228 private String deviceName = "";
229 private int openCount = 0;
230 private int channelStatus = 0;
231
232 /**
233 * The default constructor.
234 */
235 public DialogChannelStatusBean() {
236 channelIndexStatusHash = new Hashtable();
237 channelHash = new Hashtable();
238 }
239
240 /**
241 * The constructor that will set the host and the port no.
242 *
243 * @param h the hostname
244 * @param p the port no
245 * @see SNMPBean#setHost
246 * @see SNMPBean#setPort
247 */
248 public DialogChannelStatusBean(String h, int p) {
249 this(h, p, null);
250 }
251
252 /**
253 * The constructor that will set the host, the port no and the local
254 * bind address.
255 *
256 * @param h the hostname
257 * @param p the port no
258 * @param b the local bind address
259 * @see SNMPBean#setHost
260 * @see SNMPBean#setPort
261 * @see SNMPBean#setBindAddress
262 *
263 * @since 4_14
264 */
265 public DialogChannelStatusBean(String h, int p, String b) {
266 this();
267 setHost(h);
268 setPort(p);
269 setBindAddress(b);
270 }
271
272 /**
273 * Returns the date of the moment when this bean was last updated.
274 * This might be null when the first time the update was not finished.
275 *
276 * @return the last update date
277 */
278 public Date getLastUpdateDate() {
279 return lastUpdateDate;
280 }
281
282 /**
283 * Returns the indexes (as Integers) of the voice channels that are
284 * open. Only the open voice channels of the card are saved.
285 *
286 * Use getChannelStatus() or getChannelStatusString() to get the status
287 * of the channel.
288 *
289 * @see #getChannelStatus
290 * @see #getChannelStatusString
291 */
292 public Enumeration getChannelIndexes() {
293 return channelIndexStatusHash.keys();
294 }
295
296 /**
297 * Returns the number of voice channels in the table.
298 */
299 public synchronized int getChannelCount() {
300 return channelIndexStatusHash.size();
301 }
302
303 /**
304 * Returns the name of the channel.
305 *
306 * @param index The index of the channel
307 * @return The name
308 *
309 */
310 public String getChannelName(Integer index) {
311 String name = "";
312 Object obj = channelHash.get(index);
313 if (obj != null) {
314 ChannelStatus chSt = (ChannelStatus) obj;
315 name = chSt.getName();
316 }
317 return name;
318 }
319
320 /**
321 * Returns the status of the channel as an int.
322 *
323 * @param index The index of the channel
324 * @return The status
325 *
326 * @see #getChannelIndexes
327 */
328 public int getChannelStatus(Integer index) {
329 int status = 0;
330 Object obj = channelIndexStatusHash.get(index);
331 if (obj != null) {
332 status = ((Integer) obj).intValue();
333 }
334 return status;
335 }
336
337 /**
338 * Returns the String representation of the status of the channel.
339 *
340 * @param index The index of the channel
341 * @return The status
342 *
343 * @see #getChannelIndexes
344 */
345 public String getChannelStatusString(Integer index) {
346 int status = getChannelStatus(index);
347 String str = vch_status[status];
348 return str;
349 }
350
351 /**
352 * Returns the children of the reciever as an Enumeration.
353 */
354 public Enumeration children() {
355 return channelHash.elements();
356 }
357
358 /**
359 * Returns the number of children <code>TreeNode</code>s the receiver
360 * contains.
361 */
362 public int getChildCount() {
363 int sz = channelHash.size();
364 return sz;
365 }
366
367 /**
368 * Returns the child <code>TreeNode</code> at index
369 * <code>childIndex</code>.
370 */
371 public TreeNode getChildAt(int childIndex) {
372 TreeNode node = null;
373 if (childIndex < channelHash.size()) {
374 Enumeration e = channelHash.elements();
375 for (int i = 0; i <= childIndex; i++) {
376 node = (TreeNode) e.nextElement();
377 }
378 }
379 return node;
380 }
381
382 /**
383 * Returns the index of <code>node</code> in the receivers children.
384 * If the receiver does not contain <code>node</code>, -1 will be
385 * returned.
386 */
387 public int getIndex(TreeNode node) {
388 int ret = -1;
389 if (channelHash.contains(node)) {
390 boolean found = false;
391 Enumeration e = channelHash.elements();
392 while (e.hasMoreElements() && !found) {
393 TreeNode n = (TreeNode) e.nextElement();
394 found = (n == node);
395 ret++;
396 }
397 }
398 return ret;
399 }
400
401 /**
402 * Returns the parent <code>TreeNode</code> of the receiver.
403 */
404 public TreeNode getParent() {
405 return parent;
406 }
407
408 /**
409 * Returns true if the receiver allows children.
410 */
411 public boolean getAllowsChildren() {
412 return true;
413 }
414
415 /**
416 * Returns true if the receiver is a leaf.
417 */
418 public boolean isLeaf() {
419 return false;
420 }
421
422 /**
423 * This method starts the action of the bean. It will initialises
424 * all variables before starting.
425 */
426 public void action() {
427 if (isHostPortReachable()) {
428 lastUpdateDate = new Date();
429 isGetNextInFlight = false;
430 setRunning(true);
431 }
432 }
433
434 /**
435 * Implements the running of the bean.
436 *
437 * It will send the Pdu, if the previous one is not still in flight.
438 *
439 * @see SNMPRunBean#isRunning()
440 */
441 public void run() {
442 while (context != null && isRunning()) {
443 if (isGetNextInFlight == false) {
444 // start the GetNext loop again
445 isGetNextInFlight = true;
446
447 pdu = new GetNextPdu_vec(context, NR_OID);
448 pdu.addObserver(this);
449
450 pdu.addOid(dlgR4DeviceIndex);
451 pdu.addOid(dlgR4DeviceName);
452 pdu.addOid(dlgR4DeviceType);
453 pdu.addOid(dlgR4DeviceOpenCount);
454 pdu.addOid(dlgR4VoiceChannelStatus);
455 try {
456 pdu.send();
457 } catch (PduException exc) {
458 System.out.println("PduException " + exc.getMessage());
459 } catch (IOException exc) {
460 System.out.println("IOException " + exc.getMessage());
461 }
462 }
463
464 try {
465 Thread.sleep(interval);
466 } catch (InterruptedException ix) {
467 ;
468 }
469 }
470 }
471
472 /**
473 * This method is called when the Pdu response is received. When all
474 * answers are received it will fire the property change event.
475 *
476 */
477 public void update(Observable obs, Object ov) {
478 boolean hasEnded = false;
479 int index;
480 varbind[] var;
481
482 pdu = (GetNextPdu_vec) obs;
483
484 if (pdu.isTimedOut() == false) {
485 if (pdu.getErrorStatus() == AsnObject.SNMP_ERR_NOERROR) {
486 var = (varbind[]) ov;
487 if (var[0].getOid().toString().startsWith(dlgR4DeviceIndex)) {
488 index = ((AsnInteger) var[0].getValue()).getValue();
489 deviceName = ((AsnOctets) var[1].getValue()).getValue();
490 deviceType = ((AsnInteger) var[2].getValue()).getValue();
491 openCount = ((AsnInteger) var[3].getValue()).getValue();
492 channelStatus = ((AsnInteger) var[4].getValue()).getValue();
493
494 if (deviceType == voice) {
495 Integer indexInt = new Integer(index);
496 if (openCount == 0) {
497 channelIndexStatusHash.remove(indexInt);
498 channelHash.remove(indexInt);
499 } else {
500 channelIndexStatusHash.put(indexInt,
501 new Integer(channelStatus));
502
503 ChannelStatus cStatus = (ChannelStatus) channelHash.get(indexInt);
504
505 if (cStatus == null) {
506 cStatus = new ChannelStatus(index, channelStatus,
507 deviceName, this);
508 channelHash.put(indexInt, cStatus);
509 } else {
510 cStatus.setStatus(channelStatus);
511 }
512 }
513 }
514
515 // ask for the next channel
516 pdu = new GetNextPdu_vec(context, NR_OID);
517 pdu.addObserver(this);
518
519 pdu.addOid(var[0].getOid().toString());
520 pdu.addOid(var[1].getOid().toString());
521 pdu.addOid(var[2].getOid().toString());
522 pdu.addOid(var[3].getOid().toString());
523 pdu.addOid(var[4].getOid().toString());
524 try {
525 pdu.send();
526 } catch (PduException exc) {
527 System.out.println("PduException " + exc.getMessage());
528 } catch (IOException exc) {
529 System.out.println("IOException " + exc.getMessage());
530 }
531 } else {
532 hasEnded = true;
533 }
534 } else {
535 hasEnded = true;
536 }
537 } else {
538 channelIndexStatusHash.clear();
539 channelHash.clear();
540 hasEnded = true;
541 }
542
543 if (hasEnded) {
544 // the GetNext loop has ended
545 lastUpdateDate = new Date();
546 javax.swing.SwingUtilities.invokeLater(new TreeUpdate());
547 isGetNextInFlight = false;
548 }
549 }
550
551 /**
552 * Sets the parent for this TreeNode. If the parent is not set, this
553 * class should be the root of the TreeModel.
554 */
555 public void setParent(TreeNode p) {
556 parent = p;
557 }
558
559 /**
560 * Sets the DefaultTreeModel for this TreeNode. The tree model is used
561 * for notifying when any of the nodes were added, removed or changed.
562 */
563 public void setDefaultTreeModel(DefaultTreeModel model) {
564 treeModel = model;
565 }
566
567 /**
568 * Fire the property event.
569 *
570 * @see
571 * DefaultTreeModel#nodeStructureChanged
572 */
573 protected void fireTreeModelChanged() {
574 if (treeModel != null) {
575 treeModel.nodeStructureChanged(this);
576 }
577 }
578
579 class ChannelStatus extends Object implements TreeNode {
580 private TreeNode parent;
581 private int index, status;
582 private String name;
583
584 public ChannelStatus(int ind, int st, String nm, TreeNode par) {
585 index = ind;
586 status = st;
587 name = nm;
588 parent = par;
589 }
590
591 public int getIndex() {
592 return index;
593 }
594
595 public int getStatus() {
596 return status;
597 }
598
599 public void setStatus(int st) {
600 status = st;
601 }
602
603 public String getName() {
604 return name;
605 }
606
607 public String toString() {
608 return "" + index + " " + name + " " + vch_status[status];
609 }
610
611 /**
612 * Returns the children of the reciever as an Enumeration.
613 */
614 public Enumeration children() {
615 return null;
616 }
617
618 /**
619 * Returns the number of children <code>TreeNode</code>s the receiver
620 * contains.
621 */
622 public int getChildCount() {
623 return 0;
624 }
625
626 /**
627 * Returns the child <code>TreeNode</code> at index
628 * <code>childIndex</code>.
629 */
630 public TreeNode getChildAt(int childIndex) {
631 return null;
632 }
633
634 /**
635 * Returns the index of <code>node</code> in the receivers children.
636 * If the receiver does not contain <code>node</code>, -1 will be
637 * returned.
638 */
639 public int getIndex(TreeNode node) {
640 return -1;
641 }
642
643 /**
644 * Returns the parent <code>TreeNode</code> of the receiver.
645 */
646 public TreeNode getParent() {
647 return parent;
648 }
649
650 /**
651 * Returns true if the receiver allows children.
652 */
653 public boolean getAllowsChildren() {
654 return true;
655 }
656
657 /**
658 * Returns true if the receiver is a leaf.
659 */
660 public boolean isLeaf() {
661 return true;
662 }
663
664 } // end class ChannelStatus
665
666 class TreeUpdate implements Runnable {
667 public void run() {
668 fireTreeModelChanged();
669 firePropertyChange("modems", null, null);
670 }
671 }
672
673 }