Dynamic Columns in JSP Model with Struts Framework

While developing web applications, we will come across a lot of scenarios where we should use dynamic columns depending on the entitlement of the user or from the result set depending on the data itself. Dynamic columns in web applications give control to the user on what he wants to see (specially when we have a huge amount of data to work with). For applications with sensitive data, this can be even extended to act as a security layer where the access to specific data can be controlled with high precision.

In this article, I will explain one of the methods to implement this in any J2EE application with little or no code change.

High Level Architecture

In a nut shell, this design uses the Application Context of the container to maintain the values pertaining to a particular user, if the requirement demands not to maintain the preference after a user session is terminated, then it can be achieved by destroying the object stored in the context.

We will start by creating a singleton class, which will be used to store the user preference about the columns. The user preference object can be mapped against the user id or any other primary key, so that different preferences are maintained for different users. While the container starts, the instance for the singleton will be created. The default preferences can be loaded from a property / xml file or from a data store (DB). This object will contain the preferences of different pages with the different key names so that the same object can be used to maintain the preference across the application. This will be read during the logon operation and if the object in the application context doesn’t contain any values (if the user logs in for the first time or in an application where the preference is specific to the session) then the default values are loaded. Once the page loads, the preference can be read from the application context and can be presented to the user. If the user edits his preferences, it will be updated in the application context. Note that the application context is not persistent between container restarts, so appropriate mechanisms should be taken to store the data.

Implementation

Let’s go through the implementation now. The following steps describe how to integrate this component to an existing Struts application.

Start-up servlet and initializing the Singleton Class

Create an Initializer Servlet and make an entry for the same in the web.xml file so that the Servlet starts when the container is initialized. Make sure the load-on-startup is set to 1, which ensures that the application server loads the servlet while startup.

<servlet>
    <servlet-name> InitializerServlet </servlet-name>
    <servlet-class>com.startup.common.InitializerServlet</servlet-class>
    <load-on-startup> 1 </load-on-startup>
</servlet>

Next, create a Singleton class, which contains getter and setter methods for dynamic column preference, the object can be any collection, we are using Hash Map in this example which will be used to store the primary key against the list containing the preference. The set & get methods in the Singleton should be synchronized so that the simultaneous access is restricted. Also override the clone() method in your singleton.

public class AppSingleton implements Serializable {
    private Hashtable cusomizeViewValues = null;
    private static AppSingleton appSingleton = null;

    private AppSingleton (){ }

    public synchronized void setCusomizeViewValues (Hashtable cusomizeViewValues){
        this.cusomizeViewValues = cusomizeViewValues;
    }

    public static synchronized AppSingleton getInstance () throws Exception {
        try {
            if (appSingleton == null)
                return new AppSingleton ();
          } catch (Exception e) {
            throw new Exception();
        }
    }

    public Object clone() throws CloneNotSupportedException{
        throw new CloneNotSupportedException();
    }
}

In the startup servlet, create an instance of the singleton class. When created, the object will be available in the application context of the container, and no one will be able to create another instance, until the object created in startup is destroyed. Since we have overridden the clone method, no one will be able to clone the particular object. These measures are to ensure the integrity of the user preference stored in the singleton. A sample Initializer servlet will look like the following code.

public class InitializerServlet extends HttpServlet {
    public void init () throws ServletException {
        AppSingleton appSingleton = AppSingleton.getInstance ();
    }

    public void destroy (){}
    public void service (HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {}
}

Now, create a Data Transfer Object (DTO) / Value Object (VO) for storing the values. The VO/DTO will contain just two getters and setters, one for the Column Display name and the other for the bean property. This will be a POJO.

Populate the Application context

When the container starts, populate the list in the application context, from the property file or from the data source. If you are having a separate page to choose the columns displayed, you can use the same list to render the values initially. Similarly if the user has changed his preference then update the application context accordingly. This can be done during the Login Action, once the user is authorized and authenticated. You can use your own logic to get all the user preference and then update list with DTO’s/VO’s containing the display name and the property name. This list is updated in the application context against the primary key. Before updating the application context check if the PK is already present in the Hash Table if yes, update or create a new entry.

A sample property file will look like the one given below. By using different keys, we can have entries for different pages. Also the columns to be displayed to the user irrespective of the individual preference can also be marked here under a different key. The columns users are not allowed to modify are added to the rendering list once the request is got from the particular page and not during the logon time. The values are appended to the modifiable columns list and rendered to the user.

Validations$Optional=Plan #, Plan Name, Administrator
Validations$Core= Plan Val Description, Plan Val Status

# Optional represents the Columns users can modify
# Core represents the Columns users can’t modify

Validations$Plan#=strClientExtEntityId
Validations$PlanName=strPlanName
Validations$Administrator=strAdministrator
Validations$PlanValDescription=strDescription
Validations$PlanValStatus=strStatus
Rendering Logic

Once the values are available in the session, using JSP, logic iterate, render the Column names. Then to display the values from the result set, use the logic iterate with the list containing the values for the page, which is used to render the <tr> tag and inside that logic iterate, use another logic iterate, which is used to render the columns and use a bean define tag to get the column name properties in a scriplet variable and then use a bean define tag to display the value of the property. This logic is highly dynamic.

To display the column names,

<logic:iterate name="<Form Bean Name>" id="testId" property="<Name of the List>" >
    <td>
        <bean:write name=" testId " property="<Col Disp Name>"/>
    </td>
</logic:iterate>

To display the result set,

<logic:iterate name="<Form Name>" id="outerId" property="<Property of the Hitlist>">
    <tr>
        <logic:iterate name="<Form Name>" id="innerId" property="<Name of the List>" >
        <bean:define name="innerId" id="propId" property="<Col Property>" type="String"/>
            <td>
                <bean:write name="outerId" property="<%= propId %>" />
            </td>
        </logic:iterate>
    </tr>
</logic:iterate>

We also will have situations to display hyperlinks, textboxes etc. in the result set, the same logic can be used to display the different objects in the JSP. Just before the bean write tag, have a logic equal tag to check for specific types and render the display.

This architecture is highly customizable and can be easily plugged in into any existing J2EE application. Also this can be easily enhanced to incorporate new functionalities.

Java String Concatenation and Performance

The quick and dirty way to concatenate strings in Java is to use the concatenation operator (+). This will yield a reasonable performance if you need to combine two or three strings (fixed-size). But if you want to concatenate n strings in a loop, the performance degrades in multiples of n. Given that String is immutable, for large number of string concatenation operations, using (+) will give us a worst performance. But how bad ? How StringBuffer, StringBuilder or String.concat() performs if we put them on a performance test ?. This article will try to answer those questions.

We will be using Perf4J to calculate the performance, since this library will give us aggregated performance statistics like mean, minimum, maximum, standard deviation over a set time span. In the code, we will concatenate a string (*) repeatedly 50,000 times and this iteration will be performed 21 times so that we can get a good standard deviation. The following methods will be used to concatenate strings.

And finally we will look at the byte code to see how each of these operations perform. Let’s start building the class. Note that each of the block in the code should be wrapped around the Perf4J library to calculate the performance in each iteration. Let’s define the outer and inner iterations first.

private static final int OUTER_ITERATION=20;
private static final int INNER_ITERATION=50000;

Now let’s implement each of the four methods mentioned in the article. Nothing fancy here, plain implementations of (+), String.concat(), StringBuffer.append() & StringBuilder.append().

String addTestStr = "";
String concatTestStr = "";
StringBuffer concatTestSb = null;
StringBuilder concatTestSbu = null;

for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
    StopWatch stopWatch = new LoggingStopWatch("StringAddConcat");
    addTestStr = "";
    for (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
        addTestStr += "*";
    stopWatch.stop();
}

for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
    StopWatch stopWatch = new LoggingStopWatch("StringConcat");
    concatTestStr = "";
    for (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
        concatTestStr = concatTestStr.concat("*");
    stopWatch.stop();
}

for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
    StopWatch stopWatch = new LoggingStopWatch("StringBufferConcat");
    concatTestSb = new StringBuffer();
    for (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
        concatTestSb.append("*");
    stopWatch.stop();
}

for (int outerIndex=0;outerIndex<=OUTER_ITERATION;outerIndex++) {
    StopWatch stopWatch = new LoggingStopWatch("StringBuilderConcat");
    concatTestSbu = new StringBuilder();
    for (int innerIndex=0;innerIndex<=INNER_ITERATION;innerIndex++)
        concatTestSbu.append("*");
    stopWatch.stop();
}

Let’s run this program and generate the performance metrics. I ran this program in a 64-bit OS (Windows 7), 32-bit JVM (7-ea), Core 2 Quad CPU (2.00 GHz) with 4 GB RAM.

The output from the 21 iterations of the program is plotted below.

Well, the results are pretty conclusive and as expected. One interesting point to notice is how better String.concat performs. We all know String is immutable, then how the performance of concat is better. To answer the question we should look at the byte code. I have included the whole byte code in the download package, but let’s have a look at the below snippet.

45: new #7; //class java/lang/StringBuilder
48: dup
49: invokespecial #8; //Method java/lang/StringBuilder."<init>":()V
52: aload_1
53: invokevirtual #9; //Method java/lang/StringBuilder.append:
    (Ljava/lang/String;)Ljava/lang/StringBuilder;
56: ldc #10; //String *
58: invokevirtual #9; //Method java/lang/StringBuilder.append:
    (Ljava/lang/String;)Ljava/lang/StringBuilder;
61: invokevirtual #11; //Method java/lang/StringBuilder.toString:()
    Ljava/lang/String;
64: astore_1

This is the byte code for String.concat(), and its clear from this that the String.concat is using StringBuilder for concatenation and the performance should be as good as String Builder. But given that the source object being used is String, we do have some performance loss in String.concat.

So for the simple operations we should use String.concat compared to (+), if we don’t want to create a new instance of StringBuffer/Builder. But for huge operations, we shouldn’t be using the concat operator, as seen in the performance results it will bring down the application to its knees and spike up the CPU utilization. To have the best performance, the clear choice is StringBuilder as long as you do not need thread-safety or synchronization.

Full source of this application is available in my github page.