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