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.hivemind.ApplicationRuntimeException;
018    import org.apache.hivemind.HiveMind;
019    import org.apache.tapestry.IActionListener;
020    import org.apache.tapestry.IBinding;
021    import org.apache.tapestry.IForm;
022    import org.apache.tapestry.IMarkupWriter;
023    import org.apache.tapestry.IRequestCycle;
024    import org.apache.tapestry.Tapestry;
025    import org.apache.tapestry.TapestryUtils;
026    import org.apache.tapestry.engine.NullWriter;
027    import org.apache.tapestry.form.AbstractFormComponent;
028    import org.apache.tapestry.services.DataSqueezer;
029    
030    /**
031     * @author mb
032     */
033    public abstract class IfBean extends AbstractFormComponent
034    {
035        public static final String IF_VALUE_ATTRIBUTE = "org.mb.tapestry.base.IfValue";
036    
037        private boolean _rendering = false;
038    
039        private boolean _conditionValue;
040        
041        public abstract IBinding getConditionValueBinding();
042    
043        public abstract boolean getCondition();
044    
045        public abstract boolean getVolatile();
046    
047        public abstract String getElement();
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            if (cycleRewinding && form != null && !form.isRewinding())
061                return;
062    
063            // get the condition. work with a hidden field if necessary
064            _conditionValue = evaluateCondition(cycle, form, cycleRewinding);
065            _rendering = true;
066            
067            if (!cycleRewinding && form != null && !NullWriter.class.isInstance(writer))
068                form.setFormFieldUpdating(true);
069            
070            try
071            {
072                // call listener
073                IActionListener listener = getListener();
074                if (listener != null)
075                    listener.actionTriggered(this, cycle);
076                
077                // now render if condition is true
078                if (_conditionValue)
079                {
080                    String element = getElement();
081    
082                    boolean render = !cycleRewinding && HiveMind.isNonBlank(element);
083    
084                    if (render)
085                    {
086                        writer.begin(element);
087                        renderInformalParameters(writer, cycle);
088                    }
089    
090                    renderBody(writer, cycle);
091    
092                    if (render)
093                        writer.end(element);
094                }
095            }
096            finally
097            {
098                _rendering = false;
099            }
100    
101            cycle.setAttribute(IF_VALUE_ATTRIBUTE, new Boolean(_conditionValue));
102        }
103    
104        protected boolean evaluateCondition(IRequestCycle cycle, IForm form, boolean cycleRewinding)
105        {
106            boolean condition;
107    
108            if (form == null || getVolatile())
109            {
110                condition = getCondition();
111            }
112            else
113            {
114                // we are in a form and we care -- load/store the condition in a hidden field
115                String name = form.getElementId(this);
116    
117                if (!cycleRewinding)
118                {
119                    condition = getCondition();
120                    writeValue(form, name, condition);
121                }
122                else
123                {
124                    condition = readValue(cycle, name);
125                }
126            }
127    
128            // write condition value if parameter is bound
129            IBinding conditionValueBinding = getConditionValueBinding();
130            if (conditionValueBinding != null)
131                conditionValueBinding.setObject(new Boolean(condition));
132    
133            return condition;
134        }
135    
136        private void writeValue(IForm form, String name, boolean value)
137        {
138            String externalValue;
139    
140            Object booleanValue = new Boolean(value);
141            try
142            {
143                externalValue = getDataSqueezer().squeeze(booleanValue);
144            }
145            catch (Exception ex)
146            {
147                throw new ApplicationRuntimeException(Tapestry.format(
148                        "If.unable-to-convert-value",
149                        booleanValue), this, null, ex);
150            }
151    
152            form.addHiddenValue(name, externalValue);
153        }
154    
155        private boolean readValue(IRequestCycle cycle, String name)
156        {
157            String submittedValue = cycle.getParameter(name);
158    
159            try
160            {
161                Object valueObject = getDataSqueezer().unsqueeze(submittedValue);
162                if (!(valueObject instanceof Boolean))
163                    throw new ApplicationRuntimeException(Tapestry.format(
164                            "If.invalid-condition-type",
165                            submittedValue));
166    
167                return ((Boolean) valueObject).booleanValue();
168            }
169            catch (Exception ex)
170            {
171                throw new ApplicationRuntimeException(Tapestry.format(
172                        "If.unable-to-convert-string",
173                        submittedValue), this, null, ex);
174            }
175        }
176    
177        public abstract DataSqueezer getDataSqueezer();
178    
179        public boolean isDisabled()
180        {
181            return false;
182        }
183    
184        /**
185         * Returns the value of the condition.
186         * 
187         * @return the condition value
188         */
189        public boolean getConditionValue()
190        {
191            if (!_rendering)
192                throw Tapestry.createRenderOnlyPropertyException(this, "conditionValue");
193    
194            return _conditionValue;
195        }
196    
197        // Do nothing in those methods, but make the JVM happy
198        protected void renderFormComponent(IMarkupWriter writer, IRequestCycle cycle)
199        {
200        }
201    
202        protected void rewindFormComponent(IMarkupWriter writer, IRequestCycle cycle)
203        {
204        }
205    
206        /**
207         * For component can not take focus.
208         */
209        protected boolean getCanTakeFocus()
210        {
211            return false;
212        }
213    }