Tuesday, November 3, 2009

Simplified SnmpUtility class based upon SNMP4J

Due to popular request, I am posting my wrapper code or SnmpUtility based upon SNMP4J. I copy some part of this code somewhere that I could remember. So, I do apologise if I could not give the original author a proper credit.
Updated: < and > were unable to display properly so the generic is not seen properly. I wish it is fixed now.
Here is how to use it:
SnmpUtility util = new SnmpUtility(SnmpUtility.VERSION_2C, "127.0.0.1");
List<VariableBinding> vbs = util.walk("1.3.6.1.2.1.1","public");
for (VariableBinding vb : vbs) {
            System.out.println(vb.getOid() + ":=" + vb.getVariable().toString());
}
SnmpUtility.java
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.snmp4j.CommunityTarget;
import org.snmp4j.PDU;
import org.snmp4j.Snmp;
import org.snmp4j.TransportMapping;
import org.snmp4j.event.ResponseEvent;
import org.snmp4j.mp.SnmpConstants;
import org.snmp4j.smi.Address;
import org.snmp4j.smi.GenericAddress;
import org.snmp4j.smi.Integer32;
import org.snmp4j.smi.Null;
import org.snmp4j.smi.OID;
import org.snmp4j.smi.OctetString;
import org.snmp4j.smi.Variable;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.transport.DefaultTcpTransportMapping;
import org.snmp4j.transport.DefaultUdpTransportMapping;

public class SnmpUtility {

    public static int VERSION_1 = SnmpConstants.version1;
    public static int VERSION_2C = SnmpConstants.version2c;
    public static int VERSION_3 = SnmpConstants.version3;
    private int snmpVersion = SnmpUtility.VERSION_2C;
    private String host;
    private String transportProtocol = "UDP";
    private int snmpPort = 161;
    private int timeout = 3000;
    private int retry = 2;
    private Log log = LogFactory.getLog(SnmpUtility.class);

    public SnmpUtility() {
    }

    public SnmpUtility(int version) {
        this.setSnmpVersion(version);
    }

    public SnmpUtility(int version, String host) {
        this.setSnmpVersion(version);
        this.setHost(host);
    }

    /**
     * @return the snmpVersion
     */
    public int getSnmpVersion() {
        return snmpVersion;
    }

    /**
     * @param snmpVersion the snmpVersion to set
     */
    public void setSnmpVersion(int snmpVersion) {
        this.snmpVersion = snmpVersion;
    }

    /**
     * @return the host
     */
    public String getHost() {
        return host;
    }

    /**
     * @param host the host to set
     */
    public void setHost(String host) {
        this.host = host;
    }

    public Object get(OID oid, String community) {
        Object ret = null;
        TransportMapping transport;
        try {
            if (this.getTransportProtocol().equalsIgnoreCase("UDP")) {
                transport = new DefaultUdpTransportMapping();
            } else {
                transport = new DefaultTcpTransportMapping();
            }
            CommunityTarget target = new CommunityTarget();
            target.setCommunity(new OctetString(community));
            Address address = GenericAddress.parse(this.getTransportProtocol() + ":" + this.getHost() + "/" + this.getSnmpPort());
            target.setAddress(address);
            target.setVersion(this.getSnmpVersion());
            target.setTimeout(this.getTimeout());

            // create PDU
            PDU pdu = new PDU();
            pdu.setType(PDU.GET);
            pdu.addOID(new VariableBinding(oid));
            pdu.setNonRepeaters(0);

            Snmp snmp = new Snmp(transport);
            snmp.listen();

            ResponseEvent resp = snmp.send(pdu, target);
            PDU respPDU = resp.getResponse();
            Vector vbs = respPDU.getVariableBindings();
            if (vbs.size() > 0) {
                VariableBinding vb = (VariableBinding) vbs.get(0);
                ret = vb.getVariable();
            } else {
                ret = null;
            }
            snmp.close();
        } catch (Exception ex) {
            log.warn(ex.getMessage());
        }
        return ret;
    }

    public List<VariableBinding> getList(List<OID> oid_list, String community) {
        List<VariableBinding> ret = new ArrayList<VariableBinding>();
        TransportMapping transport;
        try {
            if (this.getTransportProtocol().equalsIgnoreCase("UDP")) {
                transport = new DefaultUdpTransportMapping();
            } else {
                transport = new DefaultTcpTransportMapping();
            }
            CommunityTarget target = new CommunityTarget();
            target.setCommunity(new OctetString(community));
            Address address = GenericAddress.parse(this.getTransportProtocol() + ":" + this.getHost() + "/" + this.getSnmpPort());
            target.setAddress(address);
            target.setVersion(this.getSnmpVersion());
            target.setTimeout(this.getTimeout());

            // create the PDU
            PDU pdu = new PDU();
            pdu.setType(PDU.GET);
            //put the oids you want to get
            List<VariableBinding> ivbs = new ArrayList<VariableBinding>();
            for (OID o : oid_list) {
                ivbs.add(new VariableBinding(o));
            }
            pdu.addAll(ivbs.toArray(new VariableBinding[]{}));
            pdu.setMaxRepetitions(10);
            pdu.setNonRepeaters(0);

            Snmp snmp = new Snmp(transport);
            snmp.listen();

            // send the PDU
            ResponseEvent responseEvent = snmp.send(pdu, target);
            // extract the response PDU (could be null if timed out)
            PDU responsePDU = responseEvent.getResponse();
            Vector vbs = responsePDU.getVariableBindings();
            if (vbs.size() > 0) {
                List<OID> rec_oid = new ArrayList<OID>();
                for (int i = 0; i < vbs.size(); i++) {
                    VariableBinding v = (VariableBinding) vbs.get(i);
                    if (!rec_oid.contains(v.getOid())) {
                        rec_oid.add(v.getOid());
                        ret.add((VariableBinding) vbs.get(i));
                    }
                }
            }
            snmp.close();
        } catch (Exception ex) {
            log.warn(ex.getMessage());
        }
        return ret;
    }

    public boolean set(OID oid, Variable value, String community) {
        boolean ret = false;
        TransportMapping transport;
        try {
            if (this.getTransportProtocol().equalsIgnoreCase("UDP")) {
                transport = new DefaultUdpTransportMapping();
            } else {
                transport = new DefaultTcpTransportMapping();
            }
            CommunityTarget target = new CommunityTarget();
            target.setCommunity(new OctetString(community));
            Address address = GenericAddress.parse(this.getTransportProtocol() + ":" + this.getHost() + "/" + this.getSnmpPort());
            target.setAddress(address);
            target.setVersion(this.getSnmpVersion());
            target.setTimeout(this.getTimeout());

            // create PDU
            PDU pdu = new PDU();
            pdu.setType(PDU.SET);
            pdu.add(new VariableBinding(oid, value));
            pdu.setNonRepeaters(0);

            Snmp snmp = new Snmp(transport);
            snmp.listen();

            ResponseEvent resp = snmp.set(pdu, target);
            PDU respPDU = resp.getResponse();
            if (respPDU == null) {
                log.warn("SNMP Timeout occured.");
            } else {
                Vector vbs = respPDU.getVariableBindings();
                if (vbs.size() > 0) {
                    VariableBinding vb = (VariableBinding) vbs.get(0);
                    ret = vb.isException() ? false : true;
                } else {
                    ret = false;
                }
            }
            snmp.close();
        } catch (Exception ex) {
            ex.printStackTrace();
            log.warn(ex.getMessage());
        }
        return ret;
    }

    public List<VariableBinding> walk(OID oid, String community) {
        List<VariableBinding> ret = new ArrayList<VariableBinding>();

        PDU requestPDU = new PDU();
        requestPDU.add(new VariableBinding(oid));
        requestPDU.setType(PDU.GETNEXT);

        CommunityTarget target = new CommunityTarget();
        target.setCommunity(new OctetString(community));
        Address address = GenericAddress.parse(this.getTransportProtocol() + ":" + this.getHost() + "/" + this.getSnmpPort());
        target.setAddress(address);
        target.setVersion(this.getSnmpVersion());
        target.setTimeout(this.getTimeout());

        try {
            TransportMapping transport;
            if (this.getTransportProtocol().equalsIgnoreCase("UDP")) {
                transport = new DefaultUdpTransportMapping();
            } else {
                transport = new DefaultTcpTransportMapping();
            }
            Snmp snmp = new Snmp(transport);
            transport.listen();

            boolean finished = false;

            while (!finished) {
                VariableBinding vb = null;

                ResponseEvent respEvt = snmp.send(requestPDU, target);
                PDU responsePDU = respEvt.getResponse();
                if (responsePDU != null) {
                    vb = responsePDU.get(0);
                }

                if (responsePDU == null) {
                    finished = true;
                } else if (responsePDU.getErrorStatus() != 0) {
                    finished = true;
                } else if (vb.getOid() == null) {
                    finished = true;
                } else if (vb.getOid().size() < oid.size()) {
                    finished = true;
                } else if (oid.leftMostCompare(oid.size(), vb.getOid()) != 0) {
                    finished = true;
                } else if (Null.isExceptionSyntax(vb.getVariable().getSyntax())) {
                    finished = true;
                } else if (vb.getOid().compareTo(oid) <= 0) {
                    finished = true;
                } else {
                    ret.add(vb);

                    // Set up the variable binding for the next entry.
                    requestPDU.setRequestID(new Integer32(0));
                    requestPDU.set(0, vb);
                }
            }
            snmp.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ret;
    }

    public VariableBinding getNext(OID oid, String community) {
        VariableBinding ret = null;
        TransportMapping transport;
        try {
            //create transport
            if (this.getTransportProtocol().equalsIgnoreCase("UDP")) {
                transport = new DefaultUdpTransportMapping();
            } else {
                transport = new DefaultTcpTransportMapping();
            }
            CommunityTarget target = new CommunityTarget();
            target.setCommunity(new OctetString(community));
            Address address = GenericAddress.parse(this.getTransportProtocol() + ":" + this.getHost() + "/" + this.getSnmpPort());
            target.setAddress(address);
            target.setRetries(3);
            target.setTimeout(this.getTimeout());
            target.setVersion(this.getSnmpVersion());

            // create the PDU
            PDU pdu = new PDU();
            pdu.setType(PDU.GETNEXT);
            //put the oid you want to get
            pdu.add(new VariableBinding(oid));
            pdu.setNonRepeaters(0);

            Snmp snmp = new Snmp(transport);
            snmp.listen();

            // send the PDU
            ResponseEvent responseEvent = snmp.send(pdu, target);
            // extract the response PDU (could be null if timed out)
            PDU responsePDU = responseEvent.getResponse();
            Vector vbs = responsePDU.getVariableBindings();
            if (vbs.size() > 0) {
                ret = (VariableBinding) vbs.get(0);
            }
            snmp.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return ret;
    }

    /**
     * @return the transportProtocol
     */
    public String getTransportProtocol() {
        return transportProtocol;
    }

    /**
     * @param transportProtocol the transportProtocol to set
     */
    public void setTransportProtocol(String transportProtocol) {
        this.transportProtocol = transportProtocol;
    }

    /**
     * @return the snmpPort
     */
    public int getSnmpPort() {
        return snmpPort;
    }

    /**
     * @param snmpPort the snmpPort to set
     */
    public void setSnmpPort(int snmpPort) {
        this.snmpPort = snmpPort;
    }

    /**
     * @return the timeout
     */
    public int getTimeout() {
        return timeout;
    }

    /**
     * @param timeout the timeout to set
     */
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    /**
     * @return the retry
     */
    public int getRetry() {
        return retry;
    }

    /**
     * @param retry the retry to set
     */
    public void setRetry(int retry) {
        this.retry = retry;
    }
}

Wednesday, October 28, 2009

Workaround on installing Android SDK 2.0 behind proxy requiring authentication

This morning I tried to install Android SDK 2.0 on my Ubuntu desktop. I downloaded the package with my browser without any problem. Extract it and then run tools/android to download the packages. Realising that my desktop requires a proxy which requires authentication to get to the Net, I went to the Settings panel of the Android SDK and AVD. There are only proxy host and port entries, no username and password entries. I was hoping that the software is smart enough to prompt for username and password later. However, I was wrong. It did not prompt me any authentication form whatsoever. Bummer...... Then I got an idea. I remember few months ago when I set up a forwarding only proxy to act as a child of a parent proxy. I thought if I could get this child proxy to authenticate to the parent proxy and forward all request to the parent proxy, the user won't need to authenticate at all. Hmmm.... Looking at the manual of squid http proxy, I saw cache_peer option which enable child proxy to login to the parent proxy by specifying login=username:password. Yummy.... So, I fired up the trusty apt-get to pull and install squid from my local repository.
$ sudo apt-get install squid
$ sudo vi /etc/squid/squid.conf
Then I added the following setting:
cache_peer parent_proxy.company.domain parent 8080 0 no-query default login=username:password
never_direct allow all
Then I restart squid
$ sudo /etc/init.d/squid stop
$ sudo /etc/init.d/squid start
Then I pointed the Android SDK and AVD to use 127.0.0.1 and port 3128. I also set the software to force downloading using http even if the URL is in https. Finger cross and I tick the site and click Refresh. Viola... it works. It is downloading as I write this blog entries.

Wednesday, September 23, 2009

Mass sending SMS using gnokii

During certain period within a year, we might have to send text messages (festivity greeting) to several friends for example during religious holiday season. Well, writing one template and re-sending text messages through your mobile phone might be OK for 5 or 10 numbers. How about if you have to reply 25 to 50 text messages? Sore thumb :) Gnokii is very good at sending SMS via a GSM/3G/HSDPA modem or GSM phone acting as a modem. The command for sending SMS is simple as long as you have specified a correct device on /etc/gnokiirc. I am using a USB HSDPA modem (Bandluxe C120) so the only changes I made on the /etc/gnokiirc is:
port = /dev/ttyUSB0
model = AT
In order to send mass SMS, I created three files:
template.txt : the message to send no more than 160 characters long.  
phones.txt   : containing the list of phone number the text need to send to
send.sh      : The script
Here is the example content of the template.txt:
Happy holiday, God bless you.
This is the example of the phones.txt:
+6281100000
+6281100001
Now,the send.sh script:
#!/bin/sh
SMSC="+6281100000"
MSG=`cat template.txt`
for i in `cat phones.txt`; do
 echo "$MSG" | gnokii --sendsms $i --smsc $SMSC
done
Some SIM cards do not set the SMS Center number correctly thus sometimes it does not work. In order to avoid failures, we must specify the SMSC correctly. In my case, I use Telkomsel and the SMSC number is +6281100000. Now, change permission of the script to be executable and execute it. e.g.
[user@host dir]$ chmod 755 send.sh
[user@host dir]$ ./send.sh
You should see some messages scrolling informing whether the process successful or not. Now, no more sore thumb and sore eyes having to write and send SMS from your tiny mobile phone screen.

Thursday, July 9, 2009

Opennms build failed due to xerces problem (affecting 1.6.x)

For some of you who may have tried building opennms from scratch, you may find a problem where build failed due to xerces dependencies could not be found. Based on several post that I have read, it is due to the relocation of the files. Well, the simples work around to that is to install xerces-1.4.0.jar into your local maven repository. This is the syntax command to do that:

mvn install:install-file -Dfile= -DgroupId= \
    -DartifactId= -Dversion= -Dpackaging=

In a more detail way:
1. Download xerces-1.4.0.jar from your favorite maven repository such as ibiblio.
2. Go to the folder where you save xerces-1.4.0.jar
3. Execute the following command:

mvn install:install-file -Dfile=xerces-1.4.0.jar -DgroupId=xerces \
    -DartifactId=xerces -Dversion=1.4.0 -Dpackaging=jar

Then try again to build opennms. It should then be allright. I hope this would help anyone who encounter such problem.

Thursday, June 25, 2009

JDBC class loading failed from JAX-WS annotated class

Creating a JAX-WS based webservice either using JAX-WS RI or Apache CXF is simplified by using annotation, for example creating interface annotated with @WebService is a simple as the following:
@WebService
public interface AService {
   @WebMethod
   String getThingsFromJDBC(String key);
}
Then the interface is implemented as the following:
@WebService
public class AServiceImpl implements AService {
    @WebMethod
    public String getThingsFromJDBC(String key) {
      // some impl here
    }  
}
Then you will have your web service running in no time (if you follow the guidance provided by CXF -- let say we are using apache CXF). Now, let say we want to access JDBC based database from our implementation -- we want a light weight approach, neither Hibernate nor JPA, we usually load the driver first like:
   bool initiated = false;
   Connection connection = null;
   private void initJDBC() {
      try {
         Class.forName("oracle.jdbc.driver.OracleDriver");
         connection = DriverManager.getConnection(jdbcUrl);
         initiated = true;
      } catch (Exception ex) {
        ex.printStackTrace();
      }
   }

   public String getThingsFromJDBC(String key) {
      String ret= null;
      if (initiated && connection!=null)
      {
         // do your query here
      }
      return ret;
   }

   

It should be OK right? Not OK in some occasions, the some drivers won't be loaded such as Oracle driver. Why, there is a class loading problem. The JAX-WS webservice implementation is actually loaded by the CXFServlet below the scope of the webapplication, whereas the path of the JDBC library is only visible from web application context. Thus, your JDBC driver should be loaded by the webapplication classloader. So, how can we solve this? One of the approach I have taken was to create a separate class to deal JDBC data access, instantiate it with Spring and then inject it to the JAX-WS service implementation. Example:
public class MyJDBCAccess {
    bool initiated = false;
    Connection connection = null;
    public void init()
    {
      try {
         Class.forName("oracle.jdbc.driver.OracleDriver");
         connection = DriverManager.getConnection(jdbcUrl);
         initiated = true;
      } catch (Exception ex) {         
        ex.printStackTrace();
      }
    }

   public String doGetThingsFromJDBC(String key) {
      String ret= null;
      if (initiated && connection!=null)
      {
         // do your query here
      }
      return ret;
   }
}
In order to be wire MyJDBCAccess instant to AServiceImpl, we need to define a property for MyJDBCAccess instance. E.g add the following snippet into AServiceImpl.java:

    private MyJDBCAccess bean = null;

    public void setMyJDBCAccess(MyJDBCAccess b)
    {
       this.bean = b;
    }

    public MyJDBCAccess getMyJDBCAccess() 
    {
       return this.bean;
    }
    // we need to change the implementation of getThingsFromJDBC(String key)
    public String getThingsFromJDBC(String key) {
      String ret=null;
      try {
          ret=bean.doGetThingsFromJDBC(key);
      } catch (Exception ex) {
          // use a good logging mechanism here
          ex.printStackTrace();
      }
      return ret;
    }


Now.. how to wire it? A snippet of typical CXF webservice bean definition is like this:
<bean id="aservice" class="AServiceImpl" />

<jaxws:endpoint id="AService"
    implementor="#aservice"
    address="/a_service"/>
To inject MyJDBCAccess to aservice bean we need to define an instance of MyJDBCService like the following:
<bean id="jdbcAccess" class="MyJDBCAccess" />
<bean id="aservice" class="AServiceImpl" >
    <property name='myJDBCAccess' ref='jdbcAccess'/>
</bean>

<jaxws:endpoint id="AService"
    implementor="#aservice"
    address="/a_service"/>
Then your jdbc data access should be ok. Hope this could help someone who caught similar problem.

Wednesday, June 17, 2009

Running RMIC via ant

Netbeans, does not support RMI-based project quite well especially on generating stub files using RMIC. However, we can always tweak the build-impl.xml script to run RMIC. To generate stub files, RMIC must be executed after class compilation finished. Thus, the most appropriate place to run it is in -post-compile target. Here is a snippet on how to invoke RMIC in -post-compile target. I found this trick somewhere, but I forget where I found it.

<target name="-post-compile">
        <rmic base="${build.classes.dir}" includes="com/jbs/RMIServiceImpl.class"/>
</target>



Hope this could help someone who got problem with RMI project in Netbeans.