    001// Licensed under the Apache License, Version 2.0 (the "License");
    002// you may not use this file except in compliance with the License.
    003// You may obtain a copy of the License at
    004//
    005//     http://www.apache.org/licenses/LICENSE-2.0
    006//
    007// Unless required by applicable law or agreed to in writing, software
    008// distributed under the License is distributed on an "AS IS" BASIS,
    009// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    010// See the License for the specific language governing permissions and
    011// limitations under the License.
    012
    013package org.apache.tapestry5.internal.bindings;
    014
    015import org.apache.tapestry5.Binding;
    016import org.apache.tapestry5.ComponentResources;
    017import org.apache.tapestry5.beanmodel.PropertyConduit;
    018import org.apache.tapestry5.beanmodel.services.PropertyConduitSource;
    019import org.apache.tapestry5.commons.Location;
    020import org.apache.tapestry5.commons.internal.services.StringInterner;
    021import org.apache.tapestry5.commons.internal.util.TapestryException;
    022import org.apache.tapestry5.services.BindingFactory;
    023import org.apache.tapestry5.services.pageload.PageClassLoaderContext;
    024import org.apache.tapestry5.services.pageload.PageClassLoaderContextManager;
    025
    026/**
    027 * Binding factory for reading and updating JavaBean properties.
    028 *
    029 * Expression are evaluated via a {@link PropertyConduit}, which is generated by {@link PropertyConduitSource} (which
    030 * therefore defines the expression language).
    031 */
    032public class PropBindingFactory implements BindingFactory
    033{
    034    private final PropertyConduitSource source;
    035
    036    private final StringInterner interner;
    037
    038    private final PageClassLoaderContextManager pageClassLoaderContextManager;
    039
    040    public PropBindingFactory(PropertyConduitSource propertyConduitSource, StringInterner interner,
    041            PageClassLoaderContextManager pageClassLoaderContextManager)
    042    {
    043        source = propertyConduitSource;
    044        this.interner = interner;
    045        this.pageClassLoaderContextManager = pageClassLoaderContextManager;
    046    }
    047
    048    public Binding newBinding(String description, ComponentResources container,
    049                              ComponentResources component, String expression, Location location)
    050    {
    051
    052        Object target = container.getComponent();
    053        Class targetClass = target.getClass();
    054        targetClass = getClassLoaderAppropriateClass(targetClass);
    055
    056        PropertyConduit conduit = source.create(targetClass, expression);
    057
    058        String toString = interner.format("PropBinding[%s %s(%s)]", description, container
    059                .getCompleteId(), expression);
    060
    061        return new PropBinding(location, target, conduit, expression, toString);
    062    }
    063
    064    private Class getClassLoaderAppropriateClass(Class targetClass)
    065    {
    066        final String className = targetClass.getName();
    067        try
    068        {
    069            final PageClassLoaderContext context = pageClassLoaderContextManager.get(className);
    070            targetClass = context.getProxyFactory()
    071                    .getClassLoader().loadClass(className);
    072        } catch (ClassNotFoundException e)
    073        {
    074            throw new TapestryException(e.getMessage(), e);
    075        }
    076        return targetClass;
    077    }
    078}