    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}