Extreme Java When vanilla Java is not enough

8Jul/110

TDD with Wicket

I'm starting to get in love with Wicket. I can easily isolate webpages, programming and testing. While my fictional webdesigner makes evil plans about the pages, my programmer (that's me) can develop all pages using TDD. And I'm not only talking about making unit tests for UI. I'm talking about creating the test BEFORE the implementation. See how I'm achieving this:

Let's create a new page. Since the design will be made by the designer, I only invest on the essential tags. But, even before creating my HTML, I can create the tests. From the requirement, I will have two screens: one list of all cities grouped by state, and a page with a list of vCards for that city. First, the tests (after all, it's TDD!):

@Test
public void testRendering() {
  WicketTester t = new WicketTester(CitiesPage.class);
  t.startPage(CitiesPage.class);
  t.assertRenderedPage(CitiesPage.class);
}
@Test
public void testStateBinding() {
  WicketTester t = new WicketTester(CitiesPage.class);
  t.startPage(CitiesPage.class);
  t.assertComponent("states", ListView.class);
  t.assertListView("states", getStates());
  t.assertComponent("states:0:name", "name-of-first-state");
}
@Test
public void testCityBinding() {
  // new tester, start, assertList...
  t.assertBookmarkablePageLink("states:0:cities:0:link",
                               NextPage.class, "city=0");
}

I put all tests here for simplicity, but, in TDD, I create only the first test, then correct, go for the second and so on. This will fail. I solve by creating the stub page and the bindings:

<div wicket:id="states">
  List of State <span wicket:id="name">Lorem ipsum</span>
  <div wicket:id="cities">
    <span wicket:id="name">City's name</span>
    <a href="#" wicket:id="link">Go for it</a>
  </div>
</div>

And, the Wicket's WebPage constructor:

public MyPage() {
  add(new ListView("states", getStates()) {
    protected void populateItem(ListItem item) {
    }
  });
}

And, the best part of TDD is I can make my code step-by-step: I implement the list binding, then I implement the list iteration, then, the cities binding inside "populateItem", until I finish the page. Much easier than implementing then testing. And it's a lot error-proof, too. When we make the code before the test, it's common to make a test that "just works" and having a lot of small glitches. Thinking about the test first, we develop code that needs to pass the requirements.

I finally fulfilled my dream of doing real TDD, from UI to persistence! Thanks wicket team! Now, I only hope it does not have any performance (or security) problems.

The last step (that usually takes huge time from me) is making a design that fits the code. But this part will be darn easy: I make a free (as in "freedom") design with a WYSIWYG editor and add the wicket markups, testing it direct on Safari/Firefox/IE/Opera, without the need of a slow "edit-deploy-run-test" cycle (mandatory for JSF or similar).

Filed under: Java EE No Comments
7Jul/110

vHost capabilities with Wicket

I started using Wicket because I liked how easy is to create SEO URLs and design-centric applications. One crazy feature I got working was customizing an application based on the vhost. The example I asked on StackOverflow used a fictional "abc.com" hosting with "abc.com.br" and "abc.com.pl" aliases.

The example works as this: all three vhosts are on the same codebase (i.e. the same "host" on Tomcat, with three aliases) and shows the same data. The difference between ".com", ".com.br" and ".com.pl" relies on how the data is shown to the user. There are two major country-related materials:

  1. Page design - ".com" must see an American tribute (USA is #1, American Flag, etc); ".com.br" must show Brazilian stuff (Samba, Soccer teams, etc); ".com.pl" shows Polish material. This was really easy, using a ResourceStreamLocator in my Wicket Application:
    getResourceSettings().addResourceFolder("");
    getResourceSettings().setResourceStreamLocator(
        new ResourceStreamLocator() {
      @Override
      public IResourceStream locate(Class clz, String path) {
        String host = ((WebRequest) RequestCycle.get().getRequest())
            .getHttpServletRequest().getServerName();
        String basePath = trimFolders(path);
        IResourceStream res = super.locate(clz, host + "/" + basePath);
        return (res != null) ? res : super.locate(clz, basePath);
      }
      private String trimFolders(String path) {
        return path.substring(path.lastIndexOf("/") + 1);
      }
    });
  2. Contextual URL mounting - this part was hard. Assume a page named "Page1". It must be accessed using "abc.com/page1", "abc.com.br/pagina1" and "abc.com.pl/strona1", but not with combinations (e.g. "abc.com/strona1"). After asking in SO, I got an answer from "biziclop" that lead me to the solution I wanted. It's a servlet filter mapping vhost to WicketFilter instances, isolating Wicket application instances (as biziclop sugested):
    @WebFilter(urlPatterns = "/*")
    public static class Filter implements IWebApplicationFactory,
                                          javax.servlet.Filter {
      private final Map filters = new HashMap();
      private final ThreadLocal hosts = new ThreadLocal();
      private FilterConfig config;
     
      @Override
      public void init(FilterConfig filterConfig) {
        this.config = filterConfig;
      }
      @Override
      public void destroy() {
        for (WicketFilter w : filters.values()) {
          w.destroy();
        }
        filters.clear();
      }
      @Override
      public void doFilter(ServletRequest request,
          ServletResponse response,
          FilterChain chain) throws IOException, ServletException {
        hosts.set(request.getServerName());
        try {
          getFilterForHost().doFilter(request, response, chain);
        } finally {
          hosts.remove();
        }
      }
      private WicketFilter getFilterForHost() throws ServletException {
        String host = hosts.get();
        if (!filters.containsKey(host)) {
          WicketFilter w = new WicketFilter() {
            @Override
            protected IWebApplicationFactory getApplicationFactory() {
              return Filter.this;
            }
          };
          w.init(config);
          filters.put(host, w);
        }
        return filters.get(host);
      }
      @Override
      public WebApplication createApplication(WicketFilter wf) {
        return new WicketApp(hosts.get());
      }
    }
Filed under: Java EE No Comments
18Aug/100

Simple REST WS in Java

It's really simple to do REST Webservices using JavaEE 6. Create an class that extends Application with an ApplicationPath annotation:

import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application;
 
@ApplicationPath("rest")
public class ApplicationConfig extends Application {
}

Then, use proper annotations to publish your REST services:

import javax.ws.rs.FormParam;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
 
@Path("test")
public class TestREST {
  @GET
  @Produces("application/xml")
  public Result noParms() {
    return new Result(1, "OK");
  }
  @GET
  @Path("/{p}")
  @Produces("application/xml")
  public Result oneParameter(
      @PathParam("p") String parm) {
    return new Result(1, "Hi, " + parm);
  }
  @POST
  @Produces("application/xml")
  public Result twoParms(
      @FormParam("n") String name,
      @FormParam("s") String sname) {
    return new Result(2, sname + ", " + name);
  }
}

Invoke with simple GET request (like "http://server/myapp/rest/test/Bro") or an HTML POST form. "Result" is a simple POJO with JAXB annotations.

Tagged as: , No Comments
23Apr/100

Mixing JPA with JAXB/JAXWS

With JavaEE 6, you can publish an SOAP WebService as easy as 1-2-3. It mixes well with JPA, but I give you a small advice: if you need bidirectional ORM mappings, one of them MUST be @XmlTransient. Otherwise, you will receive a com.sun.xml.ws.streaming.XMLStreamReaderException ("unexpected XML tag. expected: {yourns}yourtag but found: {http://schemas.xmlsoap.org/soap/envelope/}Envelope").

Tagged as: , , No Comments
8Apr/103

h:selectManyCheckbox with multiple columns/rows

If you ever tried to use the component, you had a bad time figuring out how to split the checkbox on multiple rows - there's no simple way to do that.

Let's talk about a feature of the tag: it can receive both SelectItem and SelectItemGroup. This means you can create a group of SelectItem easily. Example: if you have a Role list grouped by categories, the List can have a list of SelectItemGroup and these can have a list of SelectItem with the roles.

Pretty nice, but the items are rendered with the group orientation: this means JSF will render an horizontal table for the groups with nested horizontal tables for the items. Still ugly!

You can solve this using Tomahawk, but I think it's too much trouble only to get this simple requirement. I prefer using a pure-JSF solution like a new Renderer. Mojarra's renderer makes this job very easy:

public class MyRenderer
    extends SelectManyCheckboxListRenderer {
 
  // keeps track of current rendering
  private boolean inner;
 
  // overriding with synchronized
  @Override
  public synchronized void encodeEnd(
      FacesContext context,
      UIComponent component) throws IOException {
    super.encodeEnd(context, component);
  }
 
  @Override
  protected void renderBeginText(
      UIComponent component, int border,
      boolean alignVertical, FacesContext context,
      boolean outerTable) throws IOException {
    // are we at the inner table?
    this.inner = !outerTable;
    super.renderBeginText(component, border,
      alignVertical ^ inner, context, outerTable);
  }
 
  @Override
  protected void renderEndText(
      UIComponent component, boolean alignVertical,
      FacesContext context) throws IOException {
    super.renderEndText(component,
      alignVertical ^ inner, context);
    // reset after inner table is rendered
    this.inner = false;
  }
 
  @Override
  protected void renderOption(
      FacesContext context, UIComponent component,
      Converter converter, SelectItem curItem,
      Object currentSelections,
      Object[] submittedValues,
      boolean alignVertical, int itemNumber,
      OptionComponentInfo optionInfo)
      throws IOException {
    super.renderOption(context, component, converter,
      curItem, currentSelections, submittedValues,
      alignVertical ^ inner, itemNumber, optionInfo);
  }
}

The trick is pass "alignVertical" parameter XOR inner state. This will change the alignment for the inner table. If you use "pageDirection" as layout, the inner table will use "lineDirection" and vice-versa. Using the "roles" example, the groups will be aligned horizontally and their roles, vertically.

Now, if you don't want to use groups, you can still benefit - create pseudo-groups for each N elements.  This will give you a matrix-like checkbox list.

7Apr/100

Using f:selectItems with JPA entities

It's a common scenario: you must do a "SELECT e FROM Entity e" with JPA and pass it to a <h:selectOneMenu> or a <h:selectManyList>. Unfortunately, if you google it, you will find a lot of strange solutions.

I've tested a simple solution on JavaEE 6. On my managed bean, I can define a property like this:

...
public class MyBean {
  ...
  @PersistenceContext
  private EntityManager em;
 
  public Converter getConverter() {
    return new Converter() {
      @Override
      public Object getAsObject(
          FacesContext fc,
          UIComponent uic,
          String string) {
        return (string == null)
          ? null
          : em.find(MyEntity.class,
                    Long.parseLong(string));
      }
      @Override
      public String getAsString(
          FacesContext fc,
          UIComponent uic,
          Object o) {
        return (o == null)
          ? null
          : Long.toString(((MyEntity) o).getId());
      }
    };
  }
}

According to JSF specification, only managed beans can be injected. This is why I declared it as an inner class.

This way, the converter allows you to work only with entities, instead of manually storing IDs on the managed bean. This means the page can bind to this property when a conversion is needed:

<h:selectOneMenu value="#{myBean.myEntitySelection}">
  <f:selectItems value="#{myBean.myEntityList}"/>
  <f:converter binding="#{myBean.converter}"/>
</h:selectOneMenu>

One last step: your Entity must have an working "equals" method. If you forget this, you will receive the message "Validation Exception: Value is invalid".

Usually, a boilerplate, like this one generated by NetBeans will suffice:

@Override
public boolean equals(Object obj) {
  if (obj == null) {
    return false;
  }
  if (getClass() != obj.getClass()) {
    return false;
  }
  final MyEntity other = (MyEntity) obj;
  if (this.id != other.id
      &amp;&amp; (this.id == null
          || !this.id.equals(other.id))) {
    return false;
  }
  return true;
}

Works like a charm on JSF 2, but I haven't tested on JSF 1.2.

BTW, this solution can be refactored to became a more generic: create a base entity class that declares a "getId" method returning Serializable. Then, the converter can be a class receiving an entity manager and the persistent class.

22Mar/100

Unit Testing EJBs 3.1 with Glassfish Embedded

Pretty simple, indeed. You need the "glassfish-embedded-all-3.0-b74b.jar", and use the new EJBContainer like this:

MyBean ejb = (MyBean) EJBContainer
    .createEJBContainer()
    .getContext()
    .lookup("java:global/classes/MyBean");
assertEquals(3, ejb.add(1, 2));

And remember that you can use a deployment descriptor on your test classpath to customize both transaction and datasource for your unit testing.

If you are using maven, use this dependency instead of javaee-api:

<dependency>
   <groupId>org.glassfish.extras</groupId>
   <artifactId>glassfish-embedded-all</artifactId>
   <version>3.0-b74b</version>
   <scope>provided</scope>
</dependency>

If you put "javaee-api" as "provided" and GF as "test", you will receive nasty "Abscent Code" errors.

29Dec/090

Conversational Scope on JSF 2.0 (without Custom Scope)

JSF 2.0 is finally out. One thing that you will notice is the absence of a "conversational" scope. That would solve a lot of problems I have, but, unfortunately, I must wait for the next release. Or not?

There's no silver bullet to solve it, but I found a simple workaround using "view" scoped beans. Works for most cases - unless you need redirection or other advanced requirements.

First, your "conversational" managed bean must be have a "view" scope:

@ManagedBean(name="tbean")
@ViewScoped
public class TBean {
  private String name;
  private String result;
 
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public String getResult() {
    return result;
  }
  public String sayHi() {
    result = "Hi, " + name;
    return "";
  }
}

No big deal: just a POJO with @ViewScoped. The catch is you must return empty on your action. The view is simple, too:

<h:body>
  <h:form rendered="#{empty tbean.result}">
    Name: <h:inputText value="#{tbean.name}"/>
    <h:commandButton value="hi!"
        action="#{tbean.sayHi}"/>
  </h:form>
  <h:panelGroup rendered="#{not empty tbean.result}">
    <h1><h:outputText value="#{tbean.result}"/></h1>
    <h:button value="back" outcome="index"/>
  </h:panelGroup>
</h:body>

Nothing really new: classic JSF 1.0 magic tricks with the rendered attribute. The real catch, although, is the view scope. The bean will remain as long as you keep the current view (by returning empty on your actions). The "back" button clears the form and conditionally rendered components will give the feel of different pages.

This means you can easily have an three-page CRUD (list, view, edit), or an wizard-style page, that will reset when you enter it and keep state as long as you stay on "subpages".

Your page will grow fast using this method, but, since Facelets support is now native, you can use to keep this solution modular.

21Oct/090

Booleans in JPA (the portable way)

If you want to map a boolean value in JPA, you will have a headache if your RDBMS is Oracle. Since it does not support a boolean data type, you usually create a CHAR(1) 'Y'/'N' field and use a lot of bad words to describe the feeling you have when you find out that JPA does not support boolean-to-char convertion.

A nice and portable workaround is described here. The trick is to remember why getter/setter encapsulation is a good pratice - you can do a lot more than just plain old get/set:

private char enabled;
 
public boolean isEnabled() {
  return enabled == 'Y';
}
public void setEnabled(Boolean enabled) {
  this.enabled = (enabled ? 'Y' : 'N');
}
20Jul/090

Using JBoss as a remote datasource provider

After some trial-and-error, I managed to use a JBoss 5 as a JNDI server and a Tomcat as a JNDI client. If you plan to make a JBoss DataSource public, just add a "<use-java-context>false</use-java-context>" to your "<local-tx-datasource>".

Tomcat is easy to configure. You need to add a resource like this one ("look mom! no password!"):

<Resource name="jdbc/myds"
    auth="Container"
    type="javax.sql.DataSource"
    factory="org.jnp.interfaces.NamingContextFactory"
    URL="jnp://jboss-host:1099/jdbc/mydsOnJboss" />

The "jdbc/mydsOnJBoss" part is the same as the "<jndi-name>" on JBoss datasource. The real trick is the classpath. Go to JBOSS_HOME/client and copy these files:

  • jboss-logging-jdk (or jboss-logging-log4j)
  • jboss-logging-spi
  • jnp-client
  • jboss-client
  • jboss-common-core
  • jboss-integration
  • jboss-remoting
  • jboss-security-spi
  • jboss-serialization
  • jbosscx-client
  • jboss-javaee (optional if your Tomcat has the javax.transation.* already)

The first three (jnp-client, jboss-logging-*) are obvious, since they are explicit dependencies (i.e. you receive a "ClassNotFoundException"). The others are implicit - you don't receive a CNFE, you get a "ClassCastException" (cannot cast javax.naming.Reference to javax.sql.Datasource). It is evil - no docs, no log, only "-verbose:class" helped me.

With the right libs and the right configuration, you can use @Resource (or Spring's JNDI lookup) the same way as a locally defined datasource - without any sensitive information exposed.

As a final note, you don't need the JDBC driver on client.