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    }