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