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