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

0 comments :

Popular Posts