1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package net.sourceforge.sannotations.jsf.utils;
22
23 import javax.faces.context.FacesContext;
24 import javax.faces.el.EvaluationException;
25 import javax.faces.el.MethodBinding;
26 import javax.faces.el.VariableResolver;
27
28 import net.sourceforge.sannotations.scopes.ConversationScope;
29 import net.sourceforge.sannotations.scopes.FlashScope;
30
31 import org.apache.commons.logging.Log;
32 import org.apache.commons.logging.LogFactory;
33 import org.springframework.beans.factory.BeanFactory;
34 import org.springframework.util.Assert;
35 import org.springframework.web.context.WebApplicationContext;
36 import org.springframework.web.jsf.FacesContextUtils;
37 import org.springframework.web.jsf.WebApplicationContextVariableResolver;
38
39 /***
40 * JSF VariableResolver that first delegates to the original resolver of the underlying JSF implementation, then to the Spring root WebApplicationContext.
41 * <p>
42 * Configure this resolver in your <code>faces-config.xml</code> file as follows:
43 *
44 * <pre>
45 * <application>
46 * ...
47 * <variable-resolver>org.springframework.web.jsf.DelegatingVariableResolver</variable-resolver>
48 * </application>
49 * </pre>
50 *
51 * All your JSF expressions can then implicitly refer to the names of Spring-managed service layer beans, for example in property values of JSF-managed beans:
52 *
53 * <pre>
54 * <managed-bean>
55 * <managed-bean-name>myJsfManagedBean</managed-bean-name>
56 * <managed-bean-class>example.MyJsfManagedBean</managed-bean-class>
57 * <managed-bean-scope>session</managed-bean-scope>
58 * <managed-property>
59 * <property-name>mySpringManagedBusinessObject</property-name>
60 * <value>#{mySpringManagedBusinessObject}</value>
61 * </managed-property>
62 * </managed-bean>
63 * </pre>
64 *
65 * with "mySpringManagedBusinessObject" defined as Spring bean in applicationContext.xml:
66 *
67 * <pre>
68 * <bean id="mySpringManagedBusinessObject" class="example.MySpringManagedBusinessObject">
69 * ...
70 * </bean>
71 * </pre>
72 *
73 * @author Juergen Hoeller
74 * @author Rodrigo Urubatan
75 * @since 1.1
76 * @see WebApplicationContextVariableResolver
77 * @see FacesContextUtils#getRequiredWebApplicationContext
78 */
79 public class DelegatingVariableResolver extends VariableResolver {
80 /*** Logger available to subclasses */
81 protected final Log logger = LogFactory.getLog(this.getClass());
82 protected final VariableResolver originalVariableResolver;
83 private DataModelFactoryRegistry dataModelfactoryRegistry;
84
85 /***
86 * Create a new DelegatingVariableResolver, using the given original VariableResolver.
87 * <p>
88 * A JSF implementation will automatically pass its original resolver into the constructor of a configured resolver, provided that there is a corresponding constructor
89 * argument.
90 *
91 * @param originalVariableResolver
92 * the original VariableResolver
93 */
94 public DelegatingVariableResolver(final VariableResolver originalVariableResolver) {
95 Assert.notNull(originalVariableResolver, "Original JSF VariableResolver must not be null");
96 this.originalVariableResolver = originalVariableResolver;
97 }
98
99 /***
100 * Return the original JSF VariableResolver that this resolver delegates to. Used to resolve standard JSF-managed beans.
101 */
102 protected final VariableResolver getOriginalVariableResolver() {
103 return this.originalVariableResolver;
104 }
105
106 /***
107 * Delegate to the original VariableResolver first, then try to resolve the variable as Spring bean in the root WebApplicationContext.
108 */
109 @Override
110 public Object resolveVariable(final FacesContext facesContext, final String name) throws EvaluationException {
111 Object result = null;
112 final BeanFactory bf = this.getBeanFactory(facesContext);
113 result = this.resolve(facesContext, name, bf);
114 if (result == null) {
115 if (this.dataModelfactoryRegistry == null) {
116 this.dataModelfactoryRegistry = (DataModelFactoryRegistry) bf.getBean("dataModelfactoryRegistry");
117 }
118 if (this.dataModelfactoryRegistry.hasFactory(name)) {
119 if (this.logger.isDebugEnabled()) {
120 this.logger.debug("Attempting to call factory method for '" + name + "'");
121 }
122 final String fstring = this.dataModelfactoryRegistry.getFactory(name);
123 final MethodBinding factory = facesContext.getApplication().createMethodBinding(fstring, null);
124 factory.invoke(facesContext, null);
125 result = this.resolve(facesContext, name, bf);
126 }
127 }
128 return result;
129 }
130
131 private Object resolve(final FacesContext facesContext, final String name, BeanFactory bf) {
132
133 if (this.logger.isDebugEnabled()) {
134 this.logger.debug("Attempting to resolve variable '" + name + "' in root WebApplicationContext");
135 }
136 if (bf.containsBean(name)) {
137 if (this.logger.isDebugEnabled()) {
138 this.logger.debug("Successfully resolved variable '" + name + "' in root WebApplicationContext");
139 }
140 return bf.getBean(name);
141 }
142
143
144
145
146 final ConversationScope conversationScope = (ConversationScope) bf.getBean("conversationScopeBean");
147 Object object = conversationScope.get(name, null);
148 if (object != null) {
149 if (this.logger.isDebugEnabled()) {
150 this.logger.debug("Successfully resolved variable '" + name + "' in root Conversation Scope");
151 }
152 return object;
153 }
154 final FlashScope flashScope = (FlashScope) bf.getBean("flashScopeBean");
155 object = flashScope.get(name, null);
156 if (object != null) {
157 if (this.logger.isDebugEnabled()) {
158 this.logger.debug("Successfully resolved variable '" + name + "' in root Flash Scope");
159 }
160 return object;
161 }
162
163 if (this.logger.isDebugEnabled()) {
164 this.logger.debug("Attempting to resolve variable '" + name + "' in via original VariableResolver");
165 }
166 final Object originalResult = this.getOriginalVariableResolver().resolveVariable(facesContext, name);
167 if (originalResult != null) {
168 return originalResult;
169 }
170 if (this.logger.isDebugEnabled()) {
171 this.logger.debug("Could not resolve variable '" + name + "'");
172 }
173 return null;
174 }
175
176 /***
177 * Retrieve the Spring BeanFactory to delegate bean name resolution to.
178 * <p>
179 * Default implementation delegates to <code>getWebApplicationContext</code>. Can be overridden to provide an arbitrary BeanFactory reference to resolve against; usually,
180 * this will be a full Spring ApplicationContext.
181 *
182 * @param facesContext
183 * the current JSF context
184 * @return the Spring BeanFactory (never <code>null</code>)
185 * @see #getWebApplicationContext
186 */
187 protected BeanFactory getBeanFactory(final FacesContext facesContext) {
188 return this.getWebApplicationContext(facesContext);
189 }
190
191 /***
192 * Retrieve the web application context to delegate bean name resolution to.
193 * <p>
194 * Default implementation delegates to FacesContextUtils.
195 *
196 * @param facesContext
197 * the current JSF context
198 * @return the Spring web application context (never <code>null</code>)
199 * @see FacesContextUtils#getRequiredWebApplicationContext
200 */
201 protected WebApplicationContext getWebApplicationContext(final FacesContext facesContext) {
202 return FacesContextUtils.getRequiredWebApplicationContext(facesContext);
203 }
204 }