Tuesday Nov 25, 2014

Locating JSF components by ID

An occasional problem for developers using JSF is how to locate a component given just it's ID. Now if you have the complete ID, which includes the computed location, for example: Button B1 inside Region R1 inside page with template PT1 ==> PT1:R1:B1, you can hardcode that using the basic findComponent() API, or even better use the invokeOnComponent() API provided by the UIComponentBase (see the JavaDoc for more information).  However, what it you have no idea, at the time of writing the code, what the context is that the component that you want will be used in?  In that case, the only information that you might have is the basic ID of the component and you know nothing of the naming containers that contribute to the full unique ID.

 In this scenario I've seen a lot of examples where developers fall back to recursion. i.e. They grab the viewRoot from the FacesContext, get it's children, check to see if any of those children has the correct ID, if not they then get the children of each of those and check those and so on. There is, however, a much neater, and more efficient way of doing this using the JSF 2.0 visitTree API. With the visitTree API, in a similar way to the invokeOnComponent() API, you provide a callback inner class which implements a visit() method. This method is processed for each component in the component tree. You then have the ability to control how the tree is traversed based on the return value that you provide from that visit method. The valid return values are:

  • VisitResult.COMPLETE - stop the traversal all together
  • VisitResult.ACCEPT - continue with the traversal
  • VisitResult.REJECT - stop traversal for the current subtree, but continue with the rest

So here's a simple example of a helper method to invoke a ActionEvent on a commandItem such as <af:button> given just the basic id of that button. This might be the kind of thing you would want to do in a serverListener callback being invoked from a client side customEvent.

private static boolean queueActionOnCommandComponmentById(String commandId) {
  if (commandId != null && commandId.length() > 0) {
    final String candidateId = commandId;
    FacesContext ctx = FacesContext.getCurrentInstance();
    VisitContext visitContext = VisitContext.createVisitContext(ctx);
    return UIXComponent.visitTree(visitContext, ctx.getViewRoot(), new VisitCallback(){
      public VisitResult visit(VisitContext context, UIComponent component) {
        try {
          if (component instanceof UIXCommand && component.getId().equals(candidateId)) {
            ActionEvent cmdEvent = new ActionEvent(component);
            return VisitResult.COMPLETE;
          return VisitResult.ACCEPT;
        } catch (Exception e) {
          return VisitResult.COMPLETE;
        _logger.warning("Empty or null command component ID provided, no event queued");
        return false;

Of course this is a trivial example, and suffers like any of these techniques, from the risk that you might conceivably have more than one component with the same basic ID, so in this case I'd be sure that the ID assigned to the command button as already pretty unique. However, more complex uses of this traversal approach may be touching multiple components and that's where it really comes into it's own.

Anyway, I hope you get the message, never use the getChildren() recursion technique, use visitTree() instead. 

Thursday Dec 05, 2013

Current Date / Time on your JSF pages

OK, it's a trivial problem but I'll answer to anyway. Is there a simple way to get the date and time in expression language inside your pages, without writing Java code?

The answer is of course yes, it's simple to do in a declarative manner.  You will need to create a basic managed bean definition in your JSF configuration.  So for example I might add the following definition for a bean called "now" to my adfc-config.xml file:


That's enough to ensure that a Date object called "now" is available on the request map and is re-created (i.e. refreshed) on every roundtrip.  This can then be referenced inside of your page:

  <af:outputText value="#{now}">
    <af:convertDateTime type="both" timeZone="CET"/>

Notice how I've specified the timezone I want to see here as the result of the new Date() creation will be the date in UTC / GMT.

There you are, short and sweet. 

Thursday Apr 05, 2012

Application Scope v's Static - Not Quite the same

An interesting question came up today which, innocent as it sounded, needed a second or two to consider. What's the difference between storing say a Map of reference information as a Static as opposed to storing the same map as an application scoped variable in JSF? 

From the perspective of the web application itself there seems to be no functional difference, in both cases, the information is confined to the current JVM and potentially visible to your app code (note that Application Scope is not magically propagated across a cluster, you would need a separate instance on each VM).

To my mind the primary consideration here is a matter of leakage. A static will be (potentially) visible to everything running within the same VM (OK this depends on which class-loader was used but let's keep this simple), and this includes your model code and indeed other web applications running in the same container. An Application Scoped object, in JSF terms, is much more ring-fenced and is only visible to the Web app itself, not other web apps running on the same server and not directly to the business model layer if that is running in the same VM.

So given that I'm a big fan of coding applications to say what I mean, then using Application Scope appeals because it explicitly states how I expect the data to be used and a provides a more explicit statement about visibility and indeed dependency as I'd generally explicitly inject it where it is needed. 

Alternative viewpoints / thoughts are, as ever, welcomed...

Saturday May 08, 2010

Script For Detecting Availability of XMLHttp in Internet Explorer

Having the XMLHttpRequest API available is key to any ADF Faces Rich Client application. Unfortunately, it is possible for users to switch off this option in Internet Explorer as a Security setting. Without XMLHttpRequest available, your ADF Faces application will simply not work correctly, but rather than giving the user a bad user experience wouldn't it be nicer to tell them that they need to make some changes in order to use the application? 
Thanks to Blake Sullivan in the ADF Faces team we now have a little script that can do just this.
The script is available from the sample code page here, just look for the browserCheck.js sample - This is what you'll need to add to your project.
The best way to use this script is to make changes to whatever template you are using for the entry points to your application. If you're not currently using template then you'll have to make the same change in each of your JSPX pages.
  1. Save the browserCheck.js file into a /js/ directory under your HTML root within your UI project (e.g. ViewController)
  2. In the template or page, select the <af:document> object in the Structure window.
  3. From the right mouse (context) menu choose Facet and select the metaContainer facet.
  4. Switch to the source code view and locate the metaContainer facet. Then insert the following lines (I've included the facet tag for clarity but you'll already have that):
      <f:facet name="metaContainer">
        <af:resource type="javascript"
        <af:resource type="javascript">

Note that the argument to the xmlhttpNativeCheck function is a page that you want to show to the user if they need to change their browser configuration. So build this page in the appropriate place as well. You can also just call the function without any arguments e.g. xmlhttpNativeCheck(); in which case it will pop up default instructions for the user to follow, but not redirect to any other page.

Hawaii, Yes! Duncan has been around Oracle technology way too long but occasionally has interesting things to say. He works in the Development Tools Division at Oracle, but you guessed that right? In his spare time he contributes to the Hudson CI Server Project at Eclipse
Follow DuncanMills on Twitter

Note that comments on this blog are moderated so (1) There may be a delay before it gets published (2) I reserve the right to ignore silly questions and comment spam is not tolerated - it gets deleted so don't even bother, we all have better things to do with our lives.
However, don't be put off, I want to hear what you have to say!


« October 2015