org.picocontainer.web.jsf.PicoVariableResolver Maven / Gradle / Ivy
/*******************************************************************************
* Copyright (C) PicoContainer Organization. All rights reserved.
* ---------------------------------------------------------------------------
* The software in this package is published under the terms of the BSD style
* license a copy of which has been included with this distribution in the
* LICENSE.txt file.
******************************************************************************/
package org.picocontainer.web.jsf;
import java.util.Map;
import javax.faces.context.FacesContext;
import javax.faces.el.EvaluationException;
import javax.faces.el.VariableResolver;
import org.picocontainer.PicoContainer;
import org.picocontainer.MutablePicoContainer;
import org.picocontainer.web.PicoServletContainerFilter;
/**
* This is a variable resolver implementation for Java ServerFaces.
* Installation
*
* Add install this variable resolver by adding setting the application's
* variable resolver to
* org.picocontainer.web.jsf.NanoWarDelegatingVariableResolver. An
* example follows:
*
*
*
*
* <faces-config>
* <application>
* <strong>
* <variable-resolver>
* org.picocontainer.web.jsf.NanoWarDelegatingVariableResolver
* </variable-resolver>
* </strong>
* </application>
* ....
* </faces-config>
*
*
*
* Usage
* Part 1 - Write your Constructor Dependency Injection (CDI) - based
* backing bean:
*
* Even though you are writing a backing bean, you can utilize PicoContainers
* CDI capabilities to the fullest. Example:
*
*
*
* //Imports and variables...
*
* public ListCheeseController(<strong>CheeseService service</strong>) {
* this.service = service;
* }
*
* //The rest of the class.
*
*
* Part 2 - Set up your NanoWAR services.
*
* (This assumes you have installed NanoWAR properly. Please see the NanoWAR
* documentation for specific instructions)
*
*
* You need to name your services with the name you will be giving your
* Backing Bean. Example:
*
*
* pico = builder.container(parent: parent) {
* if(assemblyScope instanceof javax.servlet.ServletContext) {
* // Application Services would go here.
* } else if (assemblyScope instanceof javax.servlet.ServletRequest) {
* <strong>addComponent(key: 'cheeseBean', class: 'org.picocontainer.web.samples.jsf.ListCheeseController')</strong>
* }
* }
*
*
* Part 3 - Set up your managed beans for JSF
*
* Set the managed bean names in your faces-config to equal the names
* given to the backing beans in the nanowar composition script. Example:
*
*
*
* <managed-bean>
* <description>CDI Injected Bean</description>
* <strong><managed-bean-name>cheeseBean</managed-bean-name></strong>
* <managed-bean-class>
* org.picocontainer.web.samples.jsf.CheeseController
* </managed-bean-class>
* <managed-bean-scope>request</managed-bean-scope>
* </managed-bean>
*
*
*
* Notice how the same names were used in the faces-config as in the
* nanowar configuration. When the JSF page asks for the bean named
* 'addCheeseBean', the Nano variable resolver will take that name and check
* nanocontainer for an object of that instance. If it finds one, it will send
* it back to the page.
*
* Note:
*
* This class currently has only been tested using MyFaces. There are reports
* that this technique doesn't work on all reference implementation versions. We
* welcome success or failure feedback!
*
*
* @author Michael Rimov
*/
public class PicoVariableResolver extends VariableResolver {
public static class ServletFilter extends PicoServletContainerFilter {
private static ThreadLocal currentRequestContainer = new ThreadLocal();
private static ThreadLocal currentSessionContainer = new ThreadLocal();
private static ThreadLocal currentAppContainer = new ThreadLocal();
protected void setAppContainer(MutablePicoContainer container) {
currentAppContainer.set(container);
}
protected void setRequestContainer(MutablePicoContainer container) {
currentRequestContainer.set(container);
}
protected void setSessionContainer(MutablePicoContainer container) {
currentSessionContainer.set(container);
}
protected static MutablePicoContainer getRequestContainerForThread() {
return currentRequestContainer.get();
}
protected static MutablePicoContainer getSessionContainerForThread() {
return currentSessionContainer.get();
}
protected static MutablePicoContainer getApplicationContainerForThread() {
return currentAppContainer.get();
}
}
/**
* The nested variable resolver.
*/
private VariableResolver nested;
/**
* Decorated Variable resolver.
*
* @param decorated
*/
public PicoVariableResolver(VariableResolver decorated) {
super();
if (decorated == null) {
throw new NullPointerException("decorated");
}
nested = decorated;
}
/**
* Retrieve the delegated value.
*
* @return the wrapped variable resolver.
*/
protected VariableResolver getNested() {
return nested;
}
/**
* {@inheritDoc}
*
* @param facesContext
* @param name
* @return the resulting object, either resolved through NanoWAR, or passed
* onto the delegate resolver.
* @throws EvaluationException
* @see javax.faces.el.VariableResolver#resolveVariable(javax.faces.context.FacesContext,
* java.lang.String)
*/
public Object resolveVariable(FacesContext facesContext, String name) {
PicoContainer nano = getPicoContainer(facesContext);
Object result = nano.getComponent(name);
if (result == null) {
return nested.resolveVariable(facesContext, name);
}
return result;
}
/**
* Tries to locate the nanocontainer first at request level, and then if it
* doesn't find it there. (Filter might not be installed), it tries
* Application level. If that fails it throws an exception since you
* wouldn't expect the NanoWarDelegatingVariableResolver
*
* @param facesContext
* @return NanoContainer instance.
* @throws EvaluationException if it cannot find a NanoWAR instance.
*/
protected PicoContainer getPicoContainer(FacesContext facesContext) {
Map requestAttributeMap = facesContext.getExternalContext().getRequestMap();
PicoContainer container = null;
// First check request map.
if (requestAttributeMap != null) {
container = ServletFilter.getRequestContainerForThread();
}
if (requestAttributeMap == null || container == null) {
// If that fails, check session for container.
Map sessionMap = facesContext.getExternalContext().getSessionMap();
if (sessionMap != null) {
// If there is a session.
container = ServletFilter.getSessionContainerForThread();
}
if (sessionMap == null || container == null) {
// If that fails, check for App level container.
container = ServletFilter.getApplicationContainerForThread();
if (container == null) {
// If that fails... Fail.
throw new EvaluationException(
"The NanoWar delegating variable resolver is installed, however no NanoWar "
+ "container was found in the request or application scope.");
}
}
}
return container;
}
}