Friday, August 30, 2013

JSF 2.x Tip of the Day: FacesMessage Severity Differences Between Mojarra and MyFaces

Introduction

We encountered an inconsistency between MyFaces and Mojarra that I was surprised was not addressed a long time ago. The issue has to do with the ordinal values assigned to the FacesMessage.Severity. Mojarra uses a zero(0) based level of Severity and MyFaces uses a one(1) based Severity level. As a result, we were trying to use a <rich:notifyMessages/> component with, as you can expect, some unexpected results.

One of the items I always preach is to code to the API. If you code to the API, then you can switch out the implementations should the need occur. This is a best practice, but can be undermined by little subtleties like this. Please don't get me wrong, both Mojarra and MyFaces are great implementations. It is these fine differences that should be consistent that we need to work on to make sure that we are consistent, and that the dream is real; switching implementations will not be painful.

RichFaces is a good framework, and folks like Brian Leathem take personal pride in making it a good implementation to run on top of either Mojarra, or MyFaces. I was really surprised by my discovery of an issue with <rich:notifyMessages/> since the <rich:messages/> works correctly. The problem is focused on the ordinal value I mentioned. I opened a JIRA issue with both MyFaces and RichFaces around the ordinal issue. Please see the references below for details.

However, I needed a solution not just report an issue. So I came up with a 10¢ solution based on some work I did at home last night, and a great suggestion by one of my team. I wanted to publish an article, a complaint, and a solution that others may need. These work arounds tend to become more common when doing cross-platform development, and sharing is paramount.

Problem

The RichFaces <rich:notifyMessages/> does not work consistently across JSF implementations based on Severity ordinal values.

Solution

Implement a method that checks the FacesMessage.Severity ordinal values, and change icons and CSS to correct the differences between implementations. We can accomplish this using CSS, and Expression Language (EL) combined with a page backing bean. In this case, I use a simple page backing bean, but it could be converted to a custom EL function.

The code for this example can be found here: myfaces-rf-example

default.css


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
*.rf-ntf-cnt *.rf-ntf-ico {
    /*
     * This accounts for MyFaces Severity Fatal ordinal is 4 and does not work with RichFaces.
    */
    display: block;
    background-image: url('#{indexBean.iconURL(4)}');
}
*.rf-ntf-sum *.rf-ntf-det {
    /*
     * This accounts for MyFaces Severity Fatal ordinal is 4 and does not work with RichFaces.
    */
    color: black !important;
}
*.rf-ntf-inf *.rf-ntf-ico {
    display: block;
    color: black !important;
    background-image: url('#{indexBean.iconURL(0)}');
}
*.rf-ntf-wrn *.rf-ntf-ico{
    display: block;
    color: black !important;
    background-image: url('#{indexBean.iconURL(1)}');
}
*.rf-ntf-wrn{
    color: black !important;
}
*.rf-ntf-err *.rf-ntf-ico {
    display: block;
    color: black !important;
    background-image: url('#{indexBean.iconURL(2)}');
}
*.rf-ntf-err{
    color: black !important;
}
*.rf-ntf-ftl *.rf-ntf-ico {
    display: block;
    color: black !important;
    background-image: url('#{indexBean.iconURL(3)}');
}
*.rf-ntf-ftl{
    color: black !important;
}

iconURL()


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/**
 * This method is used in the CSS file to alter the values of the icon URLs
 * based on whether the underlying {@link FacesMessage#SEVERITY_INFO} value
 * starts with 0 (Mojarra), or a 1 (MyFaces).
 *
 * @param level The {@link FacesMessage.Severity#getOrdinal()) to be evaluated.
 * @return a RichFaces resource URL for the appropriate notification.
 */
public String iconURL(int level) {
    if (FacesMessage.SEVERITY_INFO.getOrdinal() == 0) {
        ++level;
    }
    switch (level) {
        case 1: {
            //INFO
            return "/myfaces-rf-example/faces/javax.faces.resource/info.png?ln=org.richfaces";
        }
        case 2: {
            // WARN
            return "/myfaces-rf-example/faces/javax.faces.resource/warning.png?ln=org.richfaces";
        }
        case 3: {
            //ERROR
            return "/myfaces-rf-example/faces/javax.faces.resource/error.png?ln=org.richfaces";
        }
        case 4: {
            //FATAL
            return "/myfaces-rf-example/faces/javax.faces.resource/fatal.png?ln=org.richfaces";
        }
        default: {
            //INFO
            return "/myfaces-rf-example/faces/javax.faces.resource/info.png?ln=org.richfaces";
        }
    }
}
This simple solution allows us to check to see if the implementation starts at 0, or 1 and changes the icons and CSS.

References

Wednesday, August 28, 2013

JSF 2.x Tip of the Day: Guice ELResolver using SLF4J Logging

Introduction

I was recently tasked with looking at some mechanisms to control logging in our JSF applications. This included a number of proof of concept ideas to see which Dependency Injection (DI) mechanisms we could use. We are currently using CDI (Weld), and OpenWebbeans in our applications. I had previously used Guice for doing DI in some other applications especially in Java SE which I found it very easy to use.

As I looked around, I found that I could not find a good example of how to use Guice with JSF 2.x. There were a number of articles from over the years for using Guice with JSF 1.2 primarily, but nothing that used some of the great enhancements to JSF 2. I also found very little on how to implement FacesWrapper to wrap ApplicationFactory, Application, and ELResolver. The exception being ELResolver code that you can find in OmniFaces.

Implementation

The implementation uses a number of techniques to inject our custom ELResolver. First we will use a FacesWrapper to wrap the ApplicationFactory. Our implementation will return a custom ApplicationWrapper implementation, that will return a custom FacesWrapper for our ELResolver. This arrangement may seem complex, but separates the concerns to allow us to refactor them as necessary.

The code for this project can be found here: jsf-guice-logger-integration

GuiceServletContextListenerImpl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
package com.bluelotussoftware.guice;
 
import com.bluelotussoftware.guice.slf4j.SLF4JModule;
import com.google.inject.Guice;
import com.google.inject.Injector;
import com.google.inject.servlet.GuiceServletContextListener;
 
/**
 * An implementation of {@link GuiceServletContextListener} that injects
 * {@link SLF4JModule}.
 *
 * @author John Yeary <jyeary@bluelotussoftware.com>
 * @version 1.0
 */
public class GuiceServletContextListenerImpl extends GuiceServletContextListener {
 
    @Override
    protected Injector getInjector() {
        return Guice.createInjector(new SLF4JModule());
    }
 
}

FacesApplicationFactoryWrapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package com.bluelotussoftware.jsf.application;
 
import javax.faces.application.Application;
import javax.faces.application.ApplicationFactory;
 
/**
 * An implementation of {@link ApplicationFactory}.
 *
 * @author John Yeary
 * @version 1.0
 */
public class FacesApplicationFactoryWrapper extends ApplicationFactory {
 
    private ApplicationFactory factory;
 
    /**
     * Constructor that wraps an {@link ApplicationFactory} instance.
     *
     * @param factory The factory instance to be wrapped.
     */
    public FacesApplicationFactoryWrapper(final ApplicationFactory factory) {
        this.factory = factory;
    }
 
    /**
     * {@inheritDoc}
     * <p>
     * This method returns a {@link FacesApplicationWrapper} instance.</p>
*/
    @Override
    public Application getApplication() {
        Application application = factory.getApplication();
        return new FacesApplicationWrapper(application);
    }
 
    /**
     * {@inheritDoc}
     */
    @Override
    public void setApplication(final Application application) {
        factory.setApplication(application);
    }
 
}

FacesApplicationWrapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
package com.bluelotussoftware.jsf.application;
 
import com.bluelotussoftware.jsf.el.GuiceELResolverWrapper;
import javax.el.ELResolver;
import javax.faces.application.Application;
import javax.faces.application.ApplicationWrapper;
 
/**
 * An implementation of {@link ApplicationWrapper}.
 *
 * @author John Yeary
 * @version 1.0
 */
public class FacesApplicationWrapper extends ApplicationWrapper {
 
    private Application wrapped;
 
    /**
     * Constructor that wraps an {@link Application} instance.
     *
     * @param wrapped The {@link Appplication} to be wrapped.
     */
    public FacesApplicationWrapper(final Application wrapped) {
        this.wrapped = wrapped;
    }
 
    /**
     * {@inheritDoc}
     */
    @Override
    public Application getWrapped() {
        return wrapped;
    }
 
    /**
     * {@inheritDoc}
     * <p>
     * This method returns a {@link GuiceELResolverWrapper} that wraps the
     * default {@link ELResolver}.
     */
    @Override
    public ELResolver getELResolver() {
        return new GuiceELResolverWrapper(getWrapped().getELResolver());
    }
}

GuiceELResolverWrapper.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package com.bluelotussoftware.jsf.el;
 
import com.google.inject.Injector;
import java.beans.FeatureDescriptor;
import java.util.Iterator;
import java.util.Map;
import javax.el.ELContext;
import javax.el.ELResolver;
import javax.faces.FacesWrapper;
import javax.faces.context.FacesContext;
 
/**
 * A {@link FacesWrapper} implementation that wraps an {@link ELResolver} and
 * provides a mechanism to inject Guice {@link Injector} implementations.
 *
 * @author John Yeary
 * @version 1.0
 */
public class GuiceELResolverWrapper extends ELResolver implements FacesWrapper<elresolver> {
 
    private ELResolver wrapped;
 
    /**
     * Default constructor.
     */
    public GuiceELResolverWrapper() {
    }
 
    /**
     * Constructor that wraps an {@link ELResolver}.
     *
     * @param wrapped The resolver to wrap;
     */
    public GuiceELResolverWrapper(final ELResolver wrapped) {
        this.wrapped = wrapped;
    }
 
    /**
     * {@inheritDoc}
     */
    @Override
    public ELResolver getWrapped() {
        return wrapped;
    }
 
    /**
     * {@inheritDoc}
     * <p>
     * <strong>Note:</strong> This implementation checks to see if the property
     * can be resolved using the wrapped instance. If the property is resolved,
     * this method will inject the Guice {@link Injector} implementations.
     */
    @Override
    public Object getValue(final ELContext context, final Object base, final Object property) {
 
        Object obj = getWrapped().getValue(context, base, property);
 
        if (null != obj) {
            FacesContext fctx = (FacesContext) context.getContext(FacesContext.class);
 
            if (null != fctx) {
 
                Map map = fctx.getExternalContext().getApplicationMap();
                Injector injector = (Injector) map.get(Injector.class.getName());
                if (injector == null) {
                    throw new NullPointerException("Could not locate "
                            + "Guice Injector in application scope using"
                            + " key '" + Injector.class.getName() + "'");
                }
                injector.injectMembers(obj);
            }
        }
 
        return obj;
    }
 
    /**
     * {@inheritDoc}
     * <p>
     * <strong>Note:</strong> This returns the wrapped implementation.</p>
*/
    @Override
    public Class<?> getType(final ELContext context, final Object base, final Object property) {
        return getWrapped().getType(context, base, property);
    }
 
    /**
     * {@inheritDoc}
     * <p>
     * <strong>Note:</strong> This returns the wrapped implementation.</p>
*/
    @Override
    public void setValue(final ELContext context, final Object base, final Object property, final Object value) {
        getWrapped().setValue(context, base, property, value);
    }
 
    /**
     * {@inheritDoc}
     * <p>
     * <strong>Note:</strong> This returns the wrapped implementation.</p>
*/
    @Override
    public boolean isReadOnly(final ELContext context, final Object base, final Object property) {
        return getWrapped().isReadOnly(context, base, property);
    }
 
    /**
     * {@inheritDoc}
     * <p>
     * <strong>Note:</strong> This returns the wrapped implementation.</p>
*/
    @Override
    public Iterator<featuredescriptor> getFeatureDescriptors(final ELContext context, final Object base) {
        return getWrapped().getFeatureDescriptors(context, base);
    }
 
    /**
     * {@inheritDoc}
     * <p>
     * <strong>Note:</strong> This returns the wrapped implementation.</p>
*/
    @Override
    public Class<?> getCommonPropertyType(final ELContext context, final Object base) {
        return getWrapped().getCommonPropertyType(context, base);
    }
 
}

faces-config.xml

1
2
3
4
5
6
7
8
9
<?xml version='1.0' encoding='UTF-8'?>
<faces-config version="2.0"
              xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    <factory>
        <application-factory>com.bluelotussoftware.jsf.application.FacesApplicationFactoryWrapper</application-factory>
    </factory>
</faces-config>
There are additional classes that do the logging that can be found in the project. The primary interest here is how to get an ELResolver implementation that will resolve our Guice injections. I hope this demonstration of JSF 2.x wrappers can show you how easy it is to implement custom wrappers including a custom ELResolver.

References

Tuesday, August 06, 2013

JSF 2.x Tip of the Day: jsf.js AJAX onEvent() and onError() Examples

I was looking for some information on what I could do with the jsf.js AJAX scripts in JSF. Specifically, I was wondering if I could do some event handling, and how it should be accomplished. I was surprised that there really was not a complete example that I could find. I did find some blog posts from Jim Driscoll and some comments on stackoverflow by +Bauke Scholtz which show a partial solution, but nothing complete.

I decided to combine the good parts of Jim's blog post with some of the goodies from +Bauke Scholtz to create a complete example. In this example, I use a solution from Jim to demonstrate the events that are returned from the onEvent() and onError() listeners.  Along with a common request... A spinner for AJAX requests.

Once you download, and run the code. You will see a spinner while the AJAX request is processing. In my case, I use a Thread.sleep(2000); to cause the spinner to display for a little while.

The code for project can be found here: jsf-ajax-demo

index.xhtml


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>jsf.js AJAX Example</title>
        <h:outputScript library="javax.faces" name="jsf.js"/>
        <h:outputStylesheet library="css" name="default.css"/>
        <script type="text/javascript">
            var statusUpdate = function statusUpdate(data) {
                var statusArea = document.getElementById("statusArea");
                var text = statusArea.value;
                text = text + "Name: " + data.source.id;
                if (data.type === "event") {
                    text = text + " Event: " + data.type + "\n";
                    text = text + " Status: " + data.status + "\n";
                    if (data.status !== 'begin') {
                        text = text + " Response Code: " + data.responseCode + "\n";
                    }
                } else {  // otherwise, it's an error
                    text = text + " Error: " + data.name + "\n";
                }
                statusArea.value = text;
            };
 
            function handleAjax(data) {
                var status = data.status;
 
                switch (status) {
                    case "begin":
                        // This is the start of the AJAX request.
                        document.getElementById("statusArea").value = '';
                        document.getElementsByTagName('body')[0].className = 'loading';
                        break;
 
                    case "complete":
                        // This is invoked right after ajax response is returned.
                        break;
 
                    case "success":
                        // This is invoked right after successful processing of ajax response and update of HTML DOM.
                        document.getElementsByTagName('body')[0].className = '';
                        break;
                }
            }
 
            // Setup the statusUpdate function to hear all events on the page
            jsf.ajax.addOnEvent(handleAjax);
            jsf.ajax.addOnEvent(statusUpdate);
            jsf.ajax.addOnError(statusUpdate);
        </script>
    </h:head>
    <h:body>
        <h:inputTextarea id="statusArea" cols="40" rows="10" readonly="true" disabled="true" style="resize: none;"/>
        <h:form id="form1">
            <h:panelGrid id="panelGrid1" columns="2">
                <h:outputText id="uuid" value="#{indexBean.uuid}" style="font-size: 18px; font-weight: bold; color: salmon;"/>
                <h:message for="uuid"/>
                <h:panelGroup id="panelGroup1">
                    <h:commandButton id="submitButton" value="Generate UUID" actionListener="#{indexBean.generateUUID()}">
                        <f:ajax execute="@form" render="panelGrid1"/>
                    </h:commandButton>
                </h:panelGroup>
            </h:panelGrid>
            <div class="modal">
<!-- Place at bottom of page --></div>
</h:form>
    </h:body>
</html>

IndexBean.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
package com.bluelotussoftware.example.jsf.ajax;
 
import java.util.UUID;
import javax.enterprise.context.RequestScoped;
import javax.faces.event.ActionListener;
import javax.inject.Named;
 
/**
 * Page backing bean for
 * <code>index.xhtml</code>.
 *
 * @author John Yeary
 * @version 1.0
 */
@Named
@RequestScoped
public class IndexBean {
 
    private String uuid;
 
    /**
     * {@link ActionListener} implementation that generates a random UUID and
     * sets the value in the bean. The returned value can be found by calling
     * {@link #getUuid()}.
     */
    public void generateUUID() {
        try {
            // Add this so that we have a delay for the AJAX spinner.
            Thread.sleep(2000);
            uuid = UUID.randomUUID().toString();
        } catch (InterruptedException ignore) {
        }
    }
 
    /**
     * Getter for UUID.
     *
     * @return return {@link UUID#toString()}.
     */
    public String getUuid() {
        return uuid;
    }
}

References

This is based on the primarily on the work published by Jim Driscoll and Bauke Scholz. This is just a more complete example  of what they mentioned in their articles.

Saturday, August 03, 2013

JSF/CDI Tip of the Day: @PostConstruct Lifecycle Interceptor

SR-71
I was trying to come up with a way to inject a logger into a JSF managed bean that can be done prior to @Postconstruct. I was unsuccessful with this technique, but it was not a total loss. The examples I found on interceptors for life-cycle interception were "empty". They generally mention you can do it, but they did not show any real useful examples.

I hope to change that with this example. The example I demonstrate could be easily done with constructor injection, but in the case of a no-args constructor this may be your only opportunity to inject objects during @PostConstruct. I am going to suggest that if you want to make this functionality more general, you should use an interface and call the interface methods.

The InvocationContext will return Class<? extends T> using context.getTarget(). We can use this concept to control our injection to the object. In my case, I use setter injection on the object. Pretty cool!

The code for this example can be downloaded from here: cdi-lifecycle-interceptor-example

There are a couple of classes needed to set up our @Interceptor. The first is an interface we will call Loggable and the second is an @InterceptorBinding.

Loggable.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.bluelotussoftware.example.cdi;
 
import java.util.logging.Logger;
 
/**
 * This allows for setting a {@link Logger} in an implementing class.
 *
 * @author John Yeary
 * @version 1.0
 */
public interface Loggable {
 
    /**
     * Sets the logger for a class.
     *
     * @param logger the logger to be set.
     */
    void setLogger(Logger logger);
}
This is a simple interface which we will apply to the interceptor, and to the target class that we want to intercept.

Interceptable.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package com.bluelotussoftware.example.cdi;
 
import static java.lang.annotation.ElementType.TYPE;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Target;
import javax.interceptor.InterceptorBinding;
 
/**
 * An interceptor binding.
 *
 * @author John Yeary
 * @version 1.0
 */
@Inherited
@InterceptorBinding
@Retention(RUNTIME)
@Target({TYPE})
public @interface Interceptable {
}
The next class we need is our @Interceptor. This code contains all of the magic we need for the target class which we are intercepting.

PostConstructInterceptor.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package com.bluelotussoftware.example.cdi;
 
import java.util.Map;
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.interceptor.Interceptor;
import javax.interceptor.InvocationContext;
 
/**
 *
 * @author John Yeary
 * @version 1.0
 */
@Interceptable
@Interceptor
public class PostConstructInterceptor {
 
    private static final Logger log = Logger.getLogger(PostConstructInterceptor.class.getName());
 
    /**
     * This is the method that handles the {@link @PostConstruct} event. The
     * method name can be called any legal Java method name. I chose
     * <code>intercept</code> since it is an action describing what we are
     * doing.
     *
     * @param context The current invocation context.
     * @throws Exception If any {@link Exception} occurs during processing.
     */
    @PostConstruct
    public void intercept(InvocationContext context) throws Exception {
 
        log.setLevel(Level.FINE);
        log.info("Before call to @PostConstuct.");
 
        Map<String, Object> map = context.getContextData();
        for (String key : map.keySet()) {
            log.log(Level.INFO, "Context data key --> {0} data --> {1}", new Object[]{key, map.get(key)});
        }
 
        log.log(Level.INFO, "Examining object: {0}", context.getTarget().getClass().getName());
 
        // Best practice is to check if the object is an instanceof an interface.
        if (context.getTarget() instanceof Loggable) {
            Loggable loggable = (Loggable) context.getTarget();
            loggable.setLogger(Logger.getLogger(context.getTarget().getClass().getName()));
        }
 
        /*
         * This checks for an instanceof a specific bean. This is not the preferred approach
         * unless you are really expecting to only check for a specific class.
         */
        if (context.getTarget() instanceof IndexBean) {
            IndexBean indexBean = (IndexBean) context.getTarget();
            indexBean.setFactory(new UUIDFactory() {
 
                @Override
                public UUID generateUUID() {
                    return UUID.randomUUID();
                }
            });
        }
 
        context.proceed();
        log.info("After call to  to @PostConstuct.");
    }
}
As you can see we are making changes to the class after it is constructed, and before the @PostConstruct method is executed, i.e., context.proceed().

Finally, we need to have our class that we are intercepting. In this case, it is a simple @Named and @RequestScoped CDI bean.

IndexBean.java


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
package com.bluelotussoftware.example.cdi;
 
import java.util.UUID;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.enterprise.context.RequestScoped;
import javax.inject.Named;
 
/**
 * A page backing bean for the
 * <code>index.xhtml</code> page.
 *
 * @author John Yeary <jyeary@bluelotussoftware.com>
 * @version 1.0
 */
@Named
@RequestScoped
@Interceptable
public class IndexBean implements Loggable {
 
    private UUIDFactory factory;
    private Logger log;
 
    /**
     * Default no-argument constructor.
     */
    public IndexBean() {
    }
 
    @PostConstruct
    private void initialize() {
        // This should cause an NPE since logger is not initialized, but we will do our magic here.
        log.info("I am an injected logger");
    }
 
    /**
     * {@inheritDoc}
     */
    @Override
    public void setLogger(final Logger logger) {
        this.log = logger;
    }
 
    /**
     * This sets the UUID factory for the bean.
     *
     * @param factory the factory to be set.
     */
    public void setFactory(final UUIDFactory factory) {
        log.log(Level.INFO, "Factory being set to {0}", factory);
        this.factory = factory;
    }
 
    /**
     * This returns a randomly generated {@link UUID#randomUUID()#toString()}
     *
     * @return a randomly generated UUID value, or {@code null} if the factory
     * is not initialized.
     */
    public String getUUID() {
        if (null != factory) {
            return factory.generateUUID().toString();
        } else {
            return null;
        }
    }
}
The magic is complete, but I would recommend downloading the Maven based project to see the whole example here: cdi-lifecycle-interceptor-example

Our final output is shown here.

UUID Please?

Friday, August 02, 2013

JSF Tip of the Day: How do I reset input fields after a validation failure?

I was asked earlier today how to reset fields in a JSF application, if the validation fails. In his case, he had a Richfaces table which had values that were selectable. Once the value was selected, a pop-up box would appear in which you could change values. If the user input an incorrect value, the validation would fail and the box would remain. However, if he closed the box, or hit cancel... well it would retain the error values. If he selected another row from the table, it would contain the previous values.

This is a common issue, but he could not find a quick solution so I wrote one.

This function fetches the parent component which in his case was a form containing <h:inputText/> components, and then clears them. You may need to add some more code to do it recursively if the components are nested.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public String clear(final String parentComponentId) {
        UIViewRoot view = FacesContext.getCurrentInstance().getViewRoot();
        UIComponent fc = view.findComponent(parentComponentId);
        if (null != fc) {
            List<uicomponent> components = fc.getChildren();
            for (UIComponent component : components) {
                if (component instanceof UIInput) {
                    UIInput input = (UIInput) component;
                    // JSF 1.1+
//                input.setSubmittedValue(null);
//                input.setValue(null);
//                input.setLocalValueSet(false);
//                input.setValid(true);
                    // JSF 1.2+
                    input.resetValue();
                }
            }
        }
        return null;
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:f="http://java.sun.com/jsf/core">
    <h:head>
        <title>Reset and Clear Example</title>
    </h:head>
    <h:body>
        <h:form id="form1">
            <h:panelGrid id="panelGrid1" columns="2">
                <h:inputText id="name" value="#{indexBean.name}"/>
                <h:message for="name"/>
                <h:panelGroup>
                    <h:commandButton value="Submit"/>
                    <h:commandButton type="reset"
                                     action="#{indexBean.clear('form1')}" value="Clear and Reset">
                        <f:ajax execute="@this" render="panelGrid1"/>
                    </h:commandButton>
                </h:panelGroup>
            </h:panelGrid>
        </h:form>
    </h:body>
</html>

Popular Posts