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}