001// Copyright 2006, 2008, 2009 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.tapestry5.internal.bindings;
016
017import java.lang.annotation.Annotation;
018import java.lang.reflect.Type;
019
020import org.apache.tapestry5.beanmodel.PropertyConduit;
021import org.apache.tapestry5.beanmodel.PropertyConduit2;
022import org.apache.tapestry5.beanmodel.internal.services.Invariant;
023import org.apache.tapestry5.commons.Location;
024import org.apache.tapestry5.commons.internal.util.TapestryException;
025import org.apache.tapestry5.internal.TapestryInternalUtils;
026
027/**
028 * Base class for bindings created by the {@link org.apache.tapestry5.internal.bindings.PropBindingFactory}. A subclass
029 * of this is created at runtime.
030 */
031public class PropBinding extends AbstractBinding implements InternalPropBinding
032{
033    private final Object root;
034
035    private final PropertyConduit conduit;
036
037    private final String toString;
038
039    private boolean invariant;
040    
041    private final String expression;
042
043    public PropBinding(final Location location, final Object root, final PropertyConduit conduit, final String expression, final String toString)
044    {
045        super(location);
046
047        this.root = root;
048        this.conduit = conduit;
049        this.expression = expression.intern();
050        this.toString = toString;
051
052        invariant = conduit.getAnnotation(Invariant.class) != null;
053    }
054
055    /**
056     * The default implementation of get() will throw a TapestryException (binding is write only). The fabricated
057     * subclass <em>may</em> override this method (as well as set()).
058     */
059    public Object get()
060    {
061        try
062        {
063            return conduit.get(root);
064        }
065        catch (Exception ex)
066        {
067            throw new TapestryException(ex.getMessage(), getLocation(), ex);
068        }
069    }
070
071    @Override
072    public void set(Object value)
073    {
074        try
075        {
076            conduit.set(root, value);
077        }
078        catch (Exception ex)
079        {
080            throw new TapestryException(ex.getMessage(), getLocation(), ex);
081        }
082    }
083
084    @Override
085    public String toString()
086    {
087        return toString;
088    }
089
090    /**
091     * Almost always returns false, unless the conduit provides the {@link org.apache.tapestry5.beanmodel.internal.services.Invariant}
092     * annotation.
093     */
094    @Override
095    public boolean isInvariant()
096    {
097        return invariant;
098    }
099
100    @Override
101    public Class getBindingType()
102    {
103        return conduit.getPropertyType();
104    }
105    
106    /**
107     * Get the generic type from the underlying property
108     * 
109     * @see PropertyConduit2#getPropertyGenericType()
110     */
111    @Override
112    public Type getBindingGenericType()
113    {
114        if (conduit instanceof PropertyConduit2) {
115            return ((PropertyConduit2) conduit).getPropertyGenericType();
116        }
117        return conduit.getPropertyType();
118    }
119
120    @Override
121    public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
122    {
123        return conduit.getAnnotation(annotationClass);
124    }
125
126    public String getPropertyName() 
127    {
128        return TapestryInternalUtils.toInternalPropertyConduit(conduit).getPropertyName();
129    }
130
131    public String getExpression()
132    {
133        return expression;
134    }
135    
136}