    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.
    012package org.apache.tapestry5.beaneditor;
    013
    014import org.apache.tapestry5.internal.services.BeanModelSourceImpl;
    015import org.apache.tapestry5.internal.services.PropertyConduitSourceImpl;
    016import org.apache.tapestry5.internal.services.StringInterner;
    017import org.apache.tapestry5.internal.services.StringInternerImpl;
    018import org.apache.tapestry5.ioc.AnnotationProvider;
    019import org.apache.tapestry5.ioc.Configuration;
    020import org.apache.tapestry5.ioc.ObjectLocator;
    021import org.apache.tapestry5.ioc.internal.BasicDataTypeAnalyzers;
    022import org.apache.tapestry5.ioc.internal.BasicTypeCoercions;
    023import org.apache.tapestry5.ioc.internal.services.PlasticProxyFactoryImpl;
    024import org.apache.tapestry5.ioc.internal.services.PropertyAccessImpl;
    025import org.apache.tapestry5.ioc.internal.services.TypeCoercerImpl;
    026import org.apache.tapestry5.ioc.internal.util.TapestryException;
    027import org.apache.tapestry5.ioc.services.CoercionTuple;
    028import org.apache.tapestry5.ioc.services.PlasticProxyFactory;
    029import org.apache.tapestry5.ioc.services.PropertyAccess;
    030import org.apache.tapestry5.ioc.services.TypeCoercer;
    031import org.apache.tapestry5.services.BeanModelSource;
    032import org.apache.tapestry5.services.DataTypeAnalyzer;
    033import org.apache.tapestry5.services.PropertyConduitSource;
    034import org.slf4j.LoggerFactory;
    035
    036import java.lang.annotation.Annotation;
    037import java.util.ArrayList;
    038import java.util.Collection;
    039
    040/**
    041 * Utility class for creating {@link BeanModelSource} instances without
    042 * Tapestry-IoC. Usage of Tapestry-IoC is still recommended.
    043 *
    044 * The setter methods can be used to customize the BeanModelSource to be created and can be
    045 * (and usually are) skipped so <code>BeanModelSource beanModelSource = new BeanModelSourceBuilder().build();</code>
    046 * is all you need to do.
    047 */
    048public class BeanModelSourceBuilder {
    049
    050    private TypeCoercer typeCoercer;
    051    private PropertyAccess propertyAccess;
    052    private PropertyConduitSource propertyConduitSource;
    053    private PlasticProxyFactory plasticProxyFactory;
    054    private DataTypeAnalyzer dataTypeAnalyzer;
    055    private ObjectLocator objectLocator;
    056    private StringInterner stringInterner;
    057
    058    /**
    059     * Creates and returns a {@link BeanModelSource} instance.
    060     */
    061    public BeanModelSource build()
    062    {
    063
    064        if (typeCoercer == null)
    065        {
    066            createTypeCoercer();
    067        }
    068
    069        if (propertyAccess == null)
    070        {
    071            propertyAccess = new PropertyAccessImpl();
    072        }
    073
    074        if (dataTypeAnalyzer == null)
    075        {
    076            dataTypeAnalyzer = BasicDataTypeAnalyzers.createDefaultDataTypeAnalyzer();
    077        }
    078
    079        if (stringInterner == null)
    080        {
    081            stringInterner = new StringInternerImpl();
    082        }
    083
    084        if (plasticProxyFactory == null)
    085        {
    086            plasticProxyFactory = new PlasticProxyFactoryImpl(getClass().getClassLoader(), LoggerFactory.getLogger(PlasticProxyFactory.class));
    087        }
    088
    089        if (propertyConduitSource == null)
    090        {
    091            propertyConduitSource = new PropertyConduitSourceImpl(propertyAccess, plasticProxyFactory, typeCoercer, stringInterner);
    092        }
    093
    094        if (objectLocator == null)
    095        {
    096            objectLocator = new AutobuildOnlyObjectLocator();
    097        }
    098
    099        return new BeanModelSourceImpl(typeCoercer, propertyAccess, propertyConduitSource, plasticProxyFactory, dataTypeAnalyzer, objectLocator);
    100
    101    }
    102
    103    /**
    104     * Sets the {@link TypeCoercer} to be used.
    105     */
    106    public BeanModelSourceBuilder setTypeCoercer(TypeCoercer typeCoercer)
    107    {
    108        this.typeCoercer = typeCoercer;
    109        return this;
    110    }
    111
    112    /**
    113     * Sets the {@link PropertyAccess} to be used.
    114     */
    115    public BeanModelSourceBuilder setPropertyAccess(PropertyAccess propertyAccess)
    116    {
    117        this.propertyAccess = propertyAccess;
    118        return this;
    119    }
    120
    121    /**
    122     * Sets the {@link PropertyConduitSource} to be used.
    123     */
    124    public BeanModelSourceBuilder setPropertyConduitSource(PropertyConduitSource propertyConduitSource)
    125    {
    126        this.propertyConduitSource = propertyConduitSource;
    127        return this;
    128    }
    129
    130    /**
    131     * Sets the {@link PlasticProxyFactory} to be used.
    132     */
    133    public BeanModelSourceBuilder setPlasticProxyFactory(PlasticProxyFactory plasticProxyFactory)
    134    {
    135        this.plasticProxyFactory = plasticProxyFactory;
    136        return this;
    137    }
    138
    139    /**
    140     * Sets the {@link DataTypeAnalyzer} to be used.
    141     */
    142    public BeanModelSourceBuilder setDataTypeAnalyzer(DataTypeAnalyzer dataTypeAnalyzer)
    143    {
    144        this.dataTypeAnalyzer = dataTypeAnalyzer;
    145        return this;
    146    }
    147
    148    /**
    149     * Sets the {@link ObjectLocator} to be used. Actually, the only method of it actually used is
    150     * {@link ObjectLocator#autobuild(Class)}, for creating objects of the class described by the
    151     * {@link BeanModel}.
    152     */
    153    public BeanModelSourceBuilder setObjectLocator(ObjectLocator objectLocator)
    154    {
    155        this.objectLocator = objectLocator;
    156        return this;
    157    }
    158
    159    /**
    160     * Sets the {@link StringInterner} to be used.
    161     */
    162    public BeanModelSourceBuilder setStringInterner(StringInterner stringInterner)
    163    {
    164        this.stringInterner = stringInterner;
    165        return this;
    166    }
    167
    168    private void createTypeCoercer()
    169    {
    170        CoercionTupleConfiguration configuration = new CoercionTupleConfiguration();
    171        BasicTypeCoercions.provideBasicTypeCoercions(configuration);
    172        BasicTypeCoercions.provideJSR310TypeCoercions(configuration);
    173        typeCoercer = new TypeCoercerImpl(configuration.getTuples());
    174    }
    175
    176    final private static class CoercionTupleConfiguration implements Configuration<CoercionTuple>
    177    {
    178
    179        final private Collection<CoercionTuple> tuples = new ArrayList<CoercionTuple>();
    180
    181        @Override
    182        public void add(CoercionTuple tuble)
    183        {
    184            tuples.add(tuble);
    185        }
    186
    187        @Override
    188        public void addInstance(Class<? extends CoercionTuple> clazz)
    189        {
    190            throw new RuntimeException("Not implemented");
    191        }
    192
    193        public Collection<CoercionTuple> getTuples()
    194        {
    195            return tuples;
    196        }
    197
    198    }
    199
    200    final private static class AutobuildOnlyObjectLocator implements ObjectLocator {
    201
    202        @Override
    203        public <T> T getService(String serviceId, Class<T> serviceInterface)
    204        {
    205            throw new RuntimeException("Not implemented");
    206        }
    207
    208        @Override
    209        public <T> T getService(Class<T> serviceInterface)
    210        {
    211            throw new RuntimeException("Not implemented");
    212        }
    213
    214        @Override
    215        public <T> T getService(Class<T> serviceInterface,
    216                Class<? extends Annotation>... markerTypes)
    217        {
    218            throw new RuntimeException("Not implemented");
    219        }
    220
    221        @Override
    222        public <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider)
    223        {
    224            throw new RuntimeException("Not implemented");
    225        }
    226
    227        @Override
    228        public <T> T autobuild(Class<T> clazz)
    229        {
    230            try
    231            {
    232                return clazz.newInstance();
    233            }
    234            catch (Exception e)
    235            {
    236                throw new TapestryException("Couldn't instantiate class " + clazz.getName(), e);
    237            }
    238        }
    239
    240        @Override
    241        public <T> T autobuild(String description, Class<T> clazz)
    242        {
    243            return autobuild(clazz);
    244        }
    245
    246        public <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass)
    247        {
    248            throw new RuntimeException("Not implemented");
    249        }
    250
    251    }
    252
    253}