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
015 package org.apache.tapestry5.ajax;
016
017 import org.apache.tapestry5.ClientBodyElement;
018 import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
019 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
020
021 import 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 */
037 public 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 }