1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.myfaces.tobago.facelets;
21
22 import org.apache.commons.beanutils.PropertyUtils;
23 import org.apache.commons.lang.StringUtils;
24 import org.apache.myfaces.tobago.component.Attributes;
25 import org.apache.myfaces.tobago.component.SupportsMarkup;
26 import org.apache.myfaces.tobago.component.SupportsRenderedPartially;
27 import org.apache.myfaces.tobago.context.Markup;
28 import org.apache.myfaces.tobago.el.ConstantMethodBinding;
29 import org.apache.myfaces.tobago.util.ComponentUtils;
30 import org.slf4j.Logger;
31 import org.slf4j.LoggerFactory;
32
33 import javax.el.ELException;
34 import javax.el.ExpressionFactory;
35 import javax.el.MethodExpression;
36 import javax.el.ValueExpression;
37 import javax.faces.FacesException;
38 import javax.faces.component.ActionSource;
39 import javax.faces.component.ActionSource2;
40 import javax.faces.component.EditableValueHolder;
41 import javax.faces.component.UIComponent;
42 import javax.faces.component.ValueHolder;
43 import javax.faces.convert.Converter;
44 import javax.faces.event.MethodExpressionActionListener;
45 import javax.faces.event.MethodExpressionValueChangeListener;
46 import javax.faces.validator.MethodExpressionValidator;
47 import javax.faces.view.facelets.ComponentHandler;
48 import javax.faces.view.facelets.FaceletContext;
49 import javax.faces.view.facelets.TagAttribute;
50 import javax.faces.view.facelets.TagConfig;
51 import javax.faces.view.facelets.TagException;
52 import javax.faces.view.facelets.TagHandler;
53 import java.beans.IntrospectionException;
54 import java.beans.PropertyDescriptor;
55
56 public final class AttributeHandler extends TagHandler {
57
58 private static final Logger LOG = LoggerFactory.getLogger(AttributeHandler.class);
59
60 private final TagAttribute name;
61
62 private final TagAttribute value;
63
64 private final TagAttribute mode;
65
66 public AttributeHandler(TagConfig config) {
67 super(config);
68 this.name = getRequiredAttribute(Attributes.NAME);
69 this.value = getRequiredAttribute(Attributes.VALUE);
70 this.mode = getAttribute(Attributes.MODE);
71 }
72
73 public void apply(FaceletContext faceletContext, UIComponent parent)
74 throws FacesException, ELException {
75 if (parent == null) {
76 throw new TagException(tag, "Parent UIComponent was null");
77 }
78
79 if (ComponentHandler.isNew(parent)) {
80
81 if (mode != null) {
82 if ("isNotSet".equals(mode.getValue())) {
83 boolean result = false;
84 String expressionString = value.getValue();
85 if (!value.isLiteral()) {
86 while (isSimpleExpression(expressionString)) {
87 if (isMethodOrValueExpression(expressionString)) {
88 ValueExpression expression
89 = faceletContext.getVariableMapper().resolveVariable(removeElParenthesis(expressionString));
90 if (expression == null) {
91 result = true;
92 break;
93 } else {
94 expressionString = expression.getExpressionString();
95 }
96 } else {
97 result = false;
98 break;
99 }
100 }
101 } else {
102 result = StringUtils.isEmpty(expressionString);
103 }
104 parent.getAttributes().put(name.getValue(), result);
105 } else if ("isSet".equals(mode.getValue())) {
106 boolean result = true;
107 String expressionString = value.getValue();
108 if (!value.isLiteral()) {
109 while (isSimpleExpression(expressionString)) {
110 if (isMethodOrValueExpression(expressionString)) {
111 ValueExpression expression
112 = faceletContext.getVariableMapper().resolveVariable(removeElParenthesis(expressionString));
113 if (expression == null) {
114 result = false;
115 break;
116 } else {
117 expressionString = expression.getExpressionString();
118 }
119 } else {
120 result = true;
121 break;
122 }
123 }
124 } else {
125 result = StringUtils.isNotEmpty(expressionString);
126 }
127 parent.getAttributes().put(name.getValue(), result);
128 } else if ("action".equals(mode.getValue())) {
129 String expressionString = value.getValue();
130 while (isSimpleExpression(expressionString)) {
131 if (isMethodOrValueExpression(expressionString)) {
132 ValueExpression expression
133 = faceletContext.getVariableMapper().resolveVariable(removeElParenthesis(expressionString));
134 if (expression == null) {
135
136 if (LOG.isDebugEnabled()) {
137 LOG.debug("Variable can't be resolved: value='" + expressionString + "'");
138 }
139 expressionString = null;
140 break;
141 } else {
142 expressionString = expression.getExpressionString();
143 }
144 } else {
145 break;
146 }
147 }
148 if (expressionString != null) {
149 ExpressionFactory expressionFactory = faceletContext.getExpressionFactory();
150 MethodExpression action = new TagMethodExpression(value, expressionFactory.createMethodExpression(
151 faceletContext, expressionString, String.class, ComponentUtils.ACTION_ARGS));
152 ((ActionSource2) parent).setActionExpression(action);
153 }
154 } else if ("actionListener".equals(mode.getValue())) {
155 String expressionString = value.getValue();
156 while (isSimpleExpression(expressionString)) {
157 if (isMethodOrValueExpression(expressionString)) {
158 ValueExpression expression
159 = faceletContext.getVariableMapper().resolveVariable(removeElParenthesis(expressionString));
160 if (expression == null) {
161 if (LOG.isDebugEnabled()) {
162
163 LOG.debug("Variable can't be resolved: value='" + expressionString + "'");
164 }
165 expressionString = null;
166 break;
167 } else {
168 expressionString = expression.getExpressionString();
169 }
170 } else {
171 LOG.warn("Only expressions are supported mode=actionListener value='" + expressionString + "'");
172 expressionString = null;
173 break;
174 }
175 }
176 if (expressionString != null) {
177 ExpressionFactory expressionFactory = faceletContext.getExpressionFactory();
178 MethodExpression actionListener = new TagMethodExpression(value, expressionFactory.createMethodExpression(
179 faceletContext, expressionString, null, ComponentUtils.ACTION_LISTENER_ARGS));
180 ((ActionSource) parent).addActionListener(new MethodExpressionActionListener(actionListener));
181 }
182 } else if ("actionFromValue".equals(mode.getValue())) {
183 if (!value.isLiteral()) {
184 String result = value.getValue(faceletContext);
185 parent.getAttributes().put(name.getValue(), new ConstantMethodBinding(result));
186 }
187 } else if ("valueIfSet".equals(mode.getValue())) {
188 String expressionString = value.getValue();
189 String lastExpressionString = null;
190 while (isMethodOrValueExpression(expressionString) && isSimpleExpression(expressionString)) {
191 ValueExpression expression
192 = faceletContext.getVariableMapper().resolveVariable(removeElParenthesis(expressionString));
193 if (expression != null) {
194 lastExpressionString = expressionString;
195 expressionString = expression.getExpressionString();
196 } else {
197
198 expressionString = lastExpressionString;
199 break;
200 }
201 }
202 if (expressionString != null) {
203 final String attributeName = name.getValue(faceletContext);
204 if (containsMethodOrValueExpression(expressionString)) {
205 ValueExpression expression = value.getValueExpression(faceletContext, Object.class);
206 parent.setValueExpression(attributeName, expression);
207 } else {
208 final Object literalValue = getValue(faceletContext, parent, expressionString, attributeName);
209 parent.getAttributes().put(attributeName, literalValue);
210 }
211 }
212 } else {
213 throw new FacesException("Type " + mode + " not supported");
214 }
215 } else {
216
217 String nameValue = name.getValue(faceletContext);
218 if (Attributes.RENDERED.equals(nameValue)) {
219 if (value.isLiteral()) {
220 parent.setRendered(value.getBoolean(faceletContext));
221 } else {
222 parent.setValueExpression(nameValue, value.getValueExpression(faceletContext, Boolean.class));
223 }
224 } else if (Attributes.RENDERED_PARTIALLY.equals(nameValue)
225 && parent instanceof SupportsRenderedPartially) {
226
227 if (value.isLiteral()) {
228 String[] components = ComponentUtils.splitList(value.getValue());
229 ((SupportsRenderedPartially) parent).setRenderedPartially(components);
230 } else {
231 parent.setValueExpression(nameValue, value.getValueExpression(faceletContext, Object.class));
232 }
233 } else if (Attributes.STYLE_CLASS.equals(nameValue)) {
234
235 ComponentUtils.setStyleClasses(parent, value.getValue());
236 } else if (Attributes.MARKUP.equals(nameValue)) {
237 if (parent instanceof SupportsMarkup) {
238 if (value.isLiteral()) {
239 ((SupportsMarkup) parent).setMarkup(Markup.valueOf(value.getValue()));
240 } else {
241 ValueExpression expression = value.getValueExpression(faceletContext, Object.class);
242 parent.setValueExpression(nameValue, expression);
243 }
244 } else {
245 LOG.error("Component is not instanceof SupportsMarkup. Instance is: " + parent.getClass().getName());
246 }
247 } else if (parent instanceof EditableValueHolder && Attributes.VALIDATOR.equals(nameValue)) {
248 MethodExpression methodExpression = getMethodExpression(faceletContext, null, ComponentUtils.VALIDATOR_ARGS);
249 if (methodExpression != null) {
250 ((EditableValueHolder) parent).addValidator(new MethodExpressionValidator(methodExpression));
251 }
252 } else if (parent instanceof EditableValueHolder
253 && Attributes.VALUE_CHANGE_LISTENER.equals(nameValue)) {
254 MethodExpression methodExpression =
255 getMethodExpression(faceletContext, null, ComponentUtils.VALUE_CHANGE_LISTENER_ARGS);
256 if (methodExpression != null) {
257 ((EditableValueHolder) parent).addValueChangeListener(
258 new MethodExpressionValueChangeListener(methodExpression));
259 }
260 } else if (parent instanceof ValueHolder && Attributes.CONVERTER.equals(nameValue)) {
261 setConverter(faceletContext, parent, nameValue);
262 } else if (parent instanceof ActionSource && Attributes.ACTION.equals(nameValue)) {
263 MethodExpression action = getMethodExpression(faceletContext, String.class, ComponentUtils.ACTION_ARGS);
264 if (action != null) {
265 ((ActionSource2) parent).setActionExpression(action);
266 }
267 } else if (parent instanceof ActionSource && Attributes.ACTION_LISTENER.equals(nameValue)) {
268 MethodExpression action = getMethodExpression(faceletContext, null, ComponentUtils.ACTION_LISTENER_ARGS);
269 if (action != null) {
270 ((ActionSource) parent).addActionListener(new MethodExpressionActionListener(action));
271 }
272 } else if (!parent.getAttributes().containsKey(nameValue)) {
273 if (value.isLiteral()) {
274 parent.getAttributes().put(nameValue, value.getValue());
275 } else {
276 parent.setValueExpression(nameValue, value.getValueExpression(faceletContext, Object.class));
277 }
278 }
279 }
280 }
281 }
282
283 private boolean isMethodOrValueExpression(String string) {
284 return (string.startsWith("${") || string.startsWith("#{")) && string.endsWith("}");
285 }
286
287 private boolean containsMethodOrValueExpression(String string) {
288 return (StringUtils.contains(string, "${") || StringUtils.contains(string, "#{"))
289 && StringUtils.contains(string, "}");
290 }
291
292 private boolean isSimpleExpression(String string) {
293 return string.indexOf('.') < 0 && string.indexOf('[') < 0;
294 }
295
296 private String removeElParenthesis(String string) {
297 return string.substring(2, string.length() - 1);
298 }
299
300 private ValueExpression getExpression(FaceletContext faceletContext) {
301 String myValue = removeElParenthesis(value.getValue());
302 return faceletContext.getVariableMapper().resolveVariable(myValue);
303 }
304
305 private MethodExpression getMethodExpression(FaceletContext faceletContext, Class returnType, Class[] args) {
306
307
308
309 if (value.getValue().startsWith("${")) {
310 ValueExpression expression = getExpression(faceletContext);
311 if (expression != null) {
312 ExpressionFactory expressionFactory = faceletContext.getExpressionFactory();
313 return new TagMethodExpression(value, expressionFactory.createMethodExpression(faceletContext,
314 expression.getExpressionString(), returnType, args));
315 } else {
316 return null;
317 }
318 } else {
319 return value.getMethodExpression(faceletContext, returnType, args);
320 }
321 }
322
323 private Object getValue(
324 FaceletContext faceletContext, UIComponent parent, String expressionString, String attributeName) {
325 Class type = Object.class;
326 try {
327 type = PropertyUtils.getReadMethod(
328 new PropertyDescriptor(attributeName, parent.getClass())).getReturnType();
329 } catch (IntrospectionException e) {
330 LOG.warn("Can't determine expected type", e);
331 }
332 ExpressionFactory expressionFactory = faceletContext.getExpressionFactory();
333 final ValueExpression valueExpression = expressionFactory
334 .createValueExpression(faceletContext, expressionString, type);
335 return valueExpression.getValue(faceletContext);
336 }
337
338 private void setConverter(FaceletContext faceletContext, UIComponent parent, String nameValue) {
339
340
341
342 if (value.getValue().startsWith("${")) {
343 ValueExpression expression = getExpression(faceletContext);
344 if (expression != null) {
345 setConverter(faceletContext, parent, nameValue, expression);
346 }
347 } else {
348 setConverter(faceletContext, parent, nameValue, value.getValueExpression(faceletContext, Object.class));
349 }
350 }
351
352 private void setConverter(
353 FaceletContext faceletContext, UIComponent parent, String nameValue, ValueExpression expression) {
354 if (expression.isLiteralText()) {
355 Converter converter =
356 faceletContext.getFacesContext().getApplication().createConverter(expression.getExpressionString());
357 ((ValueHolder) parent).setConverter(converter);
358 } else {
359 parent.setValueExpression(nameValue, expression);
360 }
361 }
362 }