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.binding;
016
017import org.apache.hivemind.Location;
018import org.apache.hivemind.util.Defense;
019import org.apache.tapestry.BindingException;
020import org.apache.tapestry.IBinding;
021import org.apache.tapestry.coerce.ValueConverter;
022
023/**
024 * Base class for {@link IBinding}implementations.
025 * 
026 * @author Howard Lewis Ship
027 */
028
029public abstract class AbstractBinding implements IBinding
030{
031    /** @since 4.0 */
032
033    private final String _description;
034
035    /** @since 4.0 */
036
037    private final ValueConverter _valueConverter;
038
039    /** @since 3.0 */
040
041    private final Location _location;
042
043    /** @since 3.0 */
044
045    protected AbstractBinding(String description, ValueConverter valueConverter, Location location)
046    {
047        Defense.notNull(description, "description");
048        Defense.notNull(valueConverter, "valueConverter");
049
050        _description = description;
051        _valueConverter = valueConverter;
052        _location = location;
053    }
054
055    public Location getLocation()
056    {
057        return _location;
058    }
059
060    /**
061     * Overridden in subclasses that are not invariant.
062     * 
063     * @throws ReadOnlyBindingException
064     *             always.
065     */
066
067    public void setObject(Object value)
068    {
069        throw createReadOnlyBindingException(this);
070    }
071
072    /**
073     * Default implementation: returns true.
074     * 
075     * @since 2.0.3
076     */
077
078    public boolean isInvariant()
079    {
080        return true;
081    }
082
083    public Object getObject(Class type)
084    {
085        Defense.notNull(type, "type");
086
087        Object raw = getObject();
088
089        try
090        {
091            return _valueConverter.coerceValue(raw, type);
092        }
093        catch (Exception ex)
094        {
095            String message = BindingMessages.convertObjectError(this, ex);
096
097            throw new BindingException(message, getComponent(), _location, this, ex);
098        }
099    }
100
101    /**
102     * Returns the component to which this binding is connected; this is currently only used when
103     * building certain exceptions. This implementation returns null.
104     * 
105     * @since 4.0
106     */
107
108    public Object getComponent()
109    {
110        return null;
111    }
112
113    /** @since 3.0 */
114
115    protected BindingException createReadOnlyBindingException(IBinding binding)
116    {
117        return new BindingException(BindingMessages.readOnlyBinding(binding), binding);
118    }
119
120    /** @since 4.0 */
121
122    public String getDescription()
123    {
124        return _description;
125    }
126
127    /** @since 4.0 */
128    public ValueConverter getValueConverter()
129    {
130        return _valueConverter;
131    }
132
133    public String toString()
134    {
135        StringBuffer buffer = new StringBuffer();
136        buffer.append(getClass().getName());
137        buffer.append("@");
138        buffer.append(Integer.toHexString(hashCode()));
139        buffer.append("[");
140        buffer.append(_description);
141
142        extendDescription(buffer);
143
144        buffer.append(", location=");
145        buffer.append(_location);
146        buffer.append("]");
147
148        return buffer.toString();
149    }
150
151    /**
152     * Does nothing, subclasses may override to add additional information.
153     */
154    protected void extendDescription(StringBuffer buffer)
155    {
156
157    }
158}