Tuesday 31 December 2013

Java Errors: ClassNotFoundError, NoClassDefFoundError, UnsupportedClassVersionError, LinkageError, ClassFormatError

As per JVM's parent-delegation class loading model a class can be loaded by either a bootstrap class loader or user defined class loader. During class loading the virtual machine can throw following errors and for the given reasons:
  • NoClassDefFoundError
    • If bootstrap class loader is directly invoked by the virtual machine and it is unable to load the binary data for the requested type.
  • ClassNotFoundError
    • If a user-defined class loader delegates to the bootstrap class loader or to a user-defined class loader which is then unable to load the binary data for the requested type, then the ClassNotFoundError is thrown. 

  • ClassFormatError
    •  If the class is located or produced but not in a proper structure
    • If the class does not contain a superclass and is not class Object.
  •  UnsupportedClassVersionError
    • If the binary data is produced but is not part of a recognized version.
  • LinkageError
    • If class name already appears in the current class loader's name space.

Difference between forName() and loadClass() Java API methods

A Java program can be dynamically extended by using following two APIs:

  1. The forName() method of java.lang.Class class, or
  2. The loadClass() method of an instance of a user-defined class loader.

The forName() method has two overloaded signatures:

  1. public static Class<?>  forName(String className) throws ClassNotFoundException
    • Returns the Class object associated with the class or interface with the given string name.
  2. public static Class<?>  forName(String name, boolean initialize, ClassLoader loader) throws ClassNotFoundException
    • Returns the Class object associated with the class or interface with the given string name, using the given class loader. The class will be initialized if the parameter is true, and if it has not been initialized earlier. If loader parameter is passed as null then it means request is to load class from bootstrap class loader.

The loadClass() method has two overloaded signatures:

  1. public Class<?>   loadClass(String name) throws ClassNotFoundException
    • Loads the class with the specified binary name. If the class is already loaded then it returns the Class instance representing that already-loaded type. If not then is loaded via some customized way decided by the user-defined class loader.
  2. protected Class<?>  loadClass(String name, boolean resolve) throws ClassNotFoundException
    • Loads the class with the specified binary name. The resolve parameter indicates whether or not the type should be linked as well loaded. 

Now it should be clear whether you should use forName() or loadClass(); as it depends on your need; if you have no special needs which requires class loader, you should use forName(); also when you want class to be initialized use forName() with right signature. Class loaders can help you have some custom way of loading types, such as by downloading them across a network, retrieve from a DB, from an encrypted file, or even generating them on the fly.

Initialization is the reason, for example, why JDBC drivers generally loaded with a call to forName(). Because the static initializers of driver class register the driver with a DriverManager.

Note: 

Linking process involves three steps: 
  1. verification of the loaded type; 
  2. preparation, which involves allocating more memory for the type; and
  3. optionally, resolution of symbolic references contained into the type.

Saturday 23 November 2013

Java 7 Performance Issue with XMLEncoder/XMLDecoder classes

Objective

To demonstrate Java 7 performance issue with XMLEncoder/XMLDecoder classes.

Environment

 JDK 7  or JRE 7

Issue

 If you have used XMLEncoder and XMLDecoder classes in your application and moved to Java 7 from Java 5 or 6 then it is worth notice the performance degrade in your application.
The following program can be run in different Java version and performance difference can be observed:

Program:
import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

import javax.swing.JButton;

public class TestXMLEncode {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception {
        XMLEncoder e = new XMLEncoder(new BufferedOutputStream(
                new FileOutputStream("Test1.xml")));
        e.writeObject(createObject());
        e.close();

        if (args.length > 0) {
            xmlSize = Integer.parseInt(args[0]);
        }

        if (args.length > 1) {
            numThread = Integer.parseInt(args[1]);
        }

        System.out.println("Size: " + xmlSize + ", Threads: " + numThread);

        for (int i = 0; i < 10; i++) {
            run();
        }
    }

    static int numThread = 1;
    static int xmlSize = 100;

    static Object createObject() {
        JButton[] o = new JButton[xmlSize];
        for (int i = 0;i < o.length; i++) {
            o[i] = new JButton("Hello, world");
        }
        return o;
    }

    static void run() {
        final long start = System.currentTimeMillis();
        final Object o = createObject();

        ExecutorService executorService = Executors.newFixedThreadPool(numThread);

        try {
            List<Callable<Object>> tasks = new ArrayList<Callable<Object>>();
            for (int i = 0; i < 2000 / xmlSize; i++) {
                tasks.add(new Callable() {
                    public Object call() {
                        byte[] data = encode(o);
                        decode(data);
                        return null;
                    }
                });
            }
            executorService.invokeAll(tasks);

            System.out.println("Finished: " + (System.currentTimeMillis() - start) + " ms");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static byte[] encode(Object o) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            XMLEncoder e = new XMLEncoder(bos);
            e.writeObject(o);
            e.close();

            return bos.toByteArray();
        } catch (Exception e1) {
            throw new RuntimeException(e1);
        }
    }

    private static void decode(byte[] data) {
        try {
            ByteArrayInputStream bis = new ByteArrayInputStream(data);
            XMLDecoder d = new XMLDecoder(bis);

            d.readObject();
            d.close();
        } catch (Exception e1) {
            throw new RuntimeException(e1);
        }
    }

}

Test1.xml
<?xml version="1.0" encoding="UTF-8"?>
<java version="1.7.0-u40-unofficial" class="java.beans.XMLDecoder">
 <object class="javax.swing.JButton">
  <string>Hello, world</string>
 </object>
</java>

Observation

We have also faced thread hung issue by moving to Java 7 and observed that a thread hungs at XMLEncoder class causing other many thread to be blocked at XMLEncoder/XMLDecoder calls.
We have opened a ticket with Oracle and they did acknowledge the issue, and probably they will fix this issue with some patch or so.

Thank You!

Friday 25 October 2013

Java XMLEncoder issue with java.sql.Timestamp in JDK 5 and 6

Objective

To highlight XMLEncoder class issue with java.sql.Timestamp class in JDK 5 and 6.

Environment

Java 5 and 6

Issue

From Java 5 we have XMLEncoder and XMLDecoder class to deal with XML encoding and decoding; but if you have observed the java.sql.Timestamp class is not taken care correctly by these classes, the following example is to show the same:

Program

import java.beans.XMLDecoder;
import java.beans.XMLEncoder;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.sql.Timestamp;
import java.util.Date;

/**
 * @author mchopker
 *
 */
public class TestXMLEnocdingIssue {

    public static void main(String[] args) {
        try {
            XMLEncoder enc = new XMLEncoder(new BufferedOutputStream(
                    new FileOutputStream("Test.xml")));
            Person person = new Person("Mahesh", new Timestamp(
                    new Date().getTime()));
            enc.writeObject(person);
            enc.close();
            System.out.println("Encoding completed....");
        } catch (Exception e) {
            e.printStackTrace();
        }

        try {
            XMLDecoder dec = new XMLDecoder(new BufferedInputStream(
                    new FileInputStream("Test.xml")));
            Object result = dec.readObject();
            dec.close();
            System.out.println(result);
            System.out.println("Decoding completed....");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

---
import java.io.Serializable;
import java.sql.Timestamp;

public class Person implements Serializable {
    private static final long serialVersionUID = 1L;
    private String name;
    private Timestamp time;
    public Timestamp getTime() {
        return time;
    }
    public void setTime(Timestamp time) {
        this.time = time;
    }
    public Person() {
    }
    public Person(String string, Timestamp time) {
        this.name = string;
        this.time = time;
    }
    public String getName() {
        return name;
    }
    public void setName(String string) {
        this.name = string;
    }
}

Console Output

java.lang.InstantiationException: java.sql.Timestamp
Continuing ...
java.lang.RuntimeException: failed to evaluate: <unbound>=Class.new();
Continuing ...

Encoding completed....
Person@6bdd46f7
Decoding completed....

XML Output

<?xml version="1.0" encoding="UTF-8"?>
<java version="1.5.0_15" class="java.beans.XMLDecoder">
 <object class="Person">
  <void property="name">
   <string>Mahesh</string>
  </void>
 </object>
</java>

Observation

You can notice the exception shown as red color text, this is thrown by Java itself and the resulting XML not containing the timestamp attribute; the reason java.sql.Timestamp class is not taken care by Java 5/6 and is fixed now in Java 7. 
If you still happens to use Java 5/6 for some reason then you might have to write custom persistence delegate to deal with this issue as mentioned here:

Thank You!


Saturday 19 October 2013

Java SNMP Trap Sender and Receiver using SNMP4j Open Source library

Objective

To write a SNMP Trap Receiver (for v1, v2c and v3) and Sender in Java using SNMP4j Open Source library.

Environment

Eclipse IDE
Java 7
SNMP4j library (snmp4j-2.2.2.jar, can be downloaded from Net)

Development

Testing

Thank You!

JBoss EAP 6 JBoss Monitoring Java Client

Objective

To demonstrate a Java Client which can fetch JMS statistics of a JBoss EAP 6 running applications.

Environment

  • Eclipse IDE
  • Java 7
  • jboss-cli-client.jar (can be downloaded from Net)

Development

  • Using Eclipse IDE create a Java Project and a class with following main method:

    public static void main(String[] args) {
            String host;
            int port;
            String username;
            String password;
            String[] jmsHostNodes;
            String[] operations;
            String[] queues;
            CLI cli = null;

            try {

                File f = new File("jmsmonitoring.properties");
                if (f.exists()) {
                    Properties jmsMonProperties = new Properties();
                    FileInputStream in = new FileInputStream(f);
                    jmsMonProperties.load(in);

                    // fetch properties
                    host = jmsMonProperties.getProperty("DomainHost");
                    port = Integer.parseInt(jmsMonProperties
                            .getProperty("DomainPort"));
                    username = jmsMonProperties.getProperty("Username");
                    password = jmsMonProperties.getProperty("Password");
                    jmsHostNodes = jmsMonProperties.getProperty("JmsHostNodes")
                            .split(",");
                    operations = jmsMonProperties.getProperty("Operations").split(
                            ",");
                    queues = jmsMonProperties.getProperty("Queues").split(",");
                } else {
                    System.out.println("Input Proerty file missing");
                    return;
                }

                // Get CLI instance
                cli = CLI.newInstance();
                // connect to domain controller
                cli.connect(host, port, username, password.toCharArray());

                // iterate through JMS Nodes and Queues to fetch the needed data
                for (String jmsNode : jmsHostNodes) {
                    StringBuffer cmdString = new StringBuffer("/");
                    cmdString.append(jmsNode);
                    System.out.println("########### JMS Node: " + jmsNode
                            + " #########");
                    for (String queue : queues) {
                        System.out.println("Queue: " + queue);
                        StringBuffer cmdString2 = new StringBuffer(
                                cmdString.toString())
                                .append("/subsystem=messaging/hornetq-server=default/jms-queue=")
                                .append(queue).append("/:read-attribute(name=");
                        for (String operation : operations) {
                            // execute the command
                            System.out.println("command: " + cmdString2.toString()
                                    + operation + ")");
                            Result result = cli.cmd(cmdString2.toString()
                                    + operation + ")");
                            ModelNode response = result.getResponse();
                            String returnValue = response.get("result").asString();
                            System.out.println(operation + " : " + returnValue);
                        }
                    }
                }
            } catch (Exception e) {
                // print exception trace
                e.printStackTrace();
            } finally {
                // disconnect the CLI instance
                if (cli != null)
                    cli.disconnect();
            }
        }
  • The program takes the input parameters like JMS Node, Server and Queue names from a property file. You can create a property file with name "jmsmonitoring.properties" and following contents: 
DomainHost=10.133.2.68
#check the port jboss.management.native.port in domain.xml
DomainPort=10099
Username=admin
Password=admin01
JmsHostNodes=host=host122/server=salcore-jms-node-122,host=host127/server=salcore-jms-node-127
Operations=messages-added,message-count
Queues=alarms,Inventory,sender

  • The program is very generic in the sense that you can add queue names and operation names in the property file and program will be able to fetch and display them. For sample I added just two operations messages-added and message-count only.

Testing

  • Just run the program and you will see the given queues added messages and total count properties in the console.
  • The source code can also be found here: https://github.com/mchopker/myprojects/tree/master/JBossJMSMonitoring

    Thank You!

A simple WebService using JDK

Objective

To develop a Soap WS in standalone Java (no web/app server).

Environment

  • JDK 1.7
  • Eclipse IDE

Development

  • Create a Eclipse Java Project and add a class definition as given below:
package test;

import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.xml.ws.Endpoint;

@WebService(name = "Alarm", serviceName = "AlarmingService", portName = "AlarmPort")
public class AlarmingListenerImpl {

    @WebMethod
    public String sendAlarm(@WebParam(name = "alarm") String alarm) {
        if (alarm != null) {
            System.out.println("Message received:" + alarm);
        }
        return "success";
    }

    public static void main(String[] args) {
        // Start Alarm Listener
        Endpoint endPoint = Endpoint.create(new AlarmingListenerImpl());
        endPoint.publish("http://localhost:9001/alarmingService");
    }
}
  • Start the class (main method is written in the same class); this will be running and listening on port 9001 for any WS requests.

Testing

  • You need any WS client to test the WS you just created.
  • I used Eclipse Java EE Perspective's "Web Service Explorer" (Run -> Launch the Web Service Exporer):
  • You can also try JDK provided tool wsimport to generate WS Client classes and write a Java client.
Thanks You!

Sunday 13 October 2013

Open LDAP Setup in Windows and a Java Spring LDAP Client Development

Objective

To setup an OpenLDAP server in Windows OS and write a LDAP client with standalone Java and Spring libraries.

Environment

  • Windows OS (I have Windows 7)
  • Open LDAP Windows Installer (downloaded from http://userbooster.de/en/download/openldap-for-windows.aspx)
  • LDAP Browser (I have  LDAP browser 2.8.1 by Jarek Gawor)
  • Eclipse IDE

Development

 LDAP Setup

  • Run the downloaded OpenLDAP windows installer; I selected the LDIF backend engine during LDAP setup.
  • You will see a windows service for OpenLDAP server installed.
  • Check if the LDAP is installed properly and service is running by connecting through the LDAP browser you have, for reference I have used following settings to connect to LDAP.
 
  • Now you need some sample data on the LDAP server, so the following entries can be put into a LDIF extension file and added:
dn: ou=groups, dc=maxcrc,dc=com
ou: groups
description: Container for group entries
objectClass: top
objectClass: organizationalUnit

dn: cn=itpeople,ou=groups, dc=maxcrc,dc=com
description: IT security group
objectClass: groupOfNames
member: cn=Sheri Smith,ou=people,dc=maxcrc,dc=com
cn: itpeople

dn: cn=salespeople,ou=groups, dc=maxcrc,dc=com
description: Human Resources group
objectClass: groupOfNames
member: cn=John Smith,ou=people,dc=maxcrc,dc=com
cn: salespeople

dn: ou=People, dc=maxcrc,dc=com
ou: People
objectClass: top
objectClass: organizationalUnit
description: Container for user entries

dn: cn=John Smith,ou=People, dc=maxcrc,dc=com
sn: Smith
userPassword:: alNtaXRI
ou: Sales
carLicense: HISCAR 124
mail: j.smith@maxcrc.com
mail: jsmith@maxcrc.com
mail: john.smith@maxcrc.com
objectClass: inetOrgPerson
uid: jsmith
homePhone: 555-111-2223
cn: John Smith
cn: John J Smith

dn: cn=Sheri Smith,ou=People, dc=maxcrc,dc=com
sn: smith
userPassword:: c1NtaXRI
ou: IT
carLicense: HERCAR 125
mail: s.smith@maxcrc.com
mail: ssmith@maxcrc.com
mail: sheri.smith@maxcrc.com
objectClass: inetOrgPerson
uid: ssmith
homePhone: 555-111-2225
cn: Sheri Smith

  •  To add the above data (copy paste it into some ldif file for example data.ldif) you need to use the LDAP browser import capability or run the following commnad (command available in installed openldap directory):
    • slapadd.exe -l data.ldif
  • You can verify the imported data through LDAP browser.

Java Client

package com.ldap.purjavaclient;

import java.util.Properties;

import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

public class LDAPPurJavaClient {

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
            InitialDirContext context = getDirCtx("ldap://localhost",
                    "cn=Manager,dc=maxcrc,dc=com", "secret");
            try {
                if (args != null && args.length > 0) {
                    String input = args[0];
                    switch (input) {
                    case "1":
                        createPerson(context, "Mahesh Chopker", "Mahesh",
                                "mchopker", "Sales");
                        break;
                    case "2":
                        modifyPerson(context, "Mahesh Chopker", "Chopker",
                                "mchopker", "Sales");
                        break;
                    case "3":
                        removePerson(context, "Mahesh Chopker");
                        break;
                    default:
                        searchPerson(context);
                    }
                }
            } finally {
                context.close();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void searchPerson(InitialDirContext context) {
        Attributes attrs = new BasicAttributes();
        Attribute attr = new BasicAttribute("objectClass");
        attr.add("inetOrgPerson");
        attrs.put(attr);
        SearchControls ctls = new SearchControls();
        String[] ret = { "sn", "uid" };
        String filter = "(objectclass=*)";
        ctls.setReturningAttributes(ret);
        ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
        NamingEnumeration<SearchResult> enu = null;
        try {
            enu = context.search("cn=" + "Mahesh Chopker"
                    + ",ou=people,dc=maxcrc,dc=com", filter, ctls);
            while (enu != null && enu.hasMore()) {
                SearchResult sr = (SearchResult) enu.next();
                System.out.println(sr.getNameInNamespace());
                Attributes rattr = sr.getAttributes();
                System.out.println(rattr.get("sn"));
                System.out.println(rattr.get("uid"));
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (enu != null) {
                try {
                    enu.close();
                } catch (Exception e1) {
                    // igonore this
                }
            }
        }
    }

    private static void createPerson(InitialDirContext context, String name,
            String sn, String uid, String ou) throws NamingException {
        Attributes attrs = new BasicAttributes();
        String dn = "cn=" + name + ",ou=people,dc=maxcrc,dc=com";
        Attribute attr = new BasicAttribute("objectClass");
        attr.add("inetOrgPerson");
        attrs.put(attr);
        attrs.put("sn", sn);
        attrs.put("uid", uid);
        attrs.put("ou", ou);
        SearchResult sr = new SearchResult(dn, null, attrs);
        context.createSubcontext(sr.getName(), attrs);
    }

    private static void modifyPerson(InitialDirContext context, String name,
            String sn, String uid, String ou) throws NamingException {
        Attributes attrs = new BasicAttributes();
        String dn = "cn=" + name + ",ou=people,dc=maxcrc,dc=com";
        Attribute attr = new BasicAttribute("objectClass");
        attr.add("inetOrgPerson");
        attrs.put(attr);
        attrs.put("sn", sn);
        attrs.put("uid", uid);
        attrs.put("ou", ou);
        SearchResult sr = new SearchResult(dn, null, attrs);
        context.modifyAttributes(sr.getName(), DirContext.REPLACE_ATTRIBUTE,
                attrs);
    }

    private static void removePerson(InitialDirContext context, String name)
            throws NamingException {
        context.destroySubcontext(name);
    }

    private static InitialDirContext getDirCtx(String url, String userBindDn,
            String userBindPw) throws Exception {
        InitialDirContext ctx = null;
        Properties env = new Properties();
        env.setProperty(javax.naming.Context.INITIAL_CONTEXT_FACTORY,
                "com.sun.jndi.ldap.LdapCtxFactory");
        env.setProperty(javax.naming.Context.PROVIDER_URL, url);
        env.setProperty(javax.naming.Context.SECURITY_PRINCIPAL, userBindDn);
        env.setProperty(javax.naming.Context.SECURITY_CREDENTIALS, userBindPw);
        try {
            ctx = new InitialDirContext(env);
        } catch (NamingException ex) {
            throw new Exception("LdapManagerBean::createConnection failed", ex);
        }
        return ctx;
    }
}

Java Spring Client without DI

package com.ldap.springclient;

import javax.naming.NamingException;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;

import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.LdapContextSource;

public class LDAPSpringClient {

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {

            LdapContextSource ldapContextSource = new LdapContextSource();
            ldapContextSource.setUrl("ldap://localhost");
            ldapContextSource.setBase("dc=maxcrc,dc=com");
            ldapContextSource.setUserDn("cn=Manager,dc=maxcrc,dc=com");
            ldapContextSource.setPassword("secret");

            // this line needed since we are not using DI and manually
            // initizlizing context
            ldapContextSource.afterPropertiesSet();

            LdapTemplate ldapTemplate = new LdapTemplate();
            ldapTemplate.setContextSource(ldapContextSource);

            searchPerson(ldapTemplate);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void searchPerson(LdapTemplate ldapTemplate) {
        System.out.println(ldapTemplate.search("cn=Mahesh Chopker,ou=People",
                "(objectclass=*)", new AttributesMapper() {
                    public Object mapFromAttributes(Attributes attrs)
                            throws NamingException {
                        Attributes attributes = new BasicAttributes();
                        attributes.put(attrs.get("cn"));
                        attributes.put(attrs.get("uid"));
                        return attributes;
                    }
                }));
    }
}

Java Spring Client with DI

package com.ldap.springclient;

import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttribute;
import javax.naming.directory.BasicAttributes;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.ldap.core.AttributesMapper;
import org.springframework.ldap.core.LdapTemplate;

public class LDAPSpringDIClient {

    private LdapTemplate ldapTemplate;

    public void setLdapTemplate(LdapTemplate ldapTemplate) {
        this.ldapTemplate = ldapTemplate;
    }

    /**
     * @param args
     */
    public static void main(String[] args) {
        try {
            ApplicationContext context = new ClassPathXmlApplicationContext(
                    "context.xml");
            LDAPSpringDIClient ldapClientInstance = (LDAPSpringDIClient) context
                    .getBean("ldapClient");

            if (args != null && args.length > 0) {
                String input = args[0];
                switch (input) {
                case "1":
                    ldapClientInstance.createPerson("Mahesh K Chopker",
                            "Mahesh", "mchopker", "Sales");
                    break;
                case "2":
                    ldapClientInstance.modifyPerson("Mahesh K Chopker",
                            "Chopker", "mchopker2", "Sales");
                    break;
                case "3":
                    ldapClientInstance.removePerson("Mahesh K Chopker");
                    break;
                default:
                    ldapClientInstance.searchPerson();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void createPerson(String name, String sn, String uid, String ou)
            throws NamingException {
        Attributes attrs = new BasicAttributes();
        String dn = "cn=" + name + ",ou=people";
        Attribute attr = new BasicAttribute("objectClass");
        attr.add("inetOrgPerson");
        attrs.put(attr);
        attrs.put("sn", sn);
        attrs.put("uid", uid);
        attrs.put("ou", ou);
        ldapTemplate.bind(dn, null, attrs);
    }

    private void modifyPerson(String name, String sn, String uid, String ou)
            throws NamingException {
        Attributes attrs = new BasicAttributes();
        String dn = "cn=" + name + ",ou=people";
        Attribute attr = new BasicAttribute("objectClass");
        attr.add("inetOrgPerson");
        attrs.put(attr);
        attrs.put("sn", sn);
        attrs.put("uid", uid);
        attrs.put("ou", ou);
        ldapTemplate.rebind(dn, null, attrs);
    }

    private void removePerson(String name) throws NamingException {
        ldapTemplate.unbind(name);
    }

    private void searchPerson() {
        System.out.println(ldapTemplate.search("cn=Mahesh K Chopker,ou=People",
                "(objectclass=*)", new AttributesMapper() {
                    public Object mapFromAttributes(Attributes attrs)
                            throws NamingException {
                        Attributes attributes = new BasicAttributes();
                        attributes.put(attrs.get("cn"));
                        attributes.put(attrs.get("uid"));
                        return attributes;
                    }
                }));
    }
}
 

Testing

  • The test clients have options to add/modify/delete and search LDAP which can be triggered based on the command line input value 1,2,3 and 4.
  • The source code and LDIF data file can be downloaded from following git repository location:
    • https://github.com/mchopker/myprojects/tree/master/LDAPExample

 Thank You!

Sunday 6 October 2013

How to identify a High CPU thread in a Java application

Objective

To understand the basics of how a high cpu thread can be identified in a Java application.

Notes

  1. There are many good articles in net which tell step by step instructions to identify a high cpu thread in a Java application running on different OS. In this article I just try to summarize the key concepts instead of walk you through the steps/examples.
  2. The Linux OS have one to one mapping between Java (version 1.2 onwards) threads and OS threads, and the easiest way to identify a high cpu thread is:
    1. Run command: top -H
  3. The output of above command will be PID (thread id) sorted in descending order of CPU usage.
  4. Once you get the PID of high cpu thread (probably you need to monitor the high CPU thread for some time to see if it is keeping the CPU usage high for some longer time), take a thread dump of your Java application (via jstack or any other profiling tool lie VisualVM).
  5. The PID you got has to be converted into Hexa number before you search that into thread dump to identify which Java thread in your application it is and with the stack trace in dump you will be able to identify what kind of task the thread is doing.
Thanks You!

Saturday 5 October 2013

Java Keytool command usage

Objective

In a Client-Server Model when Server is exposing resources (like WebService, Servlets, etc) on HTTPS, the Java client program needs to authenticate the Server certificate to access the resource. I tried to explain the usage of few basic Keytool commands which are handy in such situations.

Environment

Java 7 (JDK or JRE)

Command Usage

  • First you need to obtain the Server certificate, you can do via hitting the resource URL in a Web Browser. Your Web Browser will ask to authenticate the Server and trust the certificate, once you do that, you will see a small icon on Address URL (either on left of right side of the URL), you can click the icon and it will provide you options to export the certificate.
  • Export the certificate in a .pem or .crt format and copy it to directory: <JAVA/JRE_HOME>/jre/lib/security and switch to this directory.
  • Command to import certificate into Java's truststore
    • keytool -import -file <PEM or CRT file you copied> -keystore cacerts
      • The cacerts truststore password is changeit 
Now the Java Client program should be able to access the server resource over https. Following are few additional commands which you might find useful:
  • Command to see available certificates in Java's truststore
    • keytool -list -keystore cacerts
  • Command to delete an existing certificate from Java's truststore
    • keytool -delete -alias <certificate alais name> -keystore cacerts
  • Command to change the alias name of an existing certificate from Java's truststore (this command is useful when you have more than one certificates but with same alias)
    • keytool -changealias -alias <existing-alias-name> -destalias <new-alias-name> -keystore cacerts
  • You can also export a certificate stored in a keystore via following command
    • keytool -export -file <exporeted-cert-filename.crt> -alias <alias-name-of-cert-which-to-be-exported> -keystore cacerts
Please note that all above commands are valid for any keystore (not only Java's own cacerts trustore); in that case you just put your keystore name instead of cacerts. Generally this is required when your application is maintaining its own keystore.

Friday 27 September 2013

Generating a Web Service Java Client from a given WSDL using Eclipse

Objective

To develop a Java web service client from a given WSDL using Eclipse IDE.

Environment

Java 7
Eclipse IDE (Juno)
A WS wsdl xml file

Development

  • Open your Eclipse IDE and Workspace.
  • Create a new Java Project (File -> New -> Java Project).
  • Give Project name as "TestWSClient" and click on Finish
  • Copy the given WSDL file under Project "TestWSClient" root folder.
  • Right click on Project and select New -> Other -> Web Service Client  and then Next.
  • A new window will come up, give Service Definition value by clicking on Browse -> Browser and then select the WSDL file we copied earlier into Project root folder. Click OK -> Finish.

  • Ensue that the actual WS for which the WSDL is present exists and running; otherwise we will get exception in above step. At successful creation we will see many java classes get created under project src folder with the name ending with Stub, Proxy, Location, etc.

Testing

  • Now the Java APIs are generated for the WS client, let us write a simple Java class to test how can we call operations exposed by WS.
  • Create a Java class with name "Client" (File -> New -> Class) and write code similar to what shown below in your main method:
AlarmingServiceLocator asLocator = new AlarmingServiceLocator();
asLocator.setEndpointAddress("AlarmPort",
                    "http://localhost:9001/alarmingService");
Alarm service = asLocator.getAlarmPort();
service.sendAlarm("test mahesh alarm");

  • What matters here is the right parameters on call to setEndpointAddress() method when called from Locator class. And then how you get the reference to your Service from Locator which will then be used to call the WS operations (here we called sendAlarm() operation).
  • In case you face some compilation or runtime exceptions just browse through the generated Location, Stub and Proxy classes to get the idea of how things work.
Thanks!

A HelloWorld OSGI Module using Ecipse Equinox OSGI Framework

Objective

To create a HelloWorld OSGI Module using Equinox OSGI Framework.

Environment

  • Eclipse IDE (Juno)
  • OSGI Equinox Framework

Development

  • Open you Eclipse IDE and Workspace.
  • Create a new Plug-in Project (File -> New -> Other -> Plug-in Project).
  • Give Project name as "HelloWorldModule". Select target as "an OSGI Framework: standard.
  • Select Next -> Next and choose template as "Hello OSGI Bundle"; then Next -> Finish.
  • You will see a Java class Activator (implementing BundleActivator) gets created with start() and stop() methods. Both the methods have BundleContext parameter passed, the BundleContext is a way through which we can interact with OSGI framework.
  • The Activator class start() and stop() method provide a way to define what should be done when the bundle is started and stopped while running under an OSGI framework.
  • You will also see few System out messages under start() and stop() method which will help us test when these methods are called.

Testing

  • Right click on project and select Run As -> Run Configurations..
  • Create a new OSGI Configuration by right clicking on OSGI Framework. Give name as HelloWorldModule and select following Bundles
  • Cock on Apply and Run
  • In Eclipse Console view the following message and prompt will appear
Hello World!!
osgi> 
  • Type ss on osgi prompt, this will list the current bundles installed and their status
osgi> ss
"Framework is launched."
id    State       Bundle
0    ACTIVE      org.eclipse.osgi_3.8.2.v20130124-134944
                Fragments=2
1    ACTIVE      org.apache.felix.gogo.command_0.8.0.v201108120515
2    RESOLVED    org.eclipse.equinox.weaving.hook_1.0.200.I20130319-1000
                Master=0
3    ACTIVE      org.apache.felix.gogo.runtime_0.8.0.v201108120515
4    ACTIVE      org.eclipse.equinox.console_1.0.0.v20120522-1841
5    ACTIVE      HelloWorldModule_1.0.0.qualifier
6    ACTIVE      org.apache.felix.gogo.shell_0.8.0.v201110170705

  • Now to see what happens when we stop a bundle; give command osgi> stop <bundl-id>. In our case it would be stop 5 since 5 is the bundle if of HelloWorldModule.
  • We will see following output on console
osgi> stop 5
Goodbye World!!
  • Now to exit from osgi prompt type exit and then y
  • So you noticed the message "Hello World!!" and "Goodby World!!" when the HelloWorldModule bundle started and stopped. In real world application this is where we would write the actual code which we want to execute during start and stop of a module.


A HelloWorld Servlet in JBoss EAP 6 using Eclipse

Objective

To show a simple JEE6 HelloWorld Servlet development

Environment

  • Eclipse Juno
  • JBoss EAP 6.0 Application Server
  • Java 7

Development

1.       Start Eclipse.
2.       Configuring Server
a.       (Go to Menu Window -> Preferences)
b.      Select button Add, this will open a new window
c.       Select Server “JBoss Enterprise Application Platform 6.0 Runtime”. 
In case the server is not listed please download the one via selecting “Download additional server adapters” link shown on top right corner.
d.      Specify correct path for JBoss EAP 6.0 and right JRE
e.      Click on button “Finish” and then “OK” on previous window.
f.        Open Servers view (Window -> Show View -> Servers)
g.       On Servers view click on “new server wizard...” link
h.      A “New Server” window will open
Ensure the “JBoss EAP 6.0 Runtime” Server runtime environment is selected and click on Finish.
i.         Specify correct path for JBoss EAP 6.0 and right JRE

3.       Create a Dynamic Web Project (File -> New -> Dynamic Web Project)
4.       Give project name as “HelloWorldServlet”
Click on Finish.
5.       You should see the project “HelloWorldServlet” created. Now right click on project and click New -> Servlet.
6.       Specify Servlet name as “HelloWorldServlet” and package as “com.test”
Click on Finish.
7.       Make following changes on doGet() and doPost() method as:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   PrintWriter out = response.getWriter();
   out.print("<html><body><b>Respons from HelloWorld Servlet</b></body></html>");
   out.close();
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
              doGet(request, response);
}
8.       Right click on project and select “Run As” -> “Run on Server”
Click on Finish.
9.       You should see “Console” view showing server startup logs. Once server is started successfully a browser window will open with URL http://localhost:8080/HelloWorldServlet

Testing

1.       You must hit the URL http://localhost:8080/HelloWorldServlet/HelloWorldServlet either in Eclipse Web Browser window or any other Web Browser you have.
2.       Once hit the browser must show message “Respons from HelloWorld Servlet
Congratulations this completes your HelloWorldServlet which is a Servlet 3.0 Spec compliant running in JBoss EAP 6.0.