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}