001// Copyright 2009-2014 The Apache Software Foundation 002// 003// Licensed under the Apache License, Version 2.0 (the "License"); 004// you may not use this file except in compliance with the License. 005// You may obtain a copy of the License at 006// 007// http://www.apache.org/licenses/LICENSE-2.0 008// 009// Unless required by applicable law or agreed to in writing, software 010// distributed under the License is distributed on an "AS IS" BASIS, 011// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 012// See the License for the specific language governing permissions and 013// limitations under the License. 014 015package org.apache.tapestry5.internal.services.ajax; 016 017import org.apache.tapestry5.ajax.MultiZoneUpdate; 018import org.apache.tapestry5.commons.services.TypeCoercer; 019import org.apache.tapestry5.commons.util.ExceptionUtils; 020import org.apache.tapestry5.internal.services.AjaxPartialResponseRenderer; 021import org.apache.tapestry5.runtime.RenderCommand; 022import org.apache.tapestry5.services.ComponentEventResultProcessor; 023import org.apache.tapestry5.services.ajax.AjaxResponseRenderer; 024 025import java.io.IOException; 026import java.util.Map; 027 028/** 029 * Handler for {@link org.apache.tapestry5.ajax.MultiZoneUpdate} responses from a component event handler method. Works 030 * by adding {@link SingleZonePartialRendererFilter}s for each zone to the 031 * {@linkplain org.apache.tapestry5.internal.services.PageRenderQueue#addPartialMarkupRendererFilter(org.apache.tapestry5.services.PartialMarkupRendererFilter) 032 * filter stack}. Each zone writes its content as a string in the zones object of the reply, keyed on its id. 033 * JavaScript and CSS are collected for all zones rendered in the request (not for each individual zone). The final 034 * response will have some combination of "script", "scripts", "stylesheets", "content" (which is expected to be blank) 035 * and "zones". 036 * 037 * @since 5.1.0.1 038 * @deprecated Deprecated in 5.3 039 */ 040public class MultiZoneUpdateEventResultProcessor implements ComponentEventResultProcessor<MultiZoneUpdate> 041{ 042 private final TypeCoercer typeCoercer; 043 044 private final AjaxResponseRenderer ajaxResponseRenderer; 045 046 private final AjaxPartialResponseRenderer partialRenderer; 047 048 public MultiZoneUpdateEventResultProcessor(TypeCoercer typeCoercer, AjaxResponseRenderer ajaxResponseRenderer, AjaxPartialResponseRenderer partialRenderer) 049 { 050 this.typeCoercer = typeCoercer; 051 this.ajaxResponseRenderer = ajaxResponseRenderer; 052 this.partialRenderer = partialRenderer; 053 } 054 055 public void processResultValue(final MultiZoneUpdate value) throws IOException 056 { 057 058 Map<String, Object> map = value.getZoneToRenderMap(); 059 060 for (String zoneId : map.keySet()) 061 { 062 Object provided = map.get(zoneId); 063 064 // The AjaxResponseRenderer will convert the object to a RenderCommand, but does nothing special if there's a failure 065 // (because the stack trace will clearly identify what's going on). We do the conversion here so that we can relate 066 // a failure to a zone id. It will just be a pass-thru on the second type coercion. 067 068 RenderCommand zoneRenderCommand = toRenderer(zoneId, provided); 069 070 ajaxResponseRenderer.addRender(zoneId, zoneRenderCommand); 071 } 072 073 // This is actually executed deferred: 074 075 partialRenderer.renderPartialPageMarkup(); 076 } 077 078 private RenderCommand toRenderer(String zoneId, Object provided) 079 { 080 try 081 { 082 return typeCoercer.coerce(provided, RenderCommand.class); 083 } catch (Exception ex) 084 { 085 throw new IllegalArgumentException(String.format("Failure converting renderer for zone '%s': %s", zoneId, 086 ExceptionUtils.toMessage(ex)), ex); 087 } 088 } 089}