1/31/2007

Project-wide find and replace in NetBeans 6

I am so glad to notice that NetBeans 6 (development build) now supports project-wide find and replace. See my previous post about this bug that plagued NetBeans since 2001. This bug fix is long overdue, but it's great to see NetBeans now has the real find-replace.

So in NetBeans 6, I can click on a project node, or package node, or any directory node in my project, and find. The pop-up window lets you specify the replacement string and options (case-sensitive, match whole word, regular expression, etc).

What's really nice is, it then opens up output windows where you can review, select, and de-select matches for replace:

1/29/2007

Why we have to use -jar option when running a self-contained jar

We can run a self-contained jar file with a command like this:

java -jar foo.jar
,where foo.jar contains a main class that is specified in META-INF/MANIFEST.MF with a Main-Class entry. What will happen if running if without -jar option? java will read foo.jar as a main class named jar in package foo:
C:\tmp>java foo.jar
Exception in thread "main" java.lang.NoClassDefFoundError: foo/jar
I guess that's the reason why -jar option is necessary to tell JVM to look for a jar file rather than a class file foo/jar.class. But realistically, how often people name their main class jar? Why can't we disallow this naming and then omit -jar option when running a jar file? JVM should be able to figure it out by .jar extension.

The first step of installing Jboss and Glassfish appserver

Both Jboss and Glassfish application server provide an installer in the form of a self-contained jar file. Users can just download this jar file and run java command to install it in any platform.

To install Jboss appserver 4.0.5:

java -jar jems-installer-1.2.0.GA.jar
To install Glassfish, according to the instruction:
java -Xmx256m -jar glassfish.jar
Jboss jar is around 71M and glassfish zip 60M in size, and I think they are roughly comparable. But notice the difference in JVM options. I don't like having to use -jar option to run a jar file (see my previous post). Glassfish installer needs yet another more advanced JVM option. There is a big difference in usability between running it without options and running it with one or more options. The more options, the more chances for errors.

To be fair to glassfish, I tried java -jar glassfish.jar without -Xmx256m to see if I get OutOfMemoryError. The installation completes in a couple of seconds without any problem, with JDK 1.4.2, JDK 5, or JDK 6 on Windows XP. So it seems safe to just run java -jar glassfish.jar to install it.

[update 1/1/2007]: In Glassfish V2 update 1 released in 12/2007, you do need -Xmx256m option to install it. Glassfish V2U1 may have added more stuff that takes more memory.

[update 11/24/2008]: Changed -Xmx256 to -Xmx256m. Reader Bartek pointed out this error in the comment.

1/26/2007

Override equals and hashCode methods

If you want to override equals method in your class, you should also override hashCode method as well. There are a lot of ways the two methods can be implemented incorrectly.

I found the easiest way is to use the wizard in Eclipse, just running Source | Generate hashCode() and equals()... either from menu or context menu. For example, this is what Eclipse generated for a simple class Scrap with a instance variable number:


/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
final int PRIME = 31;
int result = 1;
result = PRIME * result + number;
return result;
}

/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Scrap other = (Scrap) obj;
if (number != other.number)
return false;
return true;
}
I don't feel I need to modify anything in the 2 generated methods. I especially like the @Override annotation being used in the generated code. It clearly documents the method overriding and enforces the compile-time check.

1/18/2007

Jps output

$JAVA_HOME/bin/jps command lists all java processes, but its output always includes itself, since jps is also a java program. So you will always get at least one entry:

C:\> C:\jdk5\bin\jps -l
1856 sun.tools.jps.Jps
I don't think I ever care about jps process itself. So I always run my wrapper script to filter out sun.tools.jps.Jps:
C:\bin> more jps.bat
@echo off
echo -------------------
C:\jdk5\bin\jps -l | grep -v sun.tools.jps.Jps
In Linux, I simply define a bash alias in $HOME/.bashrc:
alias jps='$JAVA_HOME/bin/jps | grep -v sun.tools.jps.Jps'
Or a tcsh alias in .tcshrc or .cshrc:
alias jps '$JAVA_HOME/bin/jps | grep -v'

1/17/2007

Tomcat common/lib vs shared/lib

What is the difference between Tomcat common/lib and shared/lib? Simply put, common/lib contains jar files to be used by both the web server and all deployed web applications. shared/lib contains jar files that are available to all deployed web applications.

Their scope is confusing. From the names (common and shared) alone, I really can't tell which one is used for which purpose. The fact the two directories are located at the same level ($CATALINA_HOME/common $CATALINA_HOME/shared) makes it more confusing. If shared directory were under $CATALINA/webapp, it would make it obvious that it is to be used by all webapps.

1/15/2007

Tomcat startup failed: Address already in use: JVM_Bind

Tomcat failed to startup with the following error in %CATALINA_HOME%\logs\catalina.2007-01-11.log:

Jan 11, 2007 8:59:33 AM org.apache.catalina.core.StandardServer await
SEVERE: StandardServer.await: create[8005]:
java.net.BindException: Address already in use: JVM_Bind
at java.net.PlainSocketImpl.socketBind(Native Method)
at java.net.PlainSocketImpl.bind(PlainSocketImpl.java:359)
at java.net.ServerSocket.bind(ServerSocket.java:319)
at java.net.ServerSocket.<init>(ServerSocket.java:185)
at org.apache.catalina.core.StandardServer.await(StandardServer.java:372)
at org.apache.catalina.startup.Catalina.await(Catalina.java:615)
at org.apache.catalina.startup.Catalina.start(Catalina.java:575)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:294)
at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:432)
It appears the port number 8005, where tomcat is listening for SHUTDOWN signal, is already used by another process. It's a little bit odd, since I just started Windows and ran Tomcat as the first command.

I suspected it was some windows service program that automatically started when windows is started. It turned out to be some apple software is running on port 8005. After I removed that apple software, I was able to run Tomcat using the default port number 8005. This site lists port numbers used by some apple software.

Alternatively, I could just change Tomcat to use another port number by editing %CATALINA_HOME%\conf\server.xml:
<Server port="8006" shutdown="SHUTDOWN">

1/10/2007

How to run Tomcat on a different port number

Tomcat web server by default runs on port number 8080, which is also the default port number used by some other popular servers like JBoss, JavaEE SDK, Sun Java System Application Server. When this port number is already used by another process, you will get the following error:

logs/catalina.2007-01-09.log:
...
INFO: Starting Servlet Engine: Apache Tomcat/5.5.20
Jan 11, 2007 9:36:12 AM org.apache.catalina.core.StandardHost start
INFO: XML validation disabled
Jan 11, 2007 9:36:13 AM org.apache.coyote.http11.Http11BaseProtocol start
SEVERE: Error starting endpoint
java.net.BindException: Address already in use: JVM_Bind:8080
at org.apache.tomcat.util.net.PoolTcpEndpoint.initEndpoint(PoolTcpEndpoi
nt.java:297)
at org.apache.tomcat.util.net.PoolTcpEndpoint.startEndpoint(PoolTcpEndpo
int.java:312)
at org.apache.coyote.http11.Http11BaseProtocol.start(Http11BaseProtocol.
java:150)
at org.apache.coyote.http11.Http11Protocol.start(Http11Protocol.java:75)

at org.apache.catalina.connector.Connector.start(Connector.java:1089)
at org.apache.catalina.core.StandardService.start(StandardService.java:4
59)
at org.apache.catalina.core.StandardServer.start(StandardServer.java:709
)
at org.apache.catalina.startup.Catalina.start(Catalina.java:551)
To use a different port number, back up and edit the port attribute value of Connector element in $CATALINA_HOME/conf/server.xml:
<!-- Define a non-SSL HTTP/1.1 Connector on port 8080 -->
<Connector port="8081" maxHttpHeaderSize="8192"
Restart Tomcat ($CATALINA_HOME/bin/startup.sh on Unix or %CATALINA_HOME%\bin\startup.bat on Windows), and check server status at URL http://localhost:8081

1/09/2007

How to run Tomcat manager web application

1. Add the security role manager to $CATALINA_HOME/conf/tomcat-users.xml, and assign this role to a username, say tomcat:

<role rolename="manager"/>
<user username="tomcat" password="tomcat" roles="tomcat,manager"/>
2. Start Tomcat:
$CATALINA_HOME/bin/startup.sh
(%CATALINA_HOME%\bin\startup.bat on windows)
3. Browser the URL http://localhost:8080, and click the Tomcat Manager link on the upper-left corner. In the basic login page, enter username tomcat and password tomcat, as specified in conf/tomcat-users.xml. Tomcat Manager web application allows you to view Tomcat server info, deploy and undeploy webapps, and other simple management tasks.

1/05/2007

Always write a no-arg constructor in a java class

When a java class contains no constructor, the compiler will generate a default no-arg constructor. But it's always a good idea to explicitly write this no-arg constructor. Some good reasons:

1. To future-proof this class and all its subclasses.

Constructors in all subclasses always calls the superclass' constructor at the first line, explicitly or implicitly. If the superclass does not define any explicit constructor, a default no-arg constructor is called. Therefore, subclasses rely on the fact that a no-arg constructor exists in the superclass. Otherwise, they will fail to compile.

However, the default no-arg constructor will not be generated by javac when the class defines any constructor. So it's likely that when a parametered constructor is added to superclass in the future, the no-arg constructor cease to exist, which will cause subclasses to fail to compile.

2. To future-proof conformance to certain Java standards.

In many Java standards or specifications, components are required to have a no-arg constructor. For example, JavaBeans, EJB, Servlet, JPA, etc, because these component classes are instantiated and managed by their respective containers. For the same reason as above, a default no-arg constructor may exist now by disappear in the future. By defining a no-arg constructor, your code is more maintainable and robust.

3. It's easy. Most IDEs like Eclipse or NetBeans can generate it for you.

4. Control its access modifier, making it private or protected, rather than public.

The generated no-arg constructor is always public, which may not be the best. For example, for utility classes that only contains static methods, clients never need to instantiate instances. Or for singleton, you also want to prevent external instantiation. Therefore, a private (in some rare cases, protected) no-arg constructor is more appropriate.

1/03/2007

Variable might not have been initialized

In Java, class instance variables and static variables have default values: null for all object types, false for boolean primitive and 0 for numeric primitives. But local variables inside a method have no defaults.

Consider the following code snippet:

public static void main(String[] args){
java.util.Date d;
System.out.println(d);
}
It will fail to compile with this error:
variable d might not have been initialized
System.out.println(d);
1 error
However, the following will compile and run successfully:
public static void main(String[] args){
java.util.Date d;
}
Because the rule is that all local variables must be initialized before they are first read. So it's perfectly OK to first declare a local variable without initializing it, initialize it later, and then use it:
public static void main(String[] args){
java.util.Date d;
//do more work
d = new java.util.Date();
System.out.println(d);
}
It may be an old habit from languages like C, where you need to declare all local variables at the beginning of a code block. But in Java with this rule in place, it's best to defer declaring local variables till needed.