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        typeCoercer = new TypeCoercerImpl(configuration.getTuples());
173    }
174
175    final private static class CoercionTupleConfiguration implements Configuration<CoercionTuple> 
176    {
177
178        final private Collection<CoercionTuple> tuples = new ArrayList<CoercionTuple>();
179
180        @Override
181        public void add(CoercionTuple tuble) 
182        {
183            tuples.add(tuble);
184        }
185
186        @Override
187        public void addInstance(Class<? extends CoercionTuple> clazz) 
188        {
189            throw new RuntimeException("Not implemented");
190        }
191
192        public Collection<CoercionTuple> getTuples() 
193        {
194            return tuples;
195        }
196
197    }
198    
199    final private static class AutobuildOnlyObjectLocator implements ObjectLocator {
200
201        @Override
202        public <T> T getService(String serviceId, Class<T> serviceInterface)
203        {
204            throw new RuntimeException("Not implemented");
205        }
206
207        @Override
208        public <T> T getService(Class<T> serviceInterface)
209        {
210            throw new RuntimeException("Not implemented");
211        }
212
213        @Override
214        public <T> T getService(Class<T> serviceInterface,
215                Class<? extends Annotation>... markerTypes)
216        {
217            throw new RuntimeException("Not implemented");
218        }
219
220        @Override
221        public <T> T getObject(Class<T> objectType, AnnotationProvider annotationProvider)
222        {
223            throw new RuntimeException("Not implemented");
224        }
225
226        @Override
227        public <T> T autobuild(Class<T> clazz)
228        {
229            try
230            {
231                return clazz.newInstance();
232            }
233            catch (Exception e)
234            {
235                throw new TapestryException("Couldn't instantiate class " + clazz.getName(), e);
236            }
237        }
238
239        @Override
240        public <T> T autobuild(String description, Class<T> clazz)
241        {
242            return autobuild(clazz);
243        }
244
245        public <T> T proxy(Class<T> interfaceClass, Class<? extends T> implementationClass)
246        {
247            throw new RuntimeException("Not implemented");
248        }
249        
250    }
251
252}