Extreme Java When vanilla Java is not enough

22May/090

Using Spring with Mojarra InjectionProvider

Are you using SpringBeanFacesELResolver to handle dependency injection on managed beans? It works nice, but your faces-config grows fast with this approach.

Two months ago, I posted about using Spring injection outside application context. I forgot to mention that the same trick can be used to replace ELResolver solution if you are using Mojarra as your JSF provider.

You only need to add a servlet context parameter:

<context-param>
  <param-name>
    com.sun.faces.injectionProvider
  </param-name>
  <param-value>
    mypkg.SpringJSFInjectionProvider
  </param-value>
</context-param>

And the implementation of SpringJSFInjectionProvider is as simple as:

public class SpringJSFInjectionProvider
       implements InjectionProvider {
  private WebContainerInjectionProvider wcip =
      new WebContainerInjectionProvider();
 
  @Override
  public void inject(Object bean)
         throws InjectionProviderException {
    FacesContextUtils
      .getWebApplicationContext(
         FacesContext.getCurrentInstance())
      .getAutowireCapableBeanFactory()
      .autowireBeanProperties(bean,
         AutowireCapableBeanFactory.AUTOWIRE_NO,
         false);
    wcip.inject(bean);
  }
  @Override
  public void invokePreDestroy(Object bean)
         throws InjectionProviderException {
    wcip.invokePreDestroy(bean);
  }
  @Override
  public void invokePostConstruct(Object bean)
         throws InjectionProviderException {
    wcip.invokePostConstruct(bean);
  }
}

Adding this, you can shrink your faces-context, removing all "managed-property" tags. Your managed beans can look more JavaEE 5 after you change this:

private BO bo;
 
public void setBo(BO bo) {
  this.bo = bo;
}

To this:

@Resource(name="bean-on-appctx")
private BO bo;

No setter, no ELResolver. This means less code to maintain! If you plan to migrate from Spring to EJB, this means you will only need to promote the BO to an stateless bean and change @Resource to @EJB!

7May/090

Executable WAR files using Winstone and Maven

After a couple of years developing webapps, I'm starting to get problems to design a non-web UI. Not a big deal, since I only use Swing on personal projects. The biggest problem with web projects is the need of at least a servlet container. If you host a lot of projects, Tomcat, JBoss, Glassfish and Geronimo are good choices. But, if you need to host only one "web-container-only" project, Jetty or Winstone are way better.

I'm planning to use maven instead of ant for all of my projects, both personal and professional. It is easier to maintain and more IDE-portable. When I'm developing, I can use "maven jetty:run" to automatically compile and start Jetty (ctrl-c ends the server). The whole process is faster than a "ant dist / deploy / OOM / kill -9" when using Tomcat. You only need to add jetty plugin to your POM (inside "project > build > plugins"):

<plugin>
  <groupId>org.mortbay.jetty</groupId>
  <artifactId>maven-jetty-plugin</artifactId>
  <configuration>
    <contextPath>/</contextPath>
  </configuration>
</plugin>

This is useful to develop, but, when I want to create the "executable WAR", I prefer using Winstone - it's even lighter than Jetty. This means I need another plugin:

<plugin>
  <groupId>net.sf.alchim</groupId>
  <artifactId>winstone-maven-plugin</artifactId>
</plugin>

Running "winstone:embed" will create a "xxx-standalone.jar" on "target" folder. This JAR can be run with "java -jar" and your application becames avaliable on "http://localhost:8080/". This plugin has a lot of configurations, and, using maven, you can configure it to run this goal on package phase. Read its manual for more information.

17Mar/090

Password and confirmation with JSF

If you need to validate a field in JSF and the value is dependent of another field (like password/confirmation), BalusC posted a nice tutorial about it. You need to create a JSF Validator and add a to your field. Easier than I thought...

17Mar/090

Spring injection outside application context

Are you using ApplicationContext (and friends) to create a single "spring context" for all your web application? If so, you are on the right way. And it is possible that you feel the need to inject properties where Spring isn't accessible (like a Servlet Filter). You can use this little trick:

public static void inject(ServletContext context,
    Object bean) {
  WebApplicationContext wCtx =
      WebApplicationContextUtils
          .getWebApplicationContext(context);
  if (wCtx != null) {
    wCtx.getAutowireCapableBeanFactory()
        .autowireBeanProperties(bean,
            AutowireCapableBeanFactory.AUTOWIRE_NO,
            false);
  }
}
17Mar/090

Hibernate JPA and Enums

Assume you have a simple enum:

public enum Status {
  ACCEPTED, REJECTED, NOTREADDEN
}

And your legacy database stores it as ordinal values (ACCEPTED = 0, REJECTED = 1, NOTREADDEN = 2). For reasons lost in time, DBA created the column as "varchar". If you want to use JPA, you will have a bad time using Hibernate:

java.lang.IllegalArgumentException: No enum const class mypkg.Status.1
  java.lang.Enum.valueOf(Enum.java:196)
  org.hibernate.type.EnumType.nullSafeGet(EnumType.java:110)

After digging into EnumType.java, I noticed it is hardcoded "if-varchar-then-name-else-ordinal". I assume they never dealed with ancient, legacy databases.

If I switch to TopLink, it works as expected... One thumb down to Hibernate...

17Mar/090

JAAS and Filters

Small tip of the day. If you define a servlet filter and container managed security on the same application, keep these in mind:

  • If your filter is "url-mapped", it is executed BEFORE the security manager;
  • If it is "servlet-mapped", it is executed AFTER the security manager.

I tested it when developing a filter to handle "user life cycle" (expired passwords, agreement signing, etc). If I map both filter and security to "/*", filter was run. If I map security to "/*" and filter to "Faces Servlet", it is not executed until authenticated (even when accessing "/faces/index.jsp").

Tagged as: , , No Comments
16Mar/090

Tomcat manager with SSO and a different Realm

Tomcat Manager's default configuration isn't pratical (nor secure): you must store your users and passwords in a plain XML file. Of course, you can change the "<Realm>" definition on "<Engine name='Catalina'>", but it has no effect if you need a host with Single Sign On.

Since Manager needs to share the same host with managed applications, you need to create a context.xml for your Manager:

<?xml version="1.0" encoding="UTF-8"?>
<Context path="/manager" privileged="true">
  <Realm className="my.secure.and.custom.Realm"/>
</Context>

Put it on "conf/<engine>/<host>/manager.xml". The "privileged='true'" will prevent a "java.lang.SecurityException: Servlet of class org.apache.catalina.manager.HTMLManagerServlet is privileged and cannot be loaded by this web application".

You must change "webapps/manager/WEB-INF/web.xml" and replace "<role-name>manager</role-name>" with the name of the role you want.

21Aug/082

MQSeries not closing connections

I got this error while connecting to MQSeries:

MQJE001: An MQException occurred: Completion Code 2, Reason 2009
MQJE016: MQ queue manager closed channel immediately during connect
Closure reason = 2009

After some trial-and-error, I found the problem: MQ's InitialContext opens a connection, but only closes it if I close the IC itself:

ic.close();

Since my application creates a lot of instances of InitialContext, a lot of connections got leaked, giving that annoying error.

+1 to the IBM's hall-of-shame, section "useless error messages".

18Jun/080

Changing HSQLDB in-process database default password

HSQLDB is not the kind of database I can use in enterprise systems (with terabytes of data), but it is specially useful if I need a simple RDBMS to small (or temporary) databases.
While trying it with Glassfish, I got a big problem: if you create an in-process database (using "jdbc:hsqldb:mem" or "jdbc:hsqldb:file" or "jdbc:hsqldb:res"), HSQLDB creates a default user named "SA" with an empty password. But Glassfish does not accept data sources without passwords (I get a "No PasswordCredential found").
To solve this, I grab the HSQLDB sources and changed the org.hsqldb.Database class. The "reopen" method has the following command:

if (isNew) {
  sessionManager.getSysSession().sqlExecuteDirectNoPreChecks(
    "CREATE USER SA PASSWORD \"\" ADMIN");
  logger.synchLogForce()
}

I just changed it to:

if (isNew) {
  sessionManager.getSysSession().sqlExecuteDirectNoPreChecks(
    "CREATE USER " + urlProperties.getProperty("user") +
    " PASSWORD \"" + urlProperties.getProperty("password") +
    "\" ADMIN");
  logger.synchLogForce();
}

Compiling with "ant jar" (in build dir), the new hsqldb.jar will now allow you to create the user based on the credentials passed as login. But this will only work if you compile with a JDK 5, because a lot of methods required by JDBC in JDK 6 are implemented by throwing UnsupportedOperationException.

For some reason, Glassfish and HSQLDB with in-process only works with OpenJPA. I've tryed with Hibernate and TopLink, with really strange results. If I find a solution, I'll post later.

13Jun/080

Java SCBCD 5.0 Certification

I am strudying for the SCBCD certification, and I realized there is almost no free material about it. I found this website and, IMHO it is an incredible source of information.
They also have some materials for other certifications (SCJP, SCWCD, etc), too, but I did not read them yet.