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.internal.services.AjaxPartialResponseRenderer;
019import org.apache.tapestry5.ioc.services.TypeCoercer;
020import org.apache.tapestry5.ioc.util.ExceptionUtils;
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}