3/30/2008

A servlet-EJB3 sample on JBoss AS 5 beta

This is a simple project illustrating how to deploy and run an EAR that contains an ejb-jar and .war on JBoss 5 beta 4. This project is completely portable and contains no JBoss-specific configurations. It should also work on any other JavaEE application servers (Glassfish v1, v2, WebLogic 10, etc).

I will take advantage of the sample projects bundled inside NetBeans 6.1 beta (earlier versions should also have them, though I haven't checked). Download the NetBeans bundle that includesJavaEE and Glassfish.

1. Inside NetBeans, press Ctrl-Shift-N to create a new project. In the popup window, under Categories choose Samples | Enterprise, then under Projects on the right panel choose Servlet Stateless.

2. On the next window, accept defaults for Name and Location, then click Finish.

3. Under Project tab, you will see a new enterprise project called ServletStateless, which contains 2 sub-projects: ServletStateless-ejb and ServletStateless-war. Everything for this project is already in place.

4. Right click the project ServletStateless (the parent project) and choose build. You will see this output: Building jar: C:\javahowto\ServletStateless\dist\ServletStateless.ear

5. Start JBoss AS all config (not default config). You can also do it inside NetBeans if JBoss has been set as the target server for this project.
cd %JBOSS_HOME%\bin
run.bat -c all
6. Deploy the EAR to JBoss AS. Or inside NetBeans, right click the project node and choose Undeploy and Deploy
cd %JBOSS_HOME%\server\all\deploy
copy C:\javahowto\ServletStateless\dist\ServletStateless.ear .
Make sure it's correctly deployed, checking the output on JBoss console:
22:27:15,859 INFO  [MCKernelAbstraction] installing bean: jboss.j2ee:ear=ServletStateless.ear,jar=ServletState
less-ejb.jar,name=StatelessSessionBean,service=EJB3 with dependencies:
22:27:15,859 INFO [MCKernelAbstraction] and demands:
22:27:15,859 INFO [MCKernelAbstraction] jboss.ejb:service=EJBTimerService
22:27:15,859 INFO [MCKernelAbstraction] and supplies:
22:27:15,859 INFO [MCKernelAbstraction] Class:enterprise.servlet_stateless_ejb.StatelessSession
22:27:16,843 INFO [EJBContainer] STARTED EJB: enterprise.servlet_stateless_ejb.StatelessSessionBean ejbName:
StatelessSessionBean
22:27:16,984 INFO [TomcatDeployment] deploy, ctxPath=/ServletStateless-war, vfsUrl=ServletStateless.ear/Servl
etStateless-war.war
7. Enter the following URL in the browser. Or inside NetBeans right click project node and choose Run.
http://localhost:8080/ServletStateless-war/servlet, you will see this:
 Servlet2Stateless:: Please enter your name
Some notes:

1. Deploying this simple EAR to JBoss default config doesn't work. I had these errors:
22:22:27,937 INFO  [EJBContainer] STARTED EJB: enterprise.servlet_stateless_ejb.StatelessSessionBean ejbName:
StatelessSessionBean
22:22:28,171 WARN [HDScanner] Failed to process changes
org.jboss.deployers.client.spi.IncompleteDeploymentException: Summary of incomplete deployments (SEE PREVIOUS
ERRORS FOR DETAILS):

*** CONTEXTS MISSING DEPENDENCIES: Name - Dependency{Required State:Actual State}

jboss.web.deployment:war=/ServletStateless-war
- jboss.cache:service=TomcatClusteringCache{Start:** NOT FOUND **}
- jboss.cache:service=TomcatClusteringCache{Create:** NOT FOUND **}


*** CONTEXTS IN ERROR: Name - Error

jboss.cache:service=TomcatClusteringCache - ** NOT FOUND **


at org.jboss.deployers.plugins.deployers.DeployersImpl.checkComplete(DeployersImpl.java:576)
at org.jboss.deployers.plugins.main.MainDeployerImpl.checkComplete(MainDeployerImpl.java:559)
at org.jboss.system.server.profileservice.hotdeploy.HDScanner.scan(HDScanner.java:291)
at org.jboss.system.server.profileservice.hotdeploy.HDScanner.run(HDScanner.java:221)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150)
Maybe because JBoss 5 is still at beta 4?

2. In my NetBeans, I set Glassfish as my default target appserver. Your NetBeans should have one target appserver, and I remember NetBeans also supports JBoss, Webspere, WebLogic with plugins. In my projects I also see various deployment descriptors auto-generated by NetBeans. For this simple project you only need web.xml (to specify servlet mapping) and other *.xml files are all redundant.

3. This is the line that injects bean reference to servlet class:

@EJB private StatelessSession sless;

3/24/2008

Install FindBugs plugin in NetBeans 6

To install FindBugs in NetBeans 6, the basic idea is to add an updatecenter configuration to NetBeans plugin manager. It will then periodically keep your installed plugin updated. These are the steps that worked for me. Note that these steps will install FindBugs + PMD + CheckStyle co-bundled plugins.

1, Go to NetBeans Tools -> plugins, click Settings tab. It shows a list of existing update centers like 3rd Party Plugins, NetBeans, NetBeans Beta, Plugin Portal.

2, Click Add button on the right side. You will see a Update Center Customizer popup, asking for Name and URL. Enter the following values. You may also enable Check for updates automatically.

Name: SQE Update Center
URL: https://sqe.dev.java.net/updatecenters/sqe/updates.xml

3, Click OK and you will see it is added the the list of update centers. Otherwise, most likely your network proxy is not properly configured. You can also manually verify the above URL in the browser.

4, Click Available Plugins tab, and then click the Reload Catalog button beneath the tab. After a short while, you will see a long list (close to 100) plugins. Plugins that are already installed are not included here.

5, Click Category column head to sort them. Notice 3 plugins under Quality category: SQE Java, SQE Update Center, SQE Platform.

6, Select all 3 plugins and click Install button. The rest is just clicking a few OK buttons. At the end, you will see 4 new icons on your tool bar: Check Quality, Run FindBugs, Run PMD, Run CheckStyle.

sqe (Software Quality Environment) is a java.net project. It also has instructions for integrate these tools with NetBeans here. But this page is slightly dated, with an invalid updatecenter URL (https://sqe.dev.java.net/updatecenters/sqe/catalog.xml). That page consists largely of screen shots and no way to copy that URL, which is the most critical data.

In sqe home page under Announcement section, it does mention that:
There is a new updatecenter url for NetBeans6 Beta 1 or later compatible development builds (pre-alpha) https://sqe.dev.java.net/updatecenters/sqe/updates.xml.This should allow the PluginManager to detect SQE as as 3 plugins (all other modules are hidden)!

3/23/2008

Enum wrapper for javax.transaction.Status (2)

In this previous post, I wrote about a enum type wrapper around javax.transaction.Status. It uses a static map to hold the mapping between integer status code and enum type. Here is a slightly shorter (better) implementation without using a static mapping. The commented lines are original code:
package javahowto;
import java.util.EnumSet;
import javax.transaction.Status;

public enum TransactionStatusEnum {
STATUS_ACTIVE (Status.STATUS_ACTIVE),
STATUS_COMMITTED (Status.STATUS_COMMITTED),
STATUS_COMMITTING (Status.STATUS_COMMITTING),
STATUS_MARKED_ROLLBACK (Status.STATUS_MARKED_ROLLBACK),
STATUS_NO_TRANSACTION (Status.STATUS_NO_TRANSACTION),
STATUS_PREPARED (Status.STATUS_PREPARED),
STATUS_PREPARING (Status.STATUS_PREPARING),
STATUS_ROLLEDBACK (Status.STATUS_ROLLEDBACK),
STATUS_ROLLING_BACK (Status.STATUS_ROLLING_BACK),
STATUS_UNKNOWN (Status.STATUS_UNKNOWN);

// private static Map<Integer, TransactionStatusEnum> codeToEnums
// = new HashMap<Integer, TransactionStatusEnum>();
//
// static {
// codeToEnums.put(Status.STATUS_ACTIVE, STATUS_ACTIVE);
// codeToEnums.put(Status.STATUS_COMMITTED, STATUS_COMMITTED);
// codeToEnums.put(Status.STATUS_COMMITTING, STATUS_COMMITTING);
// codeToEnums.put(Status.STATUS_MARKED_ROLLBACK, STATUS_MARKED_ROLLBACK);
// codeToEnums.put(Status.STATUS_NO_TRANSACTION, STATUS_NO_TRANSACTION);
// codeToEnums.put(Status.STATUS_PREPARED, STATUS_PREPARED);
// codeToEnums.put(Status.STATUS_PREPARING, STATUS_PREPARING);
// codeToEnums.put(Status.STATUS_ROLLEDBACK, STATUS_ROLLEDBACK);
// codeToEnums.put(Status.STATUS_ROLLING_BACK, STATUS_ROLLING_BACK);
// codeToEnums.put(Status.STATUS_UNKNOWN, STATUS_UNKNOWN);
// }

private Integer statusCode;

public Integer getStatusCode() {
return statusCode;
}

public static TransactionStatusEnum getEnumFor(Integer i) {
// return codeToEnums.get(i);
for(TransactionStatusEnum t : EnumSet.allOf(TransactionStatusEnum.class)) {
if(t.statusCode == i) {
return t;
}
}
throw new IllegalArgumentException("Invalid transaction status code: " + i);
}

@Override public String toString() {
return super.toString() + "(" + statusCode + ")";
}

private TransactionStatusEnum(int statusCode) {
this.statusCode = statusCode;
}
}
The output from the testcase in the previous post:
status code -> enum:
STATUS_ACTIVE(0)
STATUS_MARKED_ROLLBACK(1)
STATUS_PREPARED(2)
STATUS_COMMITTED(3)
STATUS_ROLLEDBACK(4)
STATUS_UNKNOWN(5)
STATUS_NO_TRANSACTION(6)
STATUS_PREPARING(7)
STATUS_COMMITTING(8)
STATUS_ROLLING_BACK(9)

enum -> status code:
STATUS_ACTIVE(0) 0
STATUS_COMMITTED(3) 3
STATUS_COMMITTING(8) 8
STATUS_MARKED_ROLLBACK(1) 1
STATUS_NO_TRANSACTION(6) 6
STATUS_PREPARED(2) 2
STATUS_PREPARING(7) 7
STATUS_ROLLEDBACK(4) 4
STATUS_ROLLING_BACK(9) 9
STATUS_UNKNOWN(5) 5
A third approach is to combine the above 2 approaches by building the mapping inside getEnumFor method so that subsequent calls may not need to iterate over all elements. This can be useful if the enum type has many elements. getEnumFor can be rewritten as:
public static synchronized TransactionStatusEnum getEnumFor(Integer i) {
TransactionStatusEnum en = codeToEnums.get(i);
if (en == null) {
for (TransactionStatusEnum t : values()) {
if (t.statusCode == i) {
en = t;
codeToEnums.put(i, t);
break;
}
}
}
if (en == null) {
throw new IllegalArgumentException("Invalid transaction status code: " + i);
}
return en;
}

3/11/2008

How to initialize a list when declaring it

With array, we can easily declare and initialize it at the same time:

String[] favorites = new String[] {"EJB", "JPA", "GlassFish"};
Or even simpler:
String[] favorites = {"EJB", "JPA", "GlassFish"};
We can do the same with a List using java.util.Arrays.asList method. For example:
package javahowto;

import java.util.Arrays;
import java.util.List;

public class ListTest {
public static final List<String> favorites =
Arrays.asList("EJB", "JPA", "GlassFish");

public static void main(String[] args){
System.out.println("favorites: " + favorites);
}
}

3/09/2008

UnsupportedOperationException and OperationNotSupportedException

For some unimplemented methods, I want to throw some exception instead of leaving it blank. I know there is already such a class in Java but don't know its exact name. So I typed "Operation" and then Ctrl-Space to let NetBeans to complete it. But only javax.naming.OperationNotSupportedException showed up, which is not what I want. After some search, it turns out the right class is java.lang.UnsupportedOperationException. Description from its javadoc:
java.lang.Object
extended by java.lang.Throwable
extended by java.lang.Exception
extended by java.lang.RuntimeException
extended by java.lang.UnsupportedOperationException
All Implemented Interfaces:
Serializable
Direct Known Subclasses:
HeadlessException, ReadOnlyBufferException

public class UnsupportedOperationException
extends RuntimeException

Thrown to indicate that the requested operation is not supported.

This class is a member of the Java Collections Framework.

Since:
1.2