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