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