Classes in this File | Line Coverage | Branch Coverage | Complexity | ||||||||
ValidatorCommandRenderer |
|
| 1.7777777777777777;1.778 |
1 | /* |
|
2 | * Licensed to the Apache Software Foundation (ASF) under one or more |
|
3 | * contributor license agreements. See the NOTICE file distributed with |
|
4 | * this work for additional information regarding copyright ownership. |
|
5 | * The ASF licenses this file to you under the Apache License, Version 2.0 |
|
6 | * (the "License"); you may not use this file except in compliance with |
|
7 | * the License. You may obtain a copy of the License at |
|
8 | * |
|
9 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
10 | * |
|
11 | * Unless required by applicable law or agreed to in writing, software |
|
12 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
14 | * See the License for the specific language governing permissions and |
|
15 | * limitations under the License. |
|
16 | */ |
|
17 | ||
18 | package org.apache.shale.validator.faces; |
|
19 | ||
20 | import java.io.IOException; |
|
21 | import java.io.StringWriter; |
|
22 | import javax.faces.component.UICommand; |
|
23 | import javax.faces.component.UIComponent; |
|
24 | import javax.faces.context.FacesContext; |
|
25 | import javax.faces.context.ResponseWriter; |
|
26 | import javax.faces.convert.ConverterException; |
|
27 | import javax.faces.render.Renderer; |
|
28 | ||
29 | /** |
|
30 | * <p>This Renderer is a hybrid renderer decorator that is dynamically |
|
31 | * registered by {@link ValidatorRenderKit} |
|
32 | * for component renderers in the "javax.faces.Command" family.</p> |
|
33 | */ |
|
34 | public class ValidatorCommandRenderer extends Renderer { |
|
35 | ||
36 | ||
37 | /** |
|
38 | * <p>The Original Renderer.</p> |
|
39 | */ |
|
40 | 0 | private Renderer defaultRenderer = null; |
41 | ||
42 | ||
43 | /** |
|
44 | * <p>The overloaded constructor is passed the original |
|
45 | * <code>Renderer</code> for the family and component type.</p> |
|
46 | * |
|
47 | * @param defaultRenderer The default Renderer we should delegate to |
|
48 | */ |
|
49 | 0 | public ValidatorCommandRenderer(Renderer defaultRenderer) { |
50 | 0 | this.defaultRenderer = defaultRenderer; |
51 | 0 | } |
52 | ||
53 | ||
54 | /** |
|
55 | * <p>Attribute name used to override the default behavior of how the immediate |
|
56 | * attribute effects the execution of client side javascript validation.</p> |
|
57 | */ |
|
58 | public static final String OVERRIDE_IMMEDIATE = "org.apache.shale.validator.immediate"; |
|
59 | ||
60 | private static final int ENCODE_BEGIN = 0; |
|
61 | ||
62 | private static final int ENCODE_CHILDREN = 1; |
|
63 | ||
64 | private static final int ENCODE_END = 2; |
|
65 | ||
66 | ||
67 | /** |
|
68 | * <b>Interrogates the component's immediate property and the component's |
|
69 | * immediate override attribute to determine if client side validation is |
|
70 | * invoked. If either the property or attribute override is false, client |
|
71 | * side validation is invoked. Otherwise, the response writer is hijacked |
|
72 | * and the original render is invoked. The result is buffered and a |
|
73 | * statement of javascript is injected into the onclick event which cancels |
|
74 | * client side validation. The original response writer is restored and the |
|
75 | * modified markup is written to the response writer. The |
|
76 | * <code>encodeSwitch</code> determines if the encodeBegin, encodeChildren |
|
77 | * or encodeEnd methods should be invoked on the decorated renderer.</b> |
|
78 | * |
|
79 | * @param context FacesContext for the current request |
|
80 | * @param component UIComponent being rendered |
|
81 | * @param encodeSwitch FIXME - encode switch? |
|
82 | * |
|
83 | * @exception IOException if an input/output error occurs |
|
84 | */ |
|
85 | protected void encode(FacesContext context, UIComponent component, |
|
86 | int encodeSwitch) throws IOException { |
|
87 | ||
88 | 0 | UICommand command = (UICommand) component; |
89 | ||
90 | // look for a override to the default |
|
91 | 0 | boolean immediateOverride = true; |
92 | 0 | String attr = (String) component.getAttributes() |
93 | .get(OVERRIDE_IMMEDIATE); |
|
94 | 0 | if (attr != null) { |
95 | 0 | immediateOverride = Boolean.valueOf(attr).booleanValue(); |
96 | } |
|
97 | ||
98 | 0 | if (command.isImmediate() && immediateOverride) { |
99 | ||
100 | 0 | ResponseWriter hijackedWriter = context.getResponseWriter(); |
101 | // builds a buffer to write the page to |
|
102 | 0 | StringWriter writer = new StringWriter(); |
103 | // create a buffered response writer |
|
104 | 0 | ResponseWriter buffResponsewriter = context.getRenderKit() |
105 | .createResponseWriter(writer, null, |
|
106 | hijackedWriter.getCharacterEncoding()); |
|
107 | // push buffered writer to the faces context |
|
108 | 0 | context.setResponseWriter(buffResponsewriter); |
109 | ||
110 | 0 | if (encodeSwitch == ENCODE_BEGIN) { |
111 | 0 | defaultRenderer.encodeBegin(context, component); |
112 | 0 | } else if (encodeSwitch == ENCODE_CHILDREN) { |
113 | 0 | defaultRenderer.encodeChildren(context, component); |
114 | 0 | } else { |
115 | 0 | defaultRenderer.encodeEnd(context, component); |
116 | } |
|
117 | ||
118 | 0 | buffResponsewriter.write(' '); |
119 | 0 | buffResponsewriter.flush(); |
120 | 0 | buffResponsewriter.close(); |
121 | 0 | writer.flush(); |
122 | 0 | writer.close(); |
123 | 0 | StringBuffer buff = writer.getBuffer(); |
124 | 0 | int i = buff.indexOf("onclick=\""); |
125 | 0 | if (i > 0) { |
126 | 0 | buff.insert(i + "onclick=\"".length(), "bCancel=true;"); |
127 | } |
|
128 | ||
129 | 0 | hijackedWriter.write(buff.toString()); |
130 | 0 | context.setResponseWriter(hijackedWriter); |
131 | ||
132 | 0 | } else { |
133 | ||
134 | 0 | if (encodeSwitch == ENCODE_BEGIN) { |
135 | 0 | defaultRenderer.encodeBegin(context, component); |
136 | 0 | } else if (encodeSwitch == ENCODE_CHILDREN) { |
137 | 0 | defaultRenderer.encodeChildren(context, component); |
138 | 0 | } else { |
139 | 0 | defaultRenderer.encodeEnd(context, component); |
140 | } |
|
141 | ||
142 | } |
|
143 | ||
144 | 0 | } |
145 | ||
146 | ||
147 | /** {@inheritDoc} */ |
|
148 | public String convertClientId(FacesContext context, String id) { |
|
149 | 0 | return defaultRenderer.convertClientId(context, id); |
150 | } |
|
151 | ||
152 | ||
153 | /** {@inheritDoc} */ |
|
154 | public Object getConvertedValue(FacesContext context, UIComponent component, Object o) throws ConverterException { |
|
155 | 0 | return defaultRenderer.getConvertedValue(context, component, o); |
156 | } |
|
157 | ||
158 | ||
159 | /** {@inheritDoc} */ |
|
160 | public void decode(FacesContext context, UIComponent component) { |
|
161 | 0 | defaultRenderer.decode(context, component); |
162 | 0 | } |
163 | ||
164 | ||
165 | /** |
|
166 | * <p> |
|
167 | * Invokes the <code>encode</code> method passing |
|
168 | * <code>ENCODE_BEGIN</code> for the encodeSwitch parameter. |
|
169 | * </p> |
|
170 | * |
|
171 | * @param context FacesContext for the current request |
|
172 | * @param component UIComponent being rendered |
|
173 | * |
|
174 | * @exception IOException if an input/output error occurs |
|
175 | */ |
|
176 | public void encodeBegin(FacesContext context, UIComponent component) |
|
177 | throws IOException { |
|
178 | 0 | encode(context, component, ENCODE_BEGIN); |
179 | 0 | } |
180 | ||
181 | ||
182 | /** |
|
183 | * <p>Invokes the <code>encode</code> method passing |
|
184 | * <code>ENCODE_CHILDREN</code> for the encodeSwitch parameter.</p> |
|
185 | * |
|
186 | * @param context FacesContext for the current request |
|
187 | * @param component UIComponent being rendered |
|
188 | * |
|
189 | * @exception IOException if an input/output error occurs |
|
190 | */ |
|
191 | public void encodeChildren(FacesContext context, UIComponent component) |
|
192 | throws IOException { |
|
193 | 0 | encode(context, component, ENCODE_CHILDREN); |
194 | 0 | } |
195 | ||
196 | ||
197 | /** |
|
198 | * <p>Invokes the <code>encode</code> method passing <code>ENCODE_END</code> |
|
199 | * for the encodeSwitch parameter.</p> |
|
200 | * |
|
201 | * @param context FacesContext for the current reqauest |
|
202 | * @param component UIComponent being rendered |
|
203 | * |
|
204 | * @exception IOException if an input/output error occurs |
|
205 | */ |
|
206 | public void encodeEnd(FacesContext context, UIComponent component) |
|
207 | throws IOException { |
|
208 | 0 | encode(context, component, ENCODE_END); |
209 | 0 | } |
210 | ||
211 | ||
212 | /** {@inheritDoc} */ |
|
213 | public boolean getRendersChildren() { |
|
214 | 0 | return defaultRenderer.getRendersChildren(); |
215 | } |
|
216 | ||
217 | ||
218 | } |