1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.custom.ppr;
20
21 import org.apache.commons.collections.CollectionUtils;
22 import org.apache.commons.lang.StringUtils;
23 import org.apache.commons.logging.Log;
24 import org.apache.commons.logging.LogFactory;
25 import org.apache.myfaces.component.html.ext.HtmlMessages;
26 import org.apache.myfaces.component.html.ext.UIComponentPerspective;
27 import org.apache.myfaces.shared_tomahawk.component.ExecuteOnCallback;
28 import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlRendererUtils;
29 import org.apache.myfaces.shared_tomahawk.renderkit.html.HtmlResponseWriterImpl;
30
31 import javax.faces.FacesException;
32 import javax.faces.application.FacesMessage;
33 import javax.faces.application.StateManager;
34 import javax.faces.component.UIComponent;
35 import javax.faces.component.UIViewRoot;
36 import javax.faces.context.ExternalContext;
37 import javax.faces.context.FacesContext;
38 import javax.faces.event.PhaseEvent;
39 import javax.faces.event.PhaseId;
40 import javax.faces.event.PhaseListener;
41 import javax.servlet.ServletRequest;
42 import javax.servlet.ServletResponse;
43 import java.io.IOException;
44 import java.io.PrintWriter;
45 import java.util.ArrayList;
46 import java.util.Collection;
47 import java.util.HashSet;
48 import java.util.Iterator;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.Set;
52 import java.util.StringTokenizer;
53
54
55
56
57
58
59
60
61 public class PPRPhaseListener implements PhaseListener
62 {
63 private static Log log = LogFactory.getLog(PPRPhaseListener.class);
64
65
66
67
68 private static final String PPR_PARAMETER = "org.apache.myfaces.PPRCtrl.ajaxRequest";
69
70
71
72
73
74 private static final String TRIGGERED_COMPONENTS_PARAMETER = "org.apache.myfaces.PPRCtrl.triggeredComponents";
75
76 private static final String XML_HEADER = "<?xml version=\"1.0\"?>\n";
77
78 public void afterPhase(PhaseEvent phaseEvent)
79 {
80 }
81
82
83
84
85
86
87
88
89
90 public void beforePhase(PhaseEvent event)
91 {
92 if (log.isDebugEnabled()) {
93 log.debug("In PPRPhaseListener beforePhase");
94 }
95
96 final FacesContext context = event.getFacesContext();
97 final ExternalContext externalContext = context.getExternalContext();
98
99 Map requestMap = externalContext.getRequestMap();
100
101 if (isPartialRequest(context)) {
102 processPartialPageRequest(context, externalContext, requestMap);
103 }
104 else {
105
106
107 resetTransientComponents(context.getViewRoot());
108 }
109 }
110
111
112
113
114
115
116
117 private void resetTransientComponents(UIComponent comp)
118 {
119 if (comp.getAttributes().containsKey(PPRPanelGroupRenderer.TRANSIENT_MARKER_ATTRIBUTE)) {
120 comp.setTransient(true);
121 }
122 for (Iterator iter = comp.getChildren().iterator(); iter.hasNext();) {
123 UIComponent child = (UIComponent) iter.next();
124 resetTransientComponents(child);
125 }
126 }
127
128
129
130
131
132
133
134
135 public static boolean isPartialRequest(FacesContext context)
136 {
137 return context.getExternalContext().getRequestParameterMap().containsKey(PPR_PARAMETER);
138 }
139
140
141
142
143
144
145
146
147
148
149
150
151 private void processPartialPageRequest(FacesContext context, final ExternalContext externalContext, Map requestMap)
152 {
153
154 ServletResponse response = (ServletResponse) externalContext.getResponse();
155 ServletRequest request = (ServletRequest) externalContext.getRequest();
156
157 UIViewRoot viewRoot = context.getViewRoot();
158
159
160 final String characterEncoding = request.getCharacterEncoding();
161 String contentType = getContentType("text/xml", characterEncoding);
162 response.setContentType(contentType);
163 response.setLocale(viewRoot.getLocale());
164
165
166 String triggeredComponents = getTriggeredComponents(context);
167
168 try {
169 PrintWriter out = response.getWriter();
170 context.setResponseWriter(new HtmlResponseWriterImpl(out, contentType, characterEncoding));
171 out.print(XML_HEADER);
172 out.print("<response>\n");
173 encodeTriggeredComponents(out, triggeredComponents, viewRoot, context);
174 out.print("</response>");
175 out.flush();
176 }
177 catch (IOException e) {
178 throw new FacesException(e);
179 }
180
181 context.responseComplete();
182 }
183
184
185
186
187
188
189
190
191
192
193
194
195 private static String getTriggeredComponents(FacesContext fc)
196 {
197 String triggeredComponents = (String) fc.getExternalContext().getRequestMap().get(TRIGGERED_COMPONENTS_PARAMETER);
198
199 if (triggeredComponents == null) {
200 triggeredComponents = (String) fc.getExternalContext().getRequestParameterMap().get(TRIGGERED_COMPONENTS_PARAMETER);
201 }
202
203 return triggeredComponents;
204 }
205
206
207
208
209
210
211
212
213 public static void addTriggeredComponent(FacesContext fc, String triggeredComponentClientId)
214 {
215 String triggeredComponents = getTriggeredComponents(fc);
216
217 if (triggeredComponents == null || triggeredComponents.trim().length() == 0) {
218 triggeredComponents = new String();
219 }
220 else {
221 triggeredComponents = triggeredComponents + ",";
222 }
223
224 triggeredComponents = triggeredComponents + triggeredComponentClientId;
225
226 fc.getExternalContext().getRequestMap().put(TRIGGERED_COMPONENTS_PARAMETER, triggeredComponents);
227 }
228
229
230
231
232
233
234
235
236
237 private String getContentType(String contentType, String charset)
238 {
239 if (charset == null || charset.trim().length() == 0) {
240 return contentType;
241 }
242 else {
243 return contentType + ";charset=" + charset;
244 }
245 }
246
247
248
249
250
251
252
253
254
255
256
257 private void encodeTriggeredComponents(PrintWriter out, String triggeredComponents, UIViewRoot viewRoot, FacesContext context)
258 {
259 StringTokenizer st = new StringTokenizer(triggeredComponents, ",", false);
260 String clientId;
261 UIComponent component;
262 boolean handleState = true;
263
264
265 Set toAppendMessagesComponents = new HashSet();
266 Set toReplaceMessagesComponents = new HashSet();
267
268
269 while (st.hasMoreTokens()) {
270 clientId = st.nextToken();
271 component = viewRoot.findComponent(clientId);
272 if (component != null) {
273
274
275
276 PPRPanelGroup ppr = null;
277 int oldIndex = 0;
278 if (component instanceof UIComponentPerspective) {
279 UIComponentPerspective uiComponentPerspective = (UIComponentPerspective) component;
280 ExecuteOnCallback getComponentCallback = new ExecuteOnCallback()
281 {
282 public Object execute(FacesContext context, UIComponent component)
283 {
284 return component;
285 }
286 };
287 Object retval = uiComponentPerspective.executeOn(context, getComponentCallback);
288 if (retval instanceof PPRPanelGroup) {
289 ppr = (PPRPanelGroup) retval;
290 }
291 else {
292 throw new IllegalArgumentException("Expect PPRPanelGroup or UiComponentPerspective");
293 }
294
295 oldIndex = uiComponentPerspective.getUiData().getRowIndex();
296 uiComponentPerspective.getUiData().setRowIndex(uiComponentPerspective.getRowIndex());
297 }
298 else if (component instanceof PPRPanelGroup) {
299 ppr = (PPRPanelGroup) component;
300 }
301 else {
302 throw new IllegalArgumentException("Expect PPRPanelGroup or UiComponentPerspective");
303 }
304 if (ppr.getStateUpdate().booleanValue() == false) {
305 handleState = false;
306 }
307
308 if (ppr.getAppendMessages() != null) {
309 List appendMessagesForThisGroup = PPRSupport.getComponentsByCommaSeparatedIdList(context, ppr, ppr.getAppendMessages(), HtmlMessages.class);
310 toAppendMessagesComponents.addAll(appendMessagesForThisGroup);
311 }
312
313
314 if (ppr.getReplaceMessages() != null) {
315 List replaceMessagesForThisGroup = PPRSupport.getComponentsByCommaSeparatedIdList(context, ppr, ppr.getReplaceMessages(), HtmlMessages.class);
316 toReplaceMessagesComponents.addAll(replaceMessagesForThisGroup);
317 }
318
319
320
321
322 out.print("<component id=\"" + component.getClientId(context) + "\"><![CDATA[");
323 boolean oldValue = HtmlRendererUtils.isAllowedCdataSection(context);
324 HtmlRendererUtils.allowCdataSection(context, false);
325 try {
326 component.encodeChildren(context);
327 }
328 catch (IOException e) {
329 throw new FacesException(e);
330 }
331 HtmlRendererUtils.allowCdataSection(context, oldValue);
332 out.print("]]></component>");
333
334
335 if (component instanceof UIComponentPerspective) {
336 UIComponentPerspective uiComponentPerspective = (UIComponentPerspective) component;
337 uiComponentPerspective.getUiData().setRowIndex(oldIndex);
338 }
339 }
340 else {
341 log.debug("PPRPhaseListener component with id" + clientId + "not found!");
342 }
343 }
344
345 boolean handleFacesMessages = !toAppendMessagesComponents.isEmpty() || !toReplaceMessagesComponents.isEmpty();
346
347 if (handleFacesMessages) {
348
349 Iterator messagesIterator = context.getMessages();
350
351
352 while (messagesIterator.hasNext()) {
353 FacesMessage msg = (FacesMessage) messagesIterator.next();
354 String messageText = msg.getSummary() + " " + msg.getDetail();
355 out.print("<message><![CDATA[");
356 out.print(messageText);
357 out.print("]]></message>");
358 }
359
360
361 Collection intersection = CollectionUtils.intersection(toAppendMessagesComponents, toReplaceMessagesComponents);
362 for (Iterator iterator = intersection.iterator(); iterator.hasNext();) {
363 UIComponent uiComponent = (UIComponent) iterator.next();
364 log.warn("Component with id " + uiComponent.getClientId(context) +
365 " is marked for replace and append messages -> replace has precedence");
366 toAppendMessagesComponents.remove(uiComponent);
367 }
368
369 for (Iterator iterator = toAppendMessagesComponents.iterator(); iterator.hasNext();) {
370 UIComponent uiComponent = (UIComponent) iterator.next();
371 out.print("<append id=\"");
372 out.print(uiComponent.getClientId(context));
373 out.print("\"/>");
374 }
375
376 for (Iterator iterator = toReplaceMessagesComponents.iterator(); iterator.hasNext();) {
377 UIComponent uiComponent = (UIComponent) iterator.next();
378 out.print("<replace id=\"");
379 out.print(uiComponent.getClientId(context));
380 out.print("\"/>");
381 }
382 }
383
384 if (handleState) {
385
386 out.print("<state>");
387 FacesContext facesContext = FacesContext.getCurrentInstance();
388 StateManager stateManager = facesContext.getApplication().getStateManager();
389 StateManager.SerializedView serializedView = stateManager.saveSerializedView(facesContext);
390 try {
391 stateManager.writeState(facesContext, serializedView);
392 }
393 catch (IOException e) {
394 throw new FacesException(e);
395 }
396 out.print("</state>");
397 }
398
399 }
400
401
402 private static List getComponentsByCommaSeparatedList(FacesContext context, UIComponent comp, String commaSeparatedIdList, Class componentType)
403 {
404 List retval = new ArrayList();
405 UIComponent currentComponent = null;
406 String[] componentIds = StringUtils.split(commaSeparatedIdList, ',');
407 for (int i = 0; i < componentIds.length; i++) {
408 String componentId = componentIds[i];
409
410 }
411 return retval;
412 }
413
414 public PhaseId getPhaseId()
415 {
416 return PhaseId.RENDER_RESPONSE;
417 }
418 }