View Javadoc
1   // NAME
2   //      $RCSfile: NcdPerfDataBean.java,v $
3   // DESCRIPTION
4   //      [given below in javadoc format]
5   // DELTA
6   //      $Revision: 1.12 $
7   // CREATED
8   //      $Date: 2006/01/17 17:43:53 $
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  import java.awt.*;
54  import java.util.*;
55  import java.text.*;
56  import java.lang.*;
57  import java.io.*;
58  import java.beans.*;
59  
60  /**
61   * <p>
62   * This bean collects information about a 
63   * <a href="http://www.pc.ibm.com/networkstation/">IBM Network Computer</a>. 
64   * </p>
65   *
66   * <p>
67   * It provide the following data:
68   * </p>
69   * <ul>
70   * <li> the speed of the Ethernet Card </li>
71   * <li> the available memory in bytes </li>
72   * <li> the name of the user that is logged in </li>
73   * </ul>
74   *
75   * <p>
76   * A message will be set if some of the data is not available
77   * </p>
78   *
79   * <p>
80   * This class uses the NCDware v3.2 MIB, which was very kindly provided
81   * to me by <a href="http://www.ncd.com/">Network Computing Devices, inc
82   * (NCD)</a>. This MIB is an extention of the older versions of the 
83   * <a href="ftp://ftp.ncd.com/pub/ncd/Archive/NCD-Articles/NCD_X_Terminals/SNMP/3.3.2/mib.my">MIB</a>
84   * </p>
85   *
86   * <p>
87   * The properties in the parent classes should be set, before calling
88   * the action() method. Via a PropertyChangeEvent the application/applet
89   * will be notified.
90   * </p>
91   *
92   * @see SNMPBean#setHost
93   * @see SNMPBean#setPort
94   * @see SNMPBean#setCommunityName
95   * @see #setUpdateInterval(int)
96   * @see #setUpdateInterval(String)
97   * @see SNMPBean#addPropertyChangeListener
98   * @see SNMPBean#action
99   * 
100  * @author <a href="mailto:snmp@westhawk.co.uk">Birgit Arkesteijn</a>
101  * @version $Revision: 1.12 $ $Date: 2006/01/17 17:43:53 $
102  */
103 public class NcdPerfDataBean extends SNMPBean
104         implements PropertyChangeListener {
105     private static final String version_id = "@(#)$Id: NcdPerfDataBean.java,v 1.12 2006/01/17 17:43:53 birgit Exp $ Copyright Westhawk Ltd";
106 
107     /**
108      * Used as propertyName when a propertyChangeEvent is fired because
109      * the speed was updated
110      */
111     public final static String speedPropertyName = "Speed";
112 
113     /**
114      * Used as propertyName when a propertyChangeEvent is fired because
115      * the memory was updated
116      */
117     public final static String memoryPropertyName = "Memory";
118 
119     /**
120      * Used as propertyName when a propertyChangeEvent is fired because
121      * the user name was updated
122      */
123     public final static String userPropertyName = "User";
124 
125     /**
126      * Used as propertyName when a propertyChangeEvent is fired because
127      * a message was set
128      */
129     public final static String messagePropertyName = "Message";
130 
131     /**
132      * Used as name when no one is logged in.
133      */
134     public final static String noLogin = "no one is logged in";
135 
136     /**
137      * Used as name when the name is not available.
138      */
139     public final static String noName = "not available";
140 
141     private ethernet ethernetData;
142     private user userData;
143     private memory memoryData;
144 
145     private Date lastUpdateDate = null;
146 
147     private int interval = 3000;
148     private long speed = -1;
149     private long memoryAvail = -1;
150     private String userName = "";
151 
152     /**
153      * The default constructor.
154      */
155     public NcdPerfDataBean() {
156     }
157 
158     /**
159      * Returns the speed (bits per second) of the ethernet card interface.
160      * 
161      * @return the speed (b/s)
162      */
163     public long getSpeed() {
164         return speed;
165     }
166 
167     /**
168      * Returns the amount of RAM memory in bytes which is
169      * currently available.
170      *
171      * @return the memory in bytes
172      */
173     public long getMemory() {
174         return memoryAvail;
175     }
176 
177     /**
178      * Returns the login name of the user that is logged in.
179      *
180      * @return the user name
181      * @see #noLogin
182      * @see #noName
183      */
184     public String getUserName() {
185         return userName;
186     }
187 
188     /**
189      * Returns the update interval. This is the interval that the
190      * bean will sleep between 2 requests.
191      *
192      * @return the update interval in msec
193      * @see #setUpdateInterval(int)
194      * @see #setUpdateInterval(String)
195      */
196     public int getUpdateInterval() {
197         return interval;
198     }
199 
200     /**
201      * Sets the update interval. This is the interval that the
202      * bean will sleep between 2 requests.
203      * The default will be <em>3000</em> (= 3 sec).
204      *
205      * @param i the interval in msec
206      * @see #getUpdateInterval
207      * @see #setUpdateInterval(String)
208      */
209     public void setUpdateInterval(int i) {
210         if (interval != i) {
211             interval = i;
212         }
213     }
214 
215     /**
216      * Sets the update interval as String.
217      *
218      * @param i the interval in msec as String
219      * @see #getUpdateInterval
220      * @see #setUpdateInterval(int)
221      */
222     public void setUpdateInterval(String i) {
223         int iNo;
224         try {
225             iNo = Integer.valueOf(i.trim()).intValue();
226             setUpdateInterval(iNo);
227         } catch (NumberFormatException exp) {
228         }
229     }
230 
231     /**
232      * Returns the date of the moment when this bean was last updated.
233      * This might be null when the first time the update was not finished.
234      *
235      * @return the last update date
236      */
237     public Date getLastUpdateDate() {
238         return lastUpdateDate;
239     }
240 
241     /**
242      * This method starts sending the SNMP request. All properties should be
243      * set before this method is called.
244      *
245      * The actual sending will take place in the run method.
246      * It makes a new snmp context and initialises all variables before
247      * starting.
248      */
249     public void action() {
250         if (isHostPortReachable()) {
251             lastUpdateDate = new Date();
252 
253             if (ethernetData != null) {
254                 ethernetData.setRunning(false);
255             }
256             if (userData != null) {
257                 userData.setRunning(false);
258             }
259             if (memoryData != null) {
260                 memoryData.setRunning(false);
261             }
262             ethernetData = new ethernet(host, port, community, interval, context);
263             userData = new user(host, port, community, interval, context);
264             memoryData = new memory(host, port, community, interval, context);
265 
266             ethernetData.addPropertyChangeListener(this);
267             userData.addPropertyChangeListener(this);
268             memoryData.addPropertyChangeListener(this);
269         }
270     }
271 
272     protected void setMessage(String st) {
273         message = st;
274         firePropertyChange(NcdPerfDataBean.messagePropertyName,
275                 null, message);
276     }
277 
278     /**
279      * This method is called when a new value of the speed, memory, user or
280      * message is available. It will propagate this event to any listeners.
281      *
282      * @see #speedPropertyName
283      * @see #memoryPropertyName
284      * @see #userPropertyName
285      * @see #messagePropertyName
286      */
287     public void propertyChange(PropertyChangeEvent e) {
288         Object src = e.getSource();
289         Object oldV = e.getOldValue();
290         Object newV = e.getNewValue();
291         String propName = e.getPropertyName();
292 
293         if (propName.equals(messagePropertyName)) {
294             setMessage((String) newV);
295         } else {
296             if (src == ethernetData) {
297                 speed = ((Long) newV).longValue();
298             } else if (src == userData) {
299                 userName = (String) newV;
300             } else if (src == memoryData) {
301                 memoryAvail = ((Long) newV).longValue();
302             }
303 
304             firePropertyChange(e.getPropertyName(), oldV, newV);
305         }
306     }
307 
308 }
309 
310 /**
311  * <p>
312  * This class is the super class of the classes ethernet, user and
313  * memory.
314  * </p>
315  *
316  * @see user
317  * @see ethernet
318  * @see memory
319  */
320 abstract class ncdPart extends SNMPRunBean {
321     Thread me;
322     protected boolean isPduInFlight;
323 
324     public abstract void doPdu()
325             throws PduException, IOException;
326 
327     public ncdPart(String h, int p, String c, int i, SnmpContext con) {
328         // reuse the context of the NcdPrefData class, so do not call
329         // isHostPortReachable() !
330         context = con;
331         setHost(h);
332         setPort(p);
333         setCommunityName(c);
334         setUpdateInterval(i);
335 
336         action();
337     }
338 
339     protected void setMessage(String st) {
340         message = st;
341         firePropertyChange(NcdPerfDataBean.messagePropertyName,
342                 null, message);
343     }
344 
345     public void action() {
346         setRunning(true);
347     }
348 
349     /**
350      *
351      * @see SNMPRunBean#isRunning()
352      */
353     public void run() {
354         while (context != null && isRunning()) {
355             if (isPduInFlight == false) {
356                 isPduInFlight = true;
357                 try {
358                     doPdu();
359                 } catch (PduException exc) {
360                     System.out.println("PduException " + exc.getMessage());
361                 } catch (IOException exc) {
362                     System.out.println("IOException " + exc.getMessage());
363                 }
364             }
365 
366             try {
367                 Thread.sleep(interval);
368             } catch (InterruptedException ix) {
369                 ;
370             }
371         }
372     }
373 
374 }
375 
376 /**
377  * <p>
378  * This class collects information about the ethernet card.
379  * </p>
380  *
381  * <p>
382  * The first time it will search the interface table to find the entry
383  * describing the ethernet card. After it has been found, it will ask
384  * for the information to calculate the speed.
385  * </p>
386  *
387  * <p>
388  * If the ethernet card is not found, this class assumes that it is not
389  * available at all, and will not try again.
390  * </p>
391  *
392  * @see user
393  * @see memory
394  */
395 class ethernet extends ncdPart implements Observer {
396     private final static int ethernetType = 6;
397     private final static int statusUp = 1;
398 
399     private final static String sysUpTime = "1.3.6.1.2.1.1.3.0";
400     private final static String ifIndex = "1.3.6.1.2.1.2.2.1.1";
401     private final static String ifType = "1.3.6.1.2.1.2.2.1.3";
402     private final static String ifOperStatus = "1.3.6.1.2.1.2.2.1.8";
403     private final static String ifInOctets = "1.3.6.1.2.1.2.2.1.10";
404     private final static String ifOutOctets = "1.3.6.1.2.1.2.2.1.16";
405 
406     private long speed = -1;
407     private long prevSpeed = -1;
408     private long prevSys = -1;
409     private int prevOper = -1;
410     private long prevInO = -1;
411     private long prevOutO = -1;
412     private int index = -1;
413 
414     GetNextPdu_vec typePdu;
415     GetPdu_vec ethernetPdu;
416 
417     private boolean first = true;
418     private boolean foundEthernet = false;
419 
420     public ethernet(String h, int p, String c, int i, SnmpContext con) {
421         super(h, p, c, i, con);
422         first = true;
423         foundEthernet = false;
424 
425         speed = -1;
426         prevSpeed = -1;
427         prevSys = -1;
428         prevOper = -1;
429         prevInO = -1;
430         prevOutO = -1;
431     }
432 
433     public long getSpeed() {
434         return speed;
435     }
436 
437     public void doPdu() throws PduException, IOException {
438         if (first) {
439             // first go looking which interface is the ethernet one
440             typePdu = new GetNextPdu_vec(context, 2);
441             typePdu.addObserver(this);
442             typePdu.addOid(ifIndex);
443             typePdu.addOid(ifType);
444             typePdu.send();
445 
446             first = false;
447         } else if (foundEthernet) {
448             ethernetPdu = new GetPdu_vec(context, 5);
449             ethernetPdu.addObserver(this);
450             ethernetPdu.addOid(sysUpTime);
451             ethernetPdu.addOid(ifType + "." + index);
452             ethernetPdu.addOid(ifOperStatus + "." + index);
453             ethernetPdu.addOid(ifInOctets + "." + index);
454             ethernetPdu.addOid(ifOutOctets + "." + index);
455             ethernetPdu.send();
456         }
457     }
458 
459     public void update(Observable obs, Object ov) {
460         varbind[] vars;
461 
462         if (obs == typePdu) {
463             if (typePdu.getErrorStatus() == AsnObject.SNMP_ERR_NOERROR) {
464                 vars = (varbind[]) ov;
465                 if (vars[0].getOid().toString().startsWith(ifIndex)) {
466                     int i = ((AsnInteger) vars[0].getValue()).getValue();
467                     int t = ((AsnInteger) vars[1].getValue()).getValue();
468 
469                     if (t == ethernetType) {
470                         // found it!
471                         index = i;
472                         foundEthernet = true;
473                         isPduInFlight = false;
474                     } else {
475                         // not found it, ask for the next one
476                         typePdu = new GetNextPdu_vec(context, 2);
477                         typePdu.addObserver(this);
478                         typePdu.addOid(vars[0]);
479                         typePdu.addOid(vars[1]);
480                         try {
481                             typePdu.send();
482                         } catch (PduException exc) {
483                             System.out.println("PduException " + exc.getMessage());
484                         } catch (IOException exc) {
485                             System.out.println("IOException " + exc.getMessage());
486                         }
487                     }
488                 } else {
489                     setMessage("Ethernet interface not available!");
490                 }
491             } else {
492                 setMessage("Ethernet interface not available!");
493             }
494         } else {
495             speed = -1;
496             int oper = -1;
497             if (ethernetPdu.getErrorStatus() == AsnObject.SNMP_ERR_NOERROR) {
498                 vars = (varbind[]) ov;
499 
500                 long sys = ((AsnUnsInteger) vars[0].getValue()).getValue();
501                 int t = ((AsnInteger) vars[1].getValue()).getValue();
502                 oper = ((AsnInteger) vars[2].getValue()).getValue();
503                 long inO = ((AsnUnsInteger) vars[3].getValue()).getValue();
504                 long outO = ((AsnUnsInteger) vars[4].getValue()).getValue();
505 
506                 if (t == ethernetType) {
507                     if (oper == statusUp && prevOper == statusUp) {
508                         long tdif = (sys - prevSys);
509                         if (tdif != 0) {
510                             speed = ((inO - prevInO) + (outO - prevOutO))
511                                     / tdif * 100;
512 
513                             firePropertyChange(NcdPerfDataBean.speedPropertyName,
514                                     new Long(prevSpeed),
515                                     new Long(speed));
516                         }
517                     }
518 
519                     prevSys = sys;
520                     prevInO = inO;
521                     prevOutO = outO;
522                 } else {
523                     // the index has changed, start searching again
524                     first = true;
525                     foundEthernet = false;
526                 }
527             }
528             prevSpeed = speed;
529             prevOper = oper;
530 
531             isPduInFlight = false;
532         }
533     }
534 
535 }
536 
537 /**
538  * <p>
539  * This class collects information about the user that is logged in.
540  * </p>
541  *
542  * <p>
543  * The first time it will search the NCD environment table to find the
544  * entry describing the environment variable USER. After it has been found,
545  * it will ask for the information to calculate the speed.
546  * </p>
547  *
548  * <p>
549  * When it cannot be found, it will try to see the difference between
550  * the situation where nobody is logged in and the situation where such
551  * information will never be avaible since it does not concern a NCD.
552  * </p>
553  *
554  * <p>
555  * It is not so easy as it may seem. If the machine is shut off, it seem
556  * if the machine is not a NCD.
557  * </p>
558  *
559  * @see ethernet
560  * @see memory
561  */
562 class user extends ncdPart implements Observer {
563     private final static String USER = "USER";
564 
565     private final static String ncdPrefEnvVarTableIndex = "1.3.6.1.4.1.82.2.3.15.54.1.1";
566     private final static String ncdPrefEnvVarTableName = "1.3.6.1.4.1.82.2.3.15.54.1.2";
567     private final static String ncdPrefEnvVarTableValue = "1.3.6.1.4.1.82.2.3.15.54.1.3";
568 
569     private int index = -1;
570     private String name = "";
571     private String prevName = "";
572 
573     GetNextPdu_vec namePdu;
574     GetPdu_vec userPdu;
575 
576     private boolean first = true;
577     private boolean isNcd = false;
578     private boolean foundUser = false;
579 
580     public user(String h, int p, String c, int i, SnmpContext con) {
581         super(h, p, c, i, con);
582         first = true;
583         isNcd = false;
584         foundUser = false;
585 
586         userPdu = null;
587         name = "";
588         prevName = "";
589     }
590 
591     public String getUserName() {
592         return name;
593     }
594 
595     public void doPdu() throws PduException, IOException {
596         if (first
597                 ||
598                 (isNcd && !foundUser)) {
599             // first go looking which interface is the ethernet one
600             namePdu = new GetNextPdu_vec(context, 3);
601             namePdu.addObserver(this);
602             namePdu.addOid(ncdPrefEnvVarTableIndex);
603             namePdu.addOid(ncdPrefEnvVarTableName);
604             namePdu.addOid(ncdPrefEnvVarTableValue);
605             namePdu.send();
606 
607             first = false;
608         } else if (foundUser) {
609             userPdu = new GetPdu_vec(context, 3);
610             userPdu.addObserver(this);
611             userPdu.addOid(ncdPrefEnvVarTableIndex + "." + index);
612             userPdu.addOid(ncdPrefEnvVarTableName + "." + index);
613             userPdu.addOid(ncdPrefEnvVarTableValue + "." + index);
614             userPdu.send();
615         }
616     }
617 
618     public void update(Observable obs, Object ov) {
619         varbind[] vars;
620 
621         if (obs == namePdu) {
622 
623             if (namePdu.getErrorStatus() == AsnObject.SNMP_ERR_NOERROR) {
624                 vars = (varbind[]) ov;
625                 if (vars[0].getOid().toString().startsWith(ncdPrefEnvVarTableIndex)) {
626                     // as soon as one response concerns the NCD environment
627                     // table, I assume it concerns a NCD machine.
628                     isNcd = true;
629 
630                     int i = ((AsnInteger) vars[0].getValue()).getValue();
631                     String n = ((AsnOctets) vars[1].getValue()).getValue();
632                     String v = "";
633                     if (vars[2].getValue() instanceof AsnOctets) {
634                         v = ((AsnOctets) vars[2].getValue()).getValue();
635                     }
636 
637                     if (n.equals(USER)) {
638                         // found it!
639                         index = i;
640                         foundUser = true;
641                         name = v;
642                         isPduInFlight = false;
643                     } else {
644                         // not found it, ask for the next one
645                         namePdu = new GetNextPdu_vec(context, 3);
646                         namePdu.addObserver(this);
647                         namePdu.addOid(vars[0]);
648                         namePdu.addOid(vars[1]);
649                         namePdu.addOid(vars[2]);
650                         try {
651                             namePdu.send();
652                         } catch (PduException exc) {
653                             System.out.println("PduException " + exc.getMessage());
654                         } catch (IOException exc) {
655                             System.out.println("IOException " + exc.getMessage());
656                         }
657                     }
658                 } else {
659                     if (isNcd) {
660                         name = NcdPerfDataBean.noLogin;
661                     } else {
662                         name = NcdPerfDataBean.noName;
663                     }
664                     if (!name.equals(prevName)) {
665                         firePropertyChange(NcdPerfDataBean.userPropertyName,
666                                 prevName, name);
667                     }
668 
669                     prevName = name;
670                     isPduInFlight = false;
671                 }
672             } else {
673                 prevName = name;
674                 isPduInFlight = false;
675             }
676         } else {
677             name = "";
678             if (userPdu.getErrorStatus() == AsnObject.SNMP_ERR_NOERROR) {
679                 vars = (varbind[]) ov;
680 
681                 int i = ((AsnInteger) vars[0].getValue()).getValue();
682                 String n = ((AsnOctets) vars[1].getValue()).getValue();
683                 String v = "";
684                 if (vars[2].getValue() instanceof AsnOctets) {
685                     v = ((AsnOctets) vars[2].getValue()).getValue();
686                 }
687 
688                 name = v;
689                 if (!name.equals(prevName)) {
690                     firePropertyChange(NcdPerfDataBean.userPropertyName,
691                             prevName, name);
692                 }
693 
694             } else {
695                 first = true;
696                 isNcd = true;
697                 foundUser = false;
698             }
699 
700             prevName = name;
701             isPduInFlight = false;
702         }
703     }
704 
705 }
706 
707 /**
708  * <p>
709  * This class collects information about the available memory.
710  * </p>
711  *
712  * <p>
713  * If this information is not available, probably because it is not a
714  * NCD machine, this class will not try again.
715  * </p>
716  *
717  * @see ethernet
718  * @see user
719  */
720 class memory extends ncdPart implements Observer {
721     private final static String ncdSysMemAvail = "1.3.6.1.4.1.82.2.1.1.2.0";
722 
723     GetPdu memoryPdu;
724     private long memory = -1;
725     private long prevMemory = -1;
726 
727     private boolean first = true;
728     private boolean isAvailable = false;
729 
730     public memory(String h, int p, String c, int i, SnmpContext con) {
731         super(h, p, c, i, con);
732 
733         first = true;
734         isAvailable = false;
735     }
736 
737     public long getMemory() {
738         return memory;
739     }
740 
741     public void doPdu() throws PduException, IOException {
742         if (first || isAvailable) {
743             memoryPdu = new GetPdu(context);
744             memoryPdu.addOid(ncdSysMemAvail);
745             memoryPdu.addObserver(this);
746             first = false;
747         }
748     }
749 
750     public void update(Observable obs, Object ov) {
751         varbind var;
752 
753         memory = -1;
754         if (memoryPdu.getErrorStatus() == AsnObject.SNMP_ERR_NOERROR) {
755             var = (varbind) ov;
756 
757             memory = ((AsnUnsInteger) var.getValue()).getValue();
758 
759             firePropertyChange(NcdPerfDataBean.memoryPropertyName,
760                     new Long(prevMemory),
761                     new Long(memory));
762 
763             isAvailable = true;
764         } else {
765             setMessage("Memory data not available!");
766         }
767         prevMemory = memory;
768         isPduInFlight = false;
769     }
770 
771 }