    001// Copyright 2009, 2010 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.ajax;
    016
    017import org.apache.tapestry5.ClientBodyElement;
    018import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
    019import org.apache.tapestry5.ioc.internal.util.InternalUtils;
    020
    021import java.util.Map;
    022
    023/**
    024 * A mapping from <em>client-side zone ids</em> to objects that can render the content for that zone on the client. An
    025 * event handler method may instantiate an instance and chain together a series of calls to {@link #add(String, Object)}
    026 * , and return the final result.
    027 * <p/>
    028 * Remember that client-side element ids may not match server-side component ids, especially once Ajax is added to the
    029 * mix. Because of this, it is highly recommended that the client-side logic gather the actual component ids and include
    030 * those in the Ajax request, to ensure that the server generates updates that the client can process. Better yet, use
    031 * the Zone's id parameter to lock down the zone's id to a known, predictable value.
    032 *
    033 * @since 5.1.0.1
    034 * @deprecated Deprecated in 5.3; use the {@link org.apache.tapestry5.services.ajax.AjaxResponseRenderer} service instead of
    035 *             returning an instance of MultiZoneUpdate
    036 */
    037public class MultiZoneUpdate
    038{
    039    private final MultiZoneUpdate parent;
    040
    041    private final String zoneId;
    042
    043    private final Object renderer;
    044
    045    public MultiZoneUpdate(String zoneId, Object renderer)
    046    {
    047        this(zoneId, renderer, null);
    048    }
    049
    050    /**
    051     * Alternate constructor that takes a ClientBodyElement (typically, a
    052     * {@link org.apache.tapestry5.corelib.components.Zone}).
    053     */
    054    public MultiZoneUpdate(ClientBodyElement zone)
    055    {
    056        this(zone.getClientId(), zone.getBody());
    057    }
    058
    059    private MultiZoneUpdate(String zoneId, Object renderer, MultiZoneUpdate parent)
    060    {
    061        assert renderer != null;
    062        assert InternalUtils.isNonBlank(zoneId);
    063
    064        this.zoneId = zoneId;
    065        this.renderer = renderer;
    066        this.parent = parent;
    067    }
    068
    069    /**
    070     * Adds the zone (represented by the {@link ClientBodyElement}) to the update.
    071     *
    072     * @since 5.2.3
    073     */
    074    public MultiZoneUpdate add(ClientBodyElement zone)
    075    {
    076        assert zone != null;
    077
    078        return add(zone.getClientId(), zone.getBody());
    079    }
    080
    081    /**
    082     * Returns a <strong>new</strong> MultiZoneUpdate reflecting the mapping from the indicated zone to an object that
    083     * will render the content for that zone.
    084     *
    085     * @param zoneId   client id of zone to update
    086     * @param renderer object that can provide the content for the zone
    087     * @return new MultiZoneUpdate
    088     */
    089    public MultiZoneUpdate add(String zoneId, Object renderer)
    090    {
    091        return new MultiZoneUpdate(zoneId, renderer, this);
    092    }
    093
    094    /**
    095     * Returns a mapping from client zone id to renderer object for that zone.
    096     *
    097     * @return string to renderer map
    098     */
    099    public Map<String, Object> getZoneToRenderMap()
    100    {
    101        Map<String, Object> result = CollectionFactory.newMap();
    102
    103        MultiZoneUpdate cursor = this;
    104
    105        while (cursor != null)
    106        {
    107            result.put(cursor.zoneId, cursor.renderer);
    108
    109            cursor = cursor.parent;
    110        }
    111
    112        return result;
    113    }
    114
    115    @Override
    116    public String toString()
    117    {
    118        return String.format("MultiZoneUpdate[%s]", getZoneToRenderMap());
    119    }
    120}