    001// Licensed under the Apache License, Version 2.0 (the "License");
    002// you may not use this file except in compliance with the License.
    003// You may obtain a copy of the License at
    004//
    005// http://www.apache.org/licenses/LICENSE-2.0
    006//
    007// Unless required by applicable law or agreed to in writing, software
    008// distributed under the License is distributed on an "AS IS" BASIS,
    009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    010// See the License for the specific language governing permissions and
    011// limitations under the License.
    012
    013package org.apache.tapestry5.ajax;
    014
    015import org.apache.tapestry5.ClientBodyElement;
    016import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
    017import org.apache.tapestry5.ioc.internal.util.InternalUtils;
    018
    019import java.util.Map;
    020
    021/**
    022 * A mapping from <em>client-side zone ids</em> to objects that can render the content for that zone on the client. An
    023 * event handler method may instantiate an instance and chain together a series of calls to {@link #add(String, Object)}
    024 * , and return the final result.
    025 *
    026 * Remember that client-side element ids may not match server-side component ids, especially once Ajax is added to the
    027 * mix. Because of this, it is highly recommended that the client-side logic gather the actual component ids and include
    028 * those in the Ajax request, to ensure that the server generates updates that the client can process. Better yet, use
    029 * the Zone's id parameter to lock down the zone's id to a known, predictable value.
    030 *
    031 * @since 5.1.0.1
    032 * @deprecated Deprecated in 5.3; use the {@link org.apache.tapestry5.services.ajax.AjaxResponseRenderer} service instead of
    033 *             returning an instance of MultiZoneUpdate
    034 */
    035public class MultiZoneUpdate
    036{
    037    private final MultiZoneUpdate parent;
    038
    039    private final String zoneId;
    040
    041    private final Object renderer;
    042
    043    public MultiZoneUpdate(String zoneId, Object renderer)
    044    {
    045        this(zoneId, renderer, null);
    046    }
    047
    048    /**
    049     * Alternate constructor that takes a ClientBodyElement (typically, a
    050     * {@link org.apache.tapestry5.corelib.components.Zone}).
    051     */
    052    public MultiZoneUpdate(ClientBodyElement zone)
    053    {
    054        this(zone.getClientId(), zone.getBody());
    055    }
    056
    057    private MultiZoneUpdate(String zoneId, Object renderer, MultiZoneUpdate parent)
    058    {
    059        assert renderer != null;
    060        assert InternalUtils.isNonBlank(zoneId);
    061
    062        this.zoneId = zoneId;
    063        this.renderer = renderer;
    064        this.parent = parent;
    065    }
    066
    067    /**
    068     * Adds the zone (represented by the {@link ClientBodyElement}) to the update.
    069     *
    070     * @since 5.2.3
    071     */
    072    public MultiZoneUpdate add(ClientBodyElement zone)
    073    {
    074        assert zone != null;
    075
    076        return add(zone.getClientId(), zone.getBody());
    077    }
    078
    079    /**
    080     * Returns a <strong>new</strong> MultiZoneUpdate reflecting the mapping from the indicated zone to an object that
    081     * will render the content for that zone.
    082     *
    083     * @param zoneId   client id of zone to update
    084     * @param renderer object that can provide the content for the zone
    085     * @return new MultiZoneUpdate
    086     */
    087    public MultiZoneUpdate add(String zoneId, Object renderer)
    088    {
    089        return new MultiZoneUpdate(zoneId, renderer, this);
    090    }
    091
    092    /**
    093     * Returns a mapping from client zone id to renderer object for that zone.
    094     *
    095     * @return string to renderer map
    096     */
    097    public Map<String, Object> getZoneToRenderMap()
    098    {
    099        Map<String, Object> result = CollectionFactory.newMap();
    100
    101        MultiZoneUpdate cursor = this;
    102
    103        while (cursor != null)
    104        {
    105            result.put(cursor.zoneId, cursor.renderer);
    106
    107            cursor = cursor.parent;
    108        }
    109
    110        return result;
    111    }
    112
    113    @Override
    114    public String toString()
    115    {
    116        return String.format("MultiZoneUpdate[%s]", getZoneToRenderMap());
    117    }
    118}