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}