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.binding;
016    
017    import org.apache.hivemind.Location;
018    import org.apache.hivemind.util.Defense;
019    import org.apache.tapestry.BindingException;
020    import org.apache.tapestry.IBinding;
021    import org.apache.tapestry.coerce.ValueConverter;
022    
023    /**
024     * Base class for {@link IBinding}implementations.
025     * 
026     * @author Howard Lewis Ship
027     */
028    
029    public 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    }