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
015package org.apache.tapestry.components;
016
017import org.apache.hivemind.ApplicationRuntimeException;
018import org.apache.hivemind.HiveMind;
019import org.apache.tapestry.IActionListener;
020import org.apache.tapestry.IBinding;
021import org.apache.tapestry.IForm;
022import org.apache.tapestry.IMarkupWriter;
023import org.apache.tapestry.IRequestCycle;
024import org.apache.tapestry.Tapestry;
025import org.apache.tapestry.TapestryUtils;
026import org.apache.tapestry.form.AbstractFormComponent;
027import org.apache.tapestry.services.DataSqueezer;
028
029/**
030 * @author mb
031 */
032public 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}