Manipulating Lists in JSTL

May 21st, 2008

A common problem when coding in JSTL is that you would like to have an ArrayList of items that you can iterate over. For example imagine that you have a list of Animals like:

1) Sylvester

2) Goofy

3) Mickey

<c:forEach items="${animalList}" var="animal">${animal}<</c:forEach>

And you would like the output to be in the same order:

Sylvester

Goofy

Mickey

The problem is that you can’t do this:

<jsp:useBean id=”animalList” class=”java.util.ArrayList”/>

because <c:set> doesn’t work with <i>ArrayLists</i>, and so there is no good way to use JSTL to add those values.

This fails:

<c:set target=”${animalList}” value=”Sylvester”/>

<c:set target=”${animalList}” value=”Goofy”/>

<c:set target=”${animalList}” value=”Mickey”/>

You could do this, and I wouldn’t argue if you do:

<c:set var=”dummyVar” value=”${animalList.add(’Sylvester’)}”/>

<c:set var=”dummyVar” value=”${animalList.add(’Goofy’)}”/>

<c:set var=”dummyVar” value=”${animalList.add(’Mickey’)}”/>

However, its a little ugly, because you have to use dummyVars. Still I will admit I have used this technique a lot. Another solution that you might be considering is to use HashMaps, which do work with <c:set>.

<jsp:useBean id=”animalMap” class=”java.util.HashMap”/>

<c:set target=”${animalMap}” property=”cat” value=”Sylvester”/>

<c:set target=”${animalMap}” property=”dog” value=”Goofy”/>

<c:set target=”${animalMap}” property=”rat” value=”Rat”/>

<c:forEach items=”${animalMap.values()}” var=”animal”>

${animal}<br>

</c:forEach>

This is cool because there is not hackish method calls on objects that JSTL doesn’t understand. Also the elements can now be referenced indirectly, instead of having to loop on the list to find a particular element. But there is a problem: The order has been lost! When this loop fires it dumps the animals in the order that they are stored in the HashMap, which for all practical purposes is random.

The solution: <b>java.util.LinkedHashMap</b>

By replacing java.util.HashMap in the example above with

java.util.LinkedHashMap, you get the best of both worlds! <b>Ordered

elements</b> and <b>Indirect Reference</b>:

<jsp:useBean id=”animalMap” class=”java.util.LinkedHashMap”/>

<c:set target=”${animalMap}” property=”cat” value=”Sylvester”/>

<c:set target=”${animalMap}” property=”dog” value=”Goofy”/>

<c:set target=”${animalMap}” property=”rat” value=”Rat”/>

These are ordered:<br>

<c:forEach items=”${animalMap.values()}” var=”animal”>

${animal}<br>

</c:forEach>

And this references a particular element:<br>

${animalMap[’dog’]}

Removing an item from a Map using JSP

November 30th, 2007

A common need for working with Maps in JSP is the ability to remove items from the Map.  With JSTL it is not so obvious how to do this, yet it turns out to be very easy by simply using an EL expression to call the remove(key) method on the map.  Here is an example…

 

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>

<html>
<body>

<p>Creating hash map and populate it ..</p>

<jsp:useBean id="map" class="java.util.HashMap"/>
<c:set target="${map}" property="cat" value="brown"/>
<c:set target="${map}" property="dog" value="green"/>
<c:set target="${map}" property="rat" value="black"/>

<p>Remove dog and store its former value in a local variable …</p>

<c:set var="oldDogValue" value="${map.remove(’dog’)}"/>

</body>
</html>

Another great tip from Aaron Freeman at SendThisFile.com.

Handling multiple value parameters in JSP

November 9th, 2007

In JSP, you cannot simply use an expression like ${param.weekday} to retreive multiple values if the request has multiple values assigned like the form below…

<input name="weekday" value="Sunday" checked>
<input name="weekday" value="Monday" checked>

Instead, use an expression like ${fn:join(paramValues[’weekday’], ‘,’)} to retreive a comma delimited list of values for the parameter.

Tip provided by Aaron Freeman from SendThisFile.com.

Delete All Subdirectories with a Specific Name

October 24th, 2007

Let’s say you want to delete all the "CVS" subdirectories anywhere below a top level "/opt/project" directory.  Here is how you can do this…

  1. Execute cd /opt/project to change to the top level directory below which you wish to delete the "CVS" subdirectories
  2. Execute find -type d -name 'CVS' -ls to see a preview of all the directories that will be deleted.
  3. If the preview seems ok, you can then execute find -type d -name 'CVS' -exec rm -fr {} \; to actually delete all the subdirectories (you’ll get a No such file or directory error when executing but the subdirectories are still deleted).

Obviously, this can work with any subdirectory name as you would just replace CVS above with your subdirectory name.

Determine the Parameter Names of a Java Method at Run-time

August 23rd, 2007

The Java reflection API does not allow you to determine parameter names of a method at run-time; however, you can accomplish this by using a library within the Apache Axis2 project to read parameter names of a Java method at run-time.  Here is an example…

import java.lang.reflect.*;
import org.apache.axis2.description.java2wsdl.bytecode.*;

public class Test {

  public static void main(String[] args) {

    try {
      // Nothing new here, just find the method we want to
      // lookup the parameter names
      Method m = Test.class.getMethod(
        "addNumbers",
        new Class[] {Long.class, Long.class}
      );

      // This uses the Apache Axis2 ChainedParamReader class to
      // determine the parameter names
      ChainedParamReader pr = new ChainedParamReader(Test.class);
      String[] paramNames = pr.getParameterNames(m);

      // Print the resulting paramNames
      for (String paramName : paramNames) {
        System.out.println(paramName);
      }
    }
    catch (Exception e) {
      System.err.println(e);
    }
  }

  public Long addNumbers(Long firstValue, Long secondValue) {
    return firstValue + secondValue;
  }
}

You can compile and execute this which result in…

C:\temp>javac -cp axis2-kernel-1.3.jar -g Test.java

C:\temp>java -cp .;axis2-kernel-1.3.jar Test

firstValuesecondValue

Important: You must compile your classes with the debug switch (-g) for this to work.  The ChainedParamReader class uses the debug information in the binary class file to determine the parameter names.

You can get the axis2-kernel-1.3.jar from http://ws.apache.org/axis2/.

On the fly compression of mysqldump output

March 30th, 2007

Found this tip here — you can compress your mysqldump output by executing…

mysqldump my_database_name | gzip > my_database_name.sql.gz

You can even process these compressed files directly by executing…

gunzip < my_database_name.sql.gz | mysql -D my_database_name

Very useful to process backups/restores with limited disk space on a server.

How To Work Around “Argument List Too Long” Error Deleting a Gazillion Files Under Linux

December 28th, 2006

You can receive the error argument list too long trying to execute a rm -f * in a directory with a lot of files but there is a very simple workaround.  Simply execute this instead to delete the files…

find . -name "*" -type f -maxdepth 1 -exec rm {} \;

Important: Executing a find . -exec rm {} \; is equivalent to executing a rm -f * — be sure you know what you are doing and be sure you are in the right directory when you execute this.

Note that the -name "*" switch avoids deleting system files and the -maxdepth 1 switch avoids deleting files in subdirectories.

How To Identify the Files/Directories Chewing Up Disk Space Under Linux

December 4th, 2006

If you are running out of disk space under Linux, here are three useful commands to help identify which files and directories are chewing up the most disk space…

  1. Show the 50 largest files…

    find / -path '/proc' -prune -o -size +1000k -printf '%s   %p\n' | sort -k1 -g -r | head -50

  2. Show the 50 largest directories (excluding files in subdirectories)…

    du -kS / | sort -k1 -g -r | fgrep -v '/proc' | head -50

  3. Show the 50 largest directories (including files in subdirectories)…

    du -k / | sort -k1 -g -r | fgrep -v '/proc' | head -50

Important: As these commands may take a little while to run, you should not run these commands on a production system where a significant increase in load would have an adverse impact.

The 16 String Functions Available in JSP EL

December 1st, 2006

Although I’ve used JSP extensively for quite sometime, I didn’t realize until recently that JSTL supports 16 string functions within the EL syntax.  Here is an example JSP page that exercises the 16 string functions…


<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>

<html><body>

contains() –> ${fn:contains(’Hello’, ‘el’)}<br>
containsIgnoreCase() –> ${fn:containsIgnoreCase(’HELLO’, ‘el’)}<br>
endsWith() –> ${fn:endsWith(’Hello’, ‘llo’)}<br>
escapeXml() –> ${fn:escapeXml(’1<>3′)}<br>
indexOf() –> ${fn:indexOf(’Hello’, ‘el’)}<br>
join()/split() –> ${fn:join(fn:split(’/1/2/3/4/5′, ‘/’), ‘:’)}<br>
length() –> ${fn:length(’Hello’)}<br>
replace() –> ${fn:replace(’Hello’, ‘H’, ‘J’)}<br>
startsWith() –> ${fn:startsWith(’Hello’, ‘He’)}<br>
substring() –> ${fn:substring(’Hello’, 2, 4)}<br>
substringAfter() –> ${fn:substringAfter(’Hello’, ‘el’)}<br>
substringBefore() –> ${fn:substringBefore(’Hello’, ‘el’)}<br>
toLowerCase() –> ${fn:toLowerCase(’HELLO’)}<br>
toUpperCase() –> ${fn:toUpperCase(’hello’)}<br>
trim() –> ${fn:trim(’  hello  ‘)}<br>

</body></html>

This outputs the following…


contains() --> true
containsIgnoreCase() –> true
endsWith() –> true
escapeXml() –> 1<>3
indexOf() –> 1
join()/split() –> 1:2:3:4:5
length() –> 5
replace() –> Jello
startsWith() –> true
substring() –> ll
substringAfter() –> lo
substringBefore() –> H
toLowerCase() –> hello
toUpperCase() –> HELLO
trim() –> hello

You can see the full reference for these string functions here.  This requires JSP 2.0.

You can also find an excellent article on creating a custom JSP function here:)

How To View Processes Using Most Threads Under Linux

November 30th, 2006

You can run this command under Linux (tested with RHEL 3.0) to see the processes with the most threads…

find /proc/*/status -exec gawk '/^Name:/ { n=$2}; /^Threads:/ { t=$2}; END{ printf("%-30s %5d\n", n, t);}' {} \; | sort --key=2 -g -r | head -10

This is especially useful on systems (like VPS hosting accounts) where you might have limits on the total number of threads.

Addendum (12/1/2006 1:48p CST):

Based on feedback, here are a few other tips related to this…

  • You can modify the script slightly to also show the process id using this modified version…

    find /proc/*/status -exec gawk '/^Pid:/ { p=$2}; /^Name:/ { n=$2}; /^Threads:/ { t=$2}; END{ printf("%6d %-30s %5d\n", p, n, t);}' {} \; | sort -k3 -g -r | head -10

  • You can create a topthreads alias to this long command allowing to you execute it just by typing topthreads by first executing…

    alias topthreads="find /proc/*/status -exec gawk '/^Pid:/ { p=\$2}; /^Name:/ { n=\$2}; /^Threads:/ { t=\$2}; END{ printf(\"%6d %-30s %5d\n\", p, n, t);}' {} \; | sort -k3 -g -r | head -10"