Extreme Java When vanilla Java is not enough

27Mar/090

NetBeans Platform + JPA + Derby embedded

If you want to use NetBeans Platform and JPA together, there's a great tutorial on NB's site. Unfortunatelly, it explains how to do it with an external database and using an external JAR for your entities.

If you want to have a entity module with your classes (instead of an external JAR and a library wrapper), no big deal - it works! You can follow GJ's tutorial, but you will create a module project instead and you will not have NB's wizards to help creating entity classes.

I also created a module install on my Derby wrapper, with this line:

FileUtil configRoot = FileUtil.getConfigRoot();
System.setProperty("derby.system.home",
    FileUtil.toFile(configRoot).getCanonicalPath());

This defines where Derby will create database files (user's dir, in this case).

BTW, if a "no suitable driver found" is thrown, you forgot to add a dependency between JPA wrapper (EclipseLink, TopLink, OpenJPA or Hibernate) and JDBC wrapper.

19Mar/090

Java Service Provider Interface (SPI)

Long time ago, I had a bad time trying to develop a "plugin mechanism" to my "open source Toad". What I didn't know is how to use the service provider infrastructure avaliable since Java 1.3 (what a shame!).

If you want to create a service provider interface (SPI):

  1. Define an interface or abstract class (this will be implemented/overrided by the provider)
  2. Use "ServiceLoader.load" when you need the concrete instances (it's an iterator that can be used in a "foreach")

If you want to provide a service (the plugin itself):

  1. Implement/override the code of SPI
  2. Create a META-INF/services folder
  3. Create a file with the same name of the SPI class and add the name of the concrete classes from step 1

And we are done! A simple, yet robust, solution to add extensibility.

Tagged as: , No Comments
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.

16Mar/090

Spring classes and their long names

Spring team likes big names. One of the biggest is "SimpleRemoteStatelessSessionProxyFactoryBean". This is not a problem, since I'm not a Fortran programmer. Unfortunatelly, I found two classes with similar names that aren't type-safe (i.e.: I don't receive a ClassCast or similar if I swap them): MethodInvokingFactoryBean e MethodInvokingJobDetailFactoryBean. I use the latter a lot, but, after using NB's autocomplete feature, I selected the former instead:

<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
  <property name="targetObject" ref="cache"/>
  <property name="targetMethod" value="reload"/>
</bean>

Results? NullPointerException:

org.quartz.SchedulerException: Registration of jobs and triggers failed: null [See nested exception: java.lang.NullPointerException]
  at org.springframework.scheduling.quartz.SchedulerFactoryBean.registerJobsAndTriggers(SchedulerFactoryBean.java:861)
  at org.springframework.scheduling.quartz.SchedulerFactoryBean.afterPropertiesSet(SchedulerFactoryBean.java:649)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1368)
  at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1334)
  ... 13 more
Caused by: java.lang.NullPointerException
  at org.quartz.core.QuartzScheduler.addJob(QuartzScheduler.java:808)
  at org.quartz.impl.StdScheduler.addJob(StdScheduler.java:288)
  at org.springframework.scheduling.quartz.SchedulerFactoryBean.addJobToScheduler(SchedulerFactoryBean.java:883)
  at org.springframework.scheduling.quartz.SchedulerFactoryBean.addTriggerToScheduler(SchedulerFactoryBean.java:906)
  at org.springframework.scheduling.quartz.SchedulerFactoryBean.registerJobsAndTriggers(SchedulerFactoryBean.java:842)
  ... 16 more

This wasn’t easy to solve, since the NPE wasn’t obvious. Both MIFB and MIJDFB are “factory” instances (they create real instances as needed), and, in this case, no type check was done.

16Mar/090

Jasper Reports tutorial – part 2 – tables

I never planned a "part 2" about Jasper Reports, but the previous "tutorial" lacks a small concept: how do I make tables? It's obvious, but only after you figure it out. If you downloaded Jasper Reports examples, you can look at "datasource" sample. Nice one, but not as simple as you may want.

I only want to add a basic table which row data comes from a Java Collection. It is very easy to adapt the JasperFiller: just change JREmptyDatasource with JRBeanCollectionDataSource.

Adapting JRXML is easy, too, but it not obvious for a newbie. I admit I expected something like a "table" element (blame years of HTML), but in JR, you only need to define the "detail" element with the contents you want to repeat for each element on DataSource. Create it as you want, tune the band height to the height of a row, and you have your HTML-ish table.

BTW, you need to define all fields at the top of your JRXML, since JR's DataSources does not contains metadata.

As a last tip, keep these in mind:

  • <title> only appears on first page;
  • <pageHeader> and <pageFooter> appears on every page;
  • <lastPageFooter> apperars only on last page, REPLACING <pageFooter>
12Mar/090

Jasper Reports (quick and dirt) tutorial

If you want a simple Jasper Reports tutorial, you will have a bad time googling it. The official site has a nice theorical introduction, but after reading it, you will not have a working "hello world" example. Unfortunatelly, the "definitive guide" is a book you need to buy.

Since I prefer a "try-before-you-buy" approach, I asked Google and I've found a simple "hello world" JRXML reading this tutorial from David Heffelfinger's article. Good one, but I will upgrade it. The XML can use XSD:

<?xml version="1.0" encoding="UTF-8"?>
<jasperReport name="report name"
  xmlns="http://jasperreports.sourceforge.net/jasperreports"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports
    http://jasperreports.sourceforge.net/xsd/jasperreport.xsd">
  <detail>
    ...
  </detail>
</jasperReport>

If you are using NetBeans 6, go to "Tools > Options > Miscellaneous > Files", add "jrxml" extension and associate with "application/xml". Now, it will autocomplete jasper tags for you. You can use iReport NB plugin, too, but I like to know how it work.

Well, you need to compile this JRXML before using it. David shows how to do programmatically. If you want to add only the compiled version to your JAR file, you can add this to your Ant build file (this is a NB version, change parameters as needed):

<target name="-post-init">
  <!-- Init jasper ant task -->
  <taskdef classpath="${javac.classpath}"
      classname="net.sf.jasperreports.ant.JRAntCompileTask"
      name="jrc" />
</target>
<target name="-post-compile">
  <!-- without a tempdir, JR may
       create files on NB folder! -->
  <mkdir dir="${build.dir}/jasper"/>
  <!-- compile "src/JRXML" to "build/JASPER" -->
  <jrc destdir="${build.classes.dir}"
       tempdir="${build.dir}/jasper">
    <src>
      <fileset dir="${src.dir}" includes="**/*.jrxml" />
    </src>
    <classpath>
      <path path="${javac.classpath}"/>
    </classpath>
  </jrc>
</target>

Now you have a ".jasper" file on your build dir, together with your compiled classes - just ready for use! Let's use it:

InputStream in = getClass().getResourceAsStream("/my-pkg/myReport.jasper");
JasperPrint jasperPrint = JasperFillManager.fillReport(in,
        new HashMap(), new JREmptyDataSource());
JasperExportManager.exportReportToHtmlFile(jasperPrint,
        "output-path/report.html");

Pretty easy, huh? One last note - you will need more libs than just "jasperreports.jar" on your classpath:

  • commons-digester
  • commons-logging
  • commons-collections
  • commons-beanutils
  • itext (only if you want to export as PDF)