001 // Copyright 2004, 2005 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.tapestry.components;
016
017 import org.apache.commons.logging.Log;
018 import org.apache.commons.logging.LogFactory;
019 import org.apache.hivemind.ApplicationRuntimeException;
020 import org.apache.hivemind.HiveMind;
021 import org.apache.tapestry.*;
022 import org.apache.tapestry.engine.NullWriter;
023 import org.apache.tapestry.form.AbstractFormComponent;
024 import org.apache.tapestry.services.DataSqueezer;
025
026 /**
027 * @author mb
028 */
029 public abstract class IfBean extends AbstractFormComponent
030 {
031 public static final Log _log = LogFactory.getLog(IfBean.class);
032
033 public static final String IF_VALUE_ATTRIBUTE = "org.mb.tapestry.base.IfValue";
034
035 private boolean _rendering = false;
036
037 private boolean _conditionValue;
038
039 public abstract IBinding getConditionValueBinding();
040
041 public abstract boolean getCondition();
042
043 public abstract boolean getVolatile();
044
045 public abstract String getElement();
046
047 public abstract boolean getRenderTag();
048
049 public abstract IActionListener getListener();
050
051 protected void renderComponent(IMarkupWriter writer, IRequestCycle cycle)
052 {
053 boolean cycleRewinding = cycle.isRewinding();
054
055 // form may be null if component is not located in a form
056 IForm form = (IForm)cycle.getAttribute(TapestryUtils.FORM_ATTRIBUTE);
057
058 // If the cycle is rewinding, but not this particular form,
059 // then do nothing (don't even render the body).
060
061 if (cycleRewinding && form != null && !form.isRewinding())
062 return;
063
064 // get the condition. work with a hidden field if necessary
065
066 _conditionValue = evaluateCondition(cycle, form, cycleRewinding);
067 _rendering = true;
068
069 if (!cycleRewinding && form != null && !NullWriter.class.isInstance(writer))
070 form.setFormFieldUpdating(true);
071
072 try
073 {
074 // call listener
075 IActionListener listener = getListener();
076 if (listener != null)
077 listener.actionTriggered(this, cycle);
078
079 // now render if condition is true
080 if (_conditionValue)
081 {
082 String element = HiveMind.isNonBlank(getElement()) ? getElement() : getTemplateTagName();
083
084 boolean render = !cycleRewinding && (getRenderTag() || HiveMind.isNonBlank(getElement()));
085
086 if (render)
087 {
088 writer.begin(element);
089
090 renderInformalParameters(writer, cycle);
091 renderIdAttribute(writer, cycle);
092 }
093
094 renderBody(writer, cycle);
095
096 if (render)
097 writer.end(element);
098 }
099 }
100 finally
101 {
102 _rendering = false;
103 }
104
105 cycle.setAttribute(IF_VALUE_ATTRIBUTE, new Boolean(_conditionValue));
106 }
107
108 /**
109 * Overriden from {@link AbstractFormComponent} to handle cases where
110 * we're not being wrapped by a {@link IForm} component.
111 *
112 * <p>This is basically a copy of the same method implemented in {@link AbstractComponent}.</p>
113 */
114 protected void generateClientId()
115 {
116 String id = getSpecifiedId();
117
118 if (id != null && getPage() != null && getPage().getRequestCycle() != null)
119 setClientId(getPage().getRequestCycle().getUniqueId(TapestryUtils.convertTapestryIdToNMToken(id)));
120 }
121
122 protected boolean evaluateCondition(IRequestCycle cycle, IForm form, boolean cycleRewinding)
123 {
124 boolean condition;
125
126 if (form == null || getVolatile())
127 {
128 condition = getCondition();
129 }
130 else
131 {
132 // we are in a form and we care -- load/store the condition in a hidden field
133
134 String name = form.getElementId(this);
135
136 if (!cycleRewinding)
137 {
138 condition = getCondition();
139 writeValue(form, name, condition);
140 }
141 else
142 {
143 condition = readValue(cycle, name);
144 }
145 }
146
147 // write condition value if parameter is bound
148
149 IBinding conditionValueBinding = getConditionValueBinding();
150
151 if (conditionValueBinding != null)
152 conditionValueBinding.setObject(new Boolean(condition));
153
154 return condition;
155 }
156
157 private void writeValue(IForm form, String name, boolean value)
158 {
159 String externalValue;
160
161 Object booleanValue = new Boolean(value);
162 try
163 {
164 externalValue = getDataSqueezer().squeeze(booleanValue);
165 }
166 catch (Exception ex)
167 {
168 throw new ApplicationRuntimeException(Tapestry.format("If.unable-to-convert-value",booleanValue), this, null, ex);
169 }
170
171 form.addHiddenValue(name, externalValue);
172 }
173
174 private boolean readValue(IRequestCycle cycle, String name)
175 {
176 String submittedValue = cycle.getParameter(name);
177
178 _log.debug("readValue() with : " + name + " [" + submittedValue + "]");
179
180 try
181 {
182 Object valueObject = getDataSqueezer().unsqueeze(submittedValue);
183 if (!(valueObject instanceof Boolean))
184 throw new ApplicationRuntimeException(Tapestry.format("If.invalid-condition-type", submittedValue));
185
186 return ((Boolean) valueObject).booleanValue();
187 }
188 catch (Exception ex)
189 {
190 throw new ApplicationRuntimeException(Tapestry.format(
191 "If.unable-to-convert-string",
192 submittedValue), this, null, ex);
193 }
194 }
195
196 public abstract DataSqueezer getDataSqueezer();
197
198 public boolean isDisabled()
199 {
200 return false;
201 }
202
203 /**
204 * Returns the value of the condition.
205 *
206 * @return the condition value
207 */
208 public boolean getConditionValue()
209 {
210 if (!_rendering)
211 throw Tapestry.createRenderOnlyPropertyException(this, "conditionValue");
212
213 return _conditionValue;
214 }
215
216 // Do nothing in those methods, but make the JVM happy
217 protected void renderFormComponent(IMarkupWriter writer, IRequestCycle cycle)
218 {
219 }
220
221 protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle cycle)
222 {
223 }
224
225 /**
226 * For component can not take focus.
227 */
228 protected boolean getCanTakeFocus()
229 {
230 return false;
231 }
232 }