Flexible ADS – Combining popups with ActiveDataService

In this post I showed how to create a simple counter, based on the Active Data Service from ADF Faces. This facility works out of the box with components like:

  • activeCommandToolbarButton
  • activeImage
  • activeOutputText
  • table
  • tree
  • All DVT components

However not always this is enough. There are a bunch use-cases where you want more!

One scenario could be that you have a long-running task in the background and when it is finished, you want to inform the user. Ideally you want to show him a popup which contains some information regarding the scheduled task. Let’s take a look how that is possible with ADF Faces.

As the user is most-likely not interested in watching a ticket/counter, we need to use a (hidden) trick. We use an invisible <af:activeOutputText>, which has one child element (<af:clientListener />):

...
<af:activeOutputText id="activecomp"
  value="#{counterBean.state}" visible="false">
    <af:clientListener type="propertyChange" method="activeDataCallback" />
</af:activeOutputText>
...

The <af:clientListener/> is interested in a “propertyChange” event, which get’s triggered when a property of the component changes. So every time an update is send to the client, the invisible component changes one property, here it is the “value” property. So we leverage that “trick” to call our custom JavaScript activeDataCallback() function when an update reaches the client ;-)

As you can tell from reading the JavaScript-Documentation the client-side event class has been modeled after the JSF ValueChangeEvent, but it is slightly different.

So let’s take a look at the required JavaScript:

...
<af:resource type="javascript">
 activeDataCallback = function(event)
 {
    showPopup();
 }
 showPopup = function()
 {
    var popup = AdfPage.PAGE.findComponentByAbsoluteId("demoPopup");
    popup.show();
 }
</af:resource>
...

In this example the callback is not interested in a property of the event argument. It just want’s to show a popup component, which is nested inside of the page:

...
<af:popup id="demoPopup" contentDelivery="immediate">
 <af:dialog closeIconVisible="false" title="Appointments!"
     visible="true" id="d2">

 <af:outputText value="Real content would go here" id="txtBox"/>

 </af:dialog>
</af:popup>
...

The result looks like this, once the active data arrives the client:

combining CDI producer methods with EL

CDI’s Producer methods are nice to expose any sort of class (e.g. legacy or 3rd party (JDK)). Combining the @Produces with the @Named you can reuse the result in your XHTML JSF page.

Some Java code:

...
@Produces @Named public MyBean getMyBeanImpl()
{
....
return someBean;
}

Now the XHTML can have something like:

...
<h:outputText value="#{myBeanImpl.someOfItsProperties}" />
...

If you want, you can use the @Named with a named value (e.g. @Named(“fooBar”)). Now the fooBar also is required by the EL.

Pretty nice!

Dependency Injection the JSR 330 way

Dependency Injection is not new! There have been several ways of doing DI in your Java application. The idea behind them is well understood, but the actual realization is slightly different: XML files vs Java annotation/classes etc… That can become a pretty religious discussion :-)

With the on-going progress of the “WebBeans” specification, which defines (or defined) some common Java DI API, it was clear that there is need for a more abstract way. The new “at inject” (or Dependency Injection for Java) standard, JSR 330, was born. WebBeans has been renamed to Contexts and Dependency Injection for the Java EE platform (short: CDI). CDI now also leverages the “at inject” API, specified in JSR 330. The main idea behind this new JSR was driven by Ex-Google-Fellow Bob Lee, how is responsible for the Google-Guice DI framework.

Now, using the tiny JSR 330 API is pretty simple. First you define an injection point in a class, which wants to use a concrete implementation of a common (business…) service:

// injection-point; no get/set needed...
@Inject private BusinessService service;

Now, you need to provide an implementation:

...
public class DefaultBusinessService implements BusinessService
{
...
}
...

If you have more versions of this service, you have to create a Qualifier annotation:

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.inject.Qualifier;

@Qualifier
@Target( { TYPE, METHOD, FIELD })
@Retention(RUNTIME)
public @interface FancyService
{
}

You use the Qualifier to inject a more meaningful implementation of the service:

@Inject @FancyService private BusinessService fancyService;

Now the question that comes up is what implementation of this JSR should I use ?

The ultimate suggestion would be, especially when running in the Java EE world, to use an implementation of the JSR 299. There are currently three options for that:

But what if I am not in a JavaEE container? When I am writing a tiny, small Java SE application ? The good news is here that Google Guice implements the JSR-330 as well. This is not a big surprise, since one of the guys behind the JSR-330 is Bob Lee, from Google-Guice. As a matter of fact, there is a wiki page, which acts a guide on using 330 and Guice.

Not only 299 implementations or Google Guice are supporting the unified API for Java Dependency Injection. The popular Spring framework, starting with its 3.0.x version, also has support for it!

The benefit of the wide support is that you only need to learn a simple API, which can be re-used in different environments. On Java EE containers the obligatory choice is a 299 implementation, such as Apache OpenWebBeans or JBoss Weld.But outside of the “webapplication world”, you can use the API and Guice or Spring as the implementation of the standard. Sure, most JSR-299 containers run in a vanilla JavaSE environment as well.

Summary: The API is simple and easy to use. You nail yourself to no specific platform by using/learning this API. Next blogs will be more specific to JSR-299 implementation to see what that spec adss on-top of it, such is a the producer methods., which offers a nice way to expose legacy (or vanilla JDK) classes as a injectable component.

Extensions for CDI

The JSRs 299/330 are pretty interesting as they offer a nice way to use its flexible structure to easily add new features. For instance inside of the Apache implementation (Apache OpenWebBeans) there is already some extension that adds decent support for the JSF2.0 @ViewScoped annotation. The commit shows that the implementation of this wasn’t that of a big deal.

The Apache MyFaces and Apache OWB communities put together a wiki page to discuss more extensions. The endresult of this effort will be (most-likely) a new subproject of the “Apache MyFaces Extension” project. Note: This project currently hosts ExtVal (Validation-Framework) and ExtScripting (support for dynamic languages, such as Groovy).

299/330 offers a nice tool to also create convenience annotations. One of them, the @Model, is already part of the CDI offerings. This annotation basically combines the @Named and @RequestScoped annotations. Something like that can be done for different scopes, such as @ApplicationScoped, @SessionScoped or @ViewScoped.

This is pretty trival:

package net.wessendorf.enterprise.inject;

import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import javax.enterprise.context.SessionScoped;
import javax.enterprise.inject.Stereotype;
import javax.inject.Named;

@Named
@SessionScoped
@Stereotype
@Target( { TYPE, METHOD, FIELD })
@Retention(RUNTIME)
@Documented
public @interface SessionModel
{
}

Put stuff like that into a tiny little JAR and reuse it on all your project; Simple and fast done!

On your beans this particular annotation goes along like this:

package net.wessendorf.facesgoodies;

import java.io.Serializable;

import net.wessendorf.enterprise.inject.SessionModel;

@SessionModel
public class SomeRandomBean implements Serializable
{
...
}

So get a change to checkout Apache OWB and give it a shot! Pretty good implementation, so far!

Apache MyFaces goes in strong direction to JSF 2.0

The Apache MyFaces project is very active on the JSF 2.0 front.

Recently the first alpha of the MyFaces 2.0 package has been released. Download the alpha here. Today, the Apache MyFaces Trinidad community also released the first alpha release of its JSF 2.0 efforts. Get the download here.

In the middle of January we expect to see the next alpha (or beta) of Apache MyFaces Core. The 2.0 package is pretty stable so far..

Enjoy!

ADF’s Active Data Service and scalar data (like activeOutputText)

I mentioned earlier that ADS is pretty much model driven and requires no extra sit-ups in the declarative view. It supports (currently) the following ADF components:

  • activeCommandToolbarButton
  • activeImage
  • activeOutputText
  • table
  • tree
  • All DVT components

Most examples that are viewable (or documented) provide an introduction on “How to combine ADS with collection-based data”. Let’s take a look on how to use activeOutputText with a Java Bean, as you may not have a model (or BAM).

Imagine a simple page that contains a ticker/counter. On the server-side a counter is updated every n seconds. We will use ADS to stream the data to the client. The part for the activeOutputText component is easy:

...
  <af:activeOutputText
    value="#{counterBean.state}"
    inlineStyle="
      color:brown;font-size:100px;font-weight:bold;text-align:center;
    "
  />
...

The Bean behind the page (counterBean) has a slightly tricky part, where we fake the actual model. In a @PostConstruct method we get access to the current ActiveModelContext and register a model key path for the “state” attribute:

ActiveModelContext context =
  ActiveModelContext.getActiveModelContext();
Object[] keyPath = new String[0];
context.addActiveModelInfo(this, keyPath, "state");

Afterwards we use Java’s ScheduledExecutorService class to schedule the data updates. The updates are done by the triggerDataUpdate() method:

public void triggerDataUpdate()
{
  counter.incrementAndGet();

  ActiveDataUpdateEvent event =
    ActiveDataEventUtil.buildActiveDataUpdateEvent(
      ActiveDataEntry.ChangeType.UPDATE,
      counter.get(),
      new String[0],
      null,
      new String[] { "state" },
      new Object[] { counter.get() });

  fireActiveDataUpdate(event);
}

At the beginning the “counter” is updated and the ActiveDataEventUtil is used to create the ActiveDataUpdateEvent. The complete code for the Bean (which implements a convenience implementation of the ActiveDataModel) is here:

package net.wessendorf.oracle.ads.simple;

import java.util.Collection;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.PostConstruct;

import oracle.adf.view.rich.activedata.ActiveModelContext;
import oracle.adf.view.rich.activedata.BaseActiveDataModel;
import oracle.adf.view.rich.event.ActiveDataEntry;
import oracle.adf.view.rich.event.ActiveDataUpdateEvent;

import oracle.adfinternal.view.faces.activedata.ActiveDataEventUtil;

public class CounterBean extends BaseActiveDataModel
{
  @PostConstruct
  public void setupActiveData()
  {
    ActiveModelContext context = ActiveModelContext.getActiveModelContext();
    Object[] keyPath = new String[0];
    context.addActiveModelInfo(this, keyPath, "state");

    // setup a timer that queues the events (in a loop)
    ScheduledExecutorService ses = Executors.newScheduledThreadPool(1);
    ses.scheduleAtFixedRate(
      new Runnable() {
        public void run() {
          triggerDataUpdate();
        }
      },
      5, // let's wait some seconds
      2, // period between the updates
      TimeUnit.SECONDS);
  }

  public void triggerDataUpdate()
  {
    counter.incrementAndGet();

    ActiveDataUpdateEvent event =
      ActiveDataEventUtil.buildActiveDataUpdateEvent(
        ActiveDataEntry.ChangeType.UPDATE,
        counter.get(),
        new String[0],
        null,
        new String[] { "state" },
        new Object[] { counter.get() });

    fireActiveDataUpdate(event);
  }

  public String getState()
  {
    return String.valueOf(counter);
  }

  protected void startActiveData(
     Collection<Object> rowKeys, int startChangeCount){}

  protected void stopActiveData(
     Collection<Object> rowKeys) {}

  public int getCurrentChangeCount()
  {
    return counter.get();
  }
  private final AtomicInteger counter = new AtomicInteger(0);
}

To enjoy get a copy of our latest (November 2009) release of JDeveloper and read the documentation.