001// Copyright 2006-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. 014 015package org.apache.tapestry5.ioc.modules; 016 017import org.apache.tapestry5.beanmodel.internal.services.PropertyAccessImpl; 018import org.apache.tapestry5.commons.*; 019import org.apache.tapestry5.commons.internal.BasicTypeCoercions; 020import org.apache.tapestry5.commons.internal.services.*; 021import org.apache.tapestry5.commons.services.*; 022import org.apache.tapestry5.commons.util.CollectionFactory; 023import org.apache.tapestry5.commons.util.TimeInterval; 024import org.apache.tapestry5.func.Flow; 025import org.apache.tapestry5.ioc.IOCSymbols; 026import org.apache.tapestry5.ioc.ScopeConstants; 027import org.apache.tapestry5.ioc.ServiceBinder; 028import org.apache.tapestry5.ioc.ServiceLifecycle; 029import org.apache.tapestry5.ioc.ServiceLifecycle2; 030import org.apache.tapestry5.ioc.annotations.*; 031import org.apache.tapestry5.ioc.internal.services.AspectDecoratorImpl; 032import org.apache.tapestry5.ioc.internal.services.AutobuildObjectProvider; 033import org.apache.tapestry5.ioc.internal.services.ChainBuilderImpl; 034import org.apache.tapestry5.ioc.internal.services.ClassNameLocatorImpl; 035import org.apache.tapestry5.ioc.internal.services.ClasspathScannerImpl; 036import org.apache.tapestry5.ioc.internal.services.ClasspathURLConverterImpl; 037import org.apache.tapestry5.ioc.internal.services.DefaultImplementationBuilderImpl; 038import org.apache.tapestry5.ioc.internal.services.ExceptionAnalyzerImpl; 039import org.apache.tapestry5.ioc.internal.services.ExceptionTrackerImpl; 040import org.apache.tapestry5.ioc.internal.services.LazyAdvisorImpl; 041import org.apache.tapestry5.ioc.internal.services.LoggingAdvisorImpl; 042import org.apache.tapestry5.ioc.internal.services.LoggingDecoratorImpl; 043import org.apache.tapestry5.ioc.internal.services.MapSymbolProvider; 044import org.apache.tapestry5.ioc.internal.services.MasterObjectProviderImpl; 045import org.apache.tapestry5.ioc.internal.services.NonParallelExecutor; 046import org.apache.tapestry5.ioc.internal.services.OperationAdvisorImpl; 047import org.apache.tapestry5.ioc.internal.services.ParallelExecutorImpl; 048import org.apache.tapestry5.ioc.internal.services.PerThreadServiceLifecycle; 049import org.apache.tapestry5.ioc.internal.services.PipelineBuilderImpl; 050import org.apache.tapestry5.ioc.internal.services.PropertyShadowBuilderImpl; 051import org.apache.tapestry5.ioc.internal.services.RegistryStartup; 052import org.apache.tapestry5.ioc.internal.services.ServiceOverrideImpl; 053import org.apache.tapestry5.ioc.internal.services.StrategyBuilderImpl; 054import org.apache.tapestry5.ioc.internal.services.SymbolObjectProvider; 055import org.apache.tapestry5.ioc.internal.services.SymbolSourceImpl; 056import org.apache.tapestry5.ioc.internal.services.SystemEnvSymbolProvider; 057import org.apache.tapestry5.ioc.internal.services.SystemPropertiesSymbolProvider; 058import org.apache.tapestry5.ioc.internal.services.ThreadLocaleImpl; 059import org.apache.tapestry5.ioc.internal.services.ThunkCreatorImpl; 060import org.apache.tapestry5.ioc.internal.services.UpdateListenerHubImpl; 061import org.apache.tapestry5.ioc.internal.services.ValueObjectProvider; 062import org.apache.tapestry5.ioc.internal.services.cron.PeriodicExecutorImpl; 063import org.apache.tapestry5.ioc.internal.util.InternalUtils; 064import org.apache.tapestry5.ioc.services.ApplicationDefaults; 065import org.apache.tapestry5.ioc.services.AspectDecorator; 066import org.apache.tapestry5.ioc.services.Builtin; 067import org.apache.tapestry5.ioc.services.ChainBuilder; 068import org.apache.tapestry5.ioc.services.ClassNameLocator; 069import org.apache.tapestry5.ioc.services.ClasspathScanner; 070import org.apache.tapestry5.ioc.services.ClasspathURLConverter; 071import org.apache.tapestry5.ioc.services.DefaultImplementationBuilder; 072import org.apache.tapestry5.ioc.services.ExceptionAnalyzer; 073import org.apache.tapestry5.ioc.services.ExceptionTracker; 074import org.apache.tapestry5.ioc.services.FactoryDefaults; 075import org.apache.tapestry5.ioc.services.LazyAdvisor; 076import org.apache.tapestry5.ioc.services.LoggingAdvisor; 077import org.apache.tapestry5.ioc.services.LoggingDecorator; 078import org.apache.tapestry5.ioc.services.MasterObjectProvider; 079import org.apache.tapestry5.ioc.services.OperationAdvisor; 080import org.apache.tapestry5.ioc.services.ParallelExecutor; 081import org.apache.tapestry5.ioc.services.PerthreadManager; 082import org.apache.tapestry5.ioc.services.PipelineBuilder; 083import org.apache.tapestry5.ioc.services.PropertyShadowBuilder; 084import org.apache.tapestry5.ioc.services.RegistryShutdownHub; 085import org.apache.tapestry5.ioc.services.ServiceConfigurationListenerHub; 086import org.apache.tapestry5.ioc.services.ServiceLifecycleSource; 087import org.apache.tapestry5.ioc.services.ServiceOverride; 088import org.apache.tapestry5.ioc.services.StrategyBuilder; 089import org.apache.tapestry5.ioc.services.SymbolProvider; 090import org.apache.tapestry5.ioc.services.SymbolSource; 091import org.apache.tapestry5.ioc.services.ThreadLocale; 092import org.apache.tapestry5.ioc.services.ThunkCreator; 093import org.apache.tapestry5.ioc.services.UpdateListenerHub; 094import org.apache.tapestry5.ioc.services.cron.PeriodicExecutor; 095 096import java.io.File; 097import java.lang.reflect.Array; 098import java.math.BigDecimal; 099import java.math.BigInteger; 100import java.util.*; 101import java.util.Map.Entry; 102import java.util.concurrent.LinkedBlockingQueue; 103import java.util.concurrent.ThreadPoolExecutor; 104import java.util.concurrent.TimeUnit; 105 106import static org.apache.tapestry5.ioc.OrderConstraintBuilder.after; 107import static org.apache.tapestry5.ioc.OrderConstraintBuilder.before; 108 109/** 110 * Defines the base set of services for the Tapestry IOC container. 111 */ 112@SuppressWarnings("all") 113@Marker(Builtin.class) 114public final class TapestryIOCModule 115{ 116 public static void bind(ServiceBinder binder) 117 { 118 binder.bind(LoggingDecorator.class, LoggingDecoratorImpl.class); 119 binder.bind(ChainBuilder.class, ChainBuilderImpl.class); 120 binder.bind(PropertyAccess.class, PropertyAccessImpl.class); 121 binder.bind(StrategyBuilder.class, StrategyBuilderImpl.class); 122 binder.bind(PropertyShadowBuilder.class, PropertyShadowBuilderImpl.class); 123 binder.bind(PipelineBuilder.class, PipelineBuilderImpl.class).preventReloading(); 124 binder.bind(DefaultImplementationBuilder.class, DefaultImplementationBuilderImpl.class); 125 binder.bind(ExceptionTracker.class, ExceptionTrackerImpl.class); 126 binder.bind(ExceptionAnalyzer.class, ExceptionAnalyzerImpl.class); 127 binder.bind(TypeCoercer.class, TypeCoercerImpl.class).preventReloading(); 128 binder.bind(ThreadLocale.class, ThreadLocaleImpl.class); 129 binder.bind(SymbolSource.class, SymbolSourceImpl.class); 130 binder.bind(SymbolProvider.class, MapSymbolProvider.class).withId("ApplicationDefaults") 131 .withMarker(ApplicationDefaults.class); 132 binder.bind(SymbolProvider.class, MapSymbolProvider.class).withId("FactoryDefaults") 133 .withMarker(FactoryDefaults.class); 134 binder.bind(Runnable.class, RegistryStartup.class).withSimpleId(); 135 binder.bind(MasterObjectProvider.class, MasterObjectProviderImpl.class).preventReloading(); 136 binder.bind(ClassNameLocator.class, ClassNameLocatorImpl.class); 137 binder.bind(ClasspathScanner.class, ClasspathScannerImpl.class); 138 binder.bind(AspectDecorator.class, AspectDecoratorImpl.class); 139 binder.bind(ClasspathURLConverter.class, ClasspathURLConverterImpl.class); 140 binder.bind(ServiceOverride.class, ServiceOverrideImpl.class); 141 binder.bind(LoggingAdvisor.class, LoggingAdvisorImpl.class); 142 binder.bind(LazyAdvisor.class, LazyAdvisorImpl.class); 143 binder.bind(ThunkCreator.class, ThunkCreatorImpl.class); 144 binder.bind(UpdateListenerHub.class, UpdateListenerHubImpl.class).preventReloading(); 145 binder.bind(PeriodicExecutor.class, PeriodicExecutorImpl.class); 146 binder.bind(OperationAdvisor.class, OperationAdvisorImpl.class); 147 binder.bind(ServiceConfigurationListenerHub.class); 148 } 149 150 /** 151 * Provides access to additional service lifecycles. One lifecycle is built in ("singleton") but additional ones are 152 * accessed via this service (and its mapped configuration). Only proxiable services (those with explicit service 153 * interfaces) can be managed in terms of a lifecycle. 154 */ 155 @PreventServiceDecoration 156 public static ServiceLifecycleSource build(Map<String, ServiceLifecycle> configuration) 157 { 158 final Map<String, ServiceLifecycle2> lifecycles = CollectionFactory.newCaseInsensitiveMap(); 159 160 for (Entry<String, ServiceLifecycle> entry : configuration.entrySet()) 161 { 162 lifecycles.put(entry.getKey(), InternalUtils.toServiceLifecycle2(entry.getValue())); 163 } 164 165 return new ServiceLifecycleSource() 166 { 167 @Override 168 public ServiceLifecycle get(String scope) 169 { 170 return lifecycles.get(scope); 171 } 172 }; 173 } 174 175 /** 176 * Contributes the "perthread" scope. 177 */ 178 @Contribute(ServiceLifecycleSource.class) 179 public static void providePerthreadScope(MappedConfiguration<String, ServiceLifecycle> configuration) 180 { 181 configuration.addInstance(ScopeConstants.PERTHREAD, PerThreadServiceLifecycle.class); 182 } 183 184 /** 185 * <dl> 186 * <dt>AnnotationBasedContributions</dt> 187 * <dd>Empty placeholder used to separate annotation-based ObjectProvider contributions (which come before) from 188 * non-annotation based (such as ServiceOverride) which come after.</dd> 189 * <dt>Value</dt> 190 * <dd>Supports the {@link org.apache.tapestry5.ioc.annotations.Value} annotation</dd> 191 * <dt>Symbol</dt> 192 * <dd>Supports the {@link org.apache.tapestry5.ioc.annotations.Symbol} annotations</dd> 193 * <dt>Autobuild</dt> 194 * <dd>Supports the {@link org.apache.tapestry5.ioc.annotations.Autobuild} annotation</dd> 195 * <dt>ServiceOverride</dt> 196 * <dd>Allows simple service overrides via the {@link org.apache.tapestry5.ioc.services.ServiceOverride} service 197 * (and its configuration) 198 * </dl> 199 */ 200 @Contribute(MasterObjectProvider.class) 201 public static void setupObjectProviders(OrderedConfiguration<ObjectProvider> configuration, @Local 202 final ServiceOverride serviceOverride) 203 { 204 configuration.add("AnnotationBasedContributions", null); 205 206 configuration.addInstance("Value", ValueObjectProvider.class, before("AnnotationBasedContributions").build()); 207 configuration.addInstance("Symbol", SymbolObjectProvider.class, before("AnnotationBasedContributions").build()); 208 configuration.add("Autobuild", new AutobuildObjectProvider(), before("AnnotationBasedContributions").build()); 209 210 ObjectProvider wrapper = new ObjectProvider() 211 { 212 @Override 213 public <T> T provide(Class<T> objectType, AnnotationProvider annotationProvider, ObjectLocator locator) 214 { 215 return serviceOverride.getServiceOverrideProvider().provide(objectType, annotationProvider, locator); 216 } 217 }; 218 219 configuration.add("ServiceOverride", wrapper, after("AnnotationBasedContributions").build()); 220 } 221 222 /** 223 * Contributes a set of standard type coercions to the {@link TypeCoercer} service: 224 * <ul> 225 * <li>Object to String</li> 226 * <li>Object to Boolean</li> 227 * <li>String to Double</li> 228 * <li>String to BigDecimal</li> 229 * <li>BigDecimal to Double</li> 230 * <li>Double to BigDecimal</li> 231 * <li>String to BigInteger</li> 232 * <li>BigInteger to Long</li> 233 * <li>String to Long</li> 234 * <li>Long to Byte</li> 235 * <li>Long to Short</li> 236 * <li>Long to Integer</li> 237 * <li>Double to Long</li> 238 * <li>Double to Float</li> 239 * <li>Float to Double</li> 240 * <li>Long to Double</li> 241 * <li>String to Boolean ("false" is always false, other non-blank strings are true)</li> 242 * <li>Number to Boolean (true if number value is non zero)</li> 243 * <li>Null to Boolean (always false)</li> 244 * <li>Collection to Boolean (false if empty)</li> 245 * <li>Object[] to List</li> 246 * <li>primitive[] to List</li> 247 * <li>Object to List (by wrapping as a singleton list)</li> 248 * <li>String to File</li> 249 * <li>String to {@link org.apache.tapestry5.commons.util.TimeInterval}</li> 250 * <li>{@link org.apache.tapestry5.commons.util.TimeInterval} to Long</li> 251 * <li>Object to Object[] (wrapping the object as an array)</li> 252 * <li>Collection to Object[] (via the toArray() method) 253 * <li>{@link Flow} to List</li> 254 * <li>{@link Flow} to Boolean (false if empty)</li> 255 * </ul> 256 */ 257 @Contribute(TypeCoercer.class) 258 public static void provideBasicTypeCoercions(MappedConfiguration<CoercionTuple.Key, CoercionTuple> configuration) 259 { 260 BasicTypeCoercions.provideBasicTypeCoercions(configuration); 261 } 262 263 /** 264 * Contributes coercions to and from Java Time API (JSR 310) classes. 265 * <ul> 266 * <li>java.time.Year to Integer</li> 267 * <li>Integer to java.time.Year</li> 268 * <li>java.time.Month to Integer</li> 269 * <li>Integer to Java.time.Month</li> 270 * <li>java.time.Month to String</li> 271 * <li>String to java.time.Month</li> 272 * <li>String to java.time.YearMonth</li> 273 * <li>java.time.YearMonth to java.time.Year</li> 274 * <li>java.time.YearMonth to java.time.Month</li> 275 * <li>String to java.time.MonthDay</li> 276 * <li>java.time.MonthDay to java.time.Month</li> 277 * <li>java.time.DayOfWeek to Integer</li> 278 * <li>Integer to java.time.DayOfWeek</li> 279 * <li>java.time.DayOfWeek to String</li> 280 * <li>String to java.time.DayOfWeek</li> 281 * <li>java.time.LocalDate to java.time.Instant</li> 282 * <li>java.time.Instant to java.time.LocalDate</li> 283 * <li>String to java.time.LocalDate</li> 284 * <li>java.time.LocalDate to java.time.YearMonth</li> 285 * <li>java.time.LocalDate to java.time.MonthDay</li> 286 * <li>java.time.LocalTime to Long</li> 287 * <li>Long to java.time.LocalTime</li> 288 * <li>String to java.time.LocalDateTime</li> 289 * <li>java.time.LocalDateTime to java.time.Instant</li> 290 * <li>java.time.Instant to LocalDateTime</li> 291 * <li>java.time.LocalDateTime to java.time.LocalDate</li> 292 * <li>String to java.time.OffsetDateTime</li> 293 * <li>java.time.OffsetDateTime to java.time.Instant</li> 294 * <li>java.time.Instant to java.time.OffsetDateTime</li> 295 * <li>String to java.time.ZoneId</li> 296 * <li>String to java.time.ZoneOffset</li> 297 * <li>String to java.time.ZonedDateTime</li> 298 * <li>java.time.ZonedDateTime to java.time.Instant</li> 299 * <li>java.time.ZonedDateTime to java.time.ZoneId</li> 300 * <li>java.time.Instant to Long</li> 301 * <li>Long to java.time.Instant</li> 302 * <li>java.time.Instant to java.util.Date</li> 303 * <li>java.util.Date to java.time.Instant</li> 304 * <li>java.time.Duration to Long</li> 305 * <li>Long to java.time.Duration</li> 306 * <li>String to java.time.Period</li> 307 * </ul> 308 */ 309 @Contribute(TypeCoercer.class) 310 public static void provideJSR10TypeCoercions(MappedConfiguration<CoercionTuple.Key, CoercionTuple> configuration) 311 { 312 BasicTypeCoercions.provideJSR310TypeCoercions(configuration); 313 } 314 315 /** 316 * <dl> 317 * <dt>SystemProperties</dt> 318 * <dd>Exposes JVM System properties as symbols (currently case-sensitive)</dd> 319 * <dt>EnvironmentVariables</dt> 320 * <dd>Exposes environment variables as symbols (adding a "env." prefix)</dd> 321 * <dt>ApplicationDefaults</dt> 322 * <dd>Values contributed to @{@link SymbolProvider} @{@link ApplicationDefaults}</dd> 323 * <dt>FactoryDefaults</dt> 324 * <dd>Values contributed to @{@link SymbolProvider} @{@link FactoryDefaults}</dd> 325 * </dl> 326 */ 327 @Contribute(SymbolSource.class) 328 public static void setupStandardSymbolProviders(OrderedConfiguration<SymbolProvider> configuration, 329 @ApplicationDefaults 330 SymbolProvider applicationDefaults, 331 332 @FactoryDefaults 333 SymbolProvider factoryDefaults) 334 { 335 configuration.add("SystemProperties", new SystemPropertiesSymbolProvider(), "before:*"); 336 configuration.add("EnvironmentVariables", new SystemEnvSymbolProvider()); 337 configuration.add("ApplicationDefaults", applicationDefaults); 338 configuration.add("FactoryDefaults", factoryDefaults); 339 } 340 341 public static ParallelExecutor buildDeferredExecution(@Symbol(IOCSymbols.THREAD_POOL_CORE_SIZE) 342 int coreSize, 343 344 @Symbol(IOCSymbols.THREAD_POOL_MAX_SIZE) 345 int maxSize, 346 347 @Symbol(IOCSymbols.THREAD_POOL_KEEP_ALIVE) 348 @IntermediateType(TimeInterval.class) 349 int keepAliveMillis, 350 351 @Symbol(IOCSymbols.THREAD_POOL_ENABLED) 352 boolean threadPoolEnabled, 353 354 @Symbol(IOCSymbols.THREAD_POOL_QUEUE_SIZE) 355 int queueSize, 356 357 PerthreadManager perthreadManager, 358 359 RegistryShutdownHub shutdownHub, 360 361 ThunkCreator thunkCreator) 362 { 363 364 if (!threadPoolEnabled) 365 return new NonParallelExecutor(); 366 367 LinkedBlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(queueSize); 368 369 final ThreadPoolExecutor executorService = new ThreadPoolExecutor(coreSize, maxSize, keepAliveMillis, 370 TimeUnit.MILLISECONDS, workQueue); 371 372 shutdownHub.addRegistryShutdownListener(new Runnable() 373 { 374 @Override 375 public void run() 376 { 377 executorService.shutdown(); 378 } 379 }); 380 381 return new ParallelExecutorImpl(executorService, thunkCreator, perthreadManager); 382 } 383 384 @Contribute(SymbolProvider.class) 385 @FactoryDefaults 386 public static void setupDefaultSymbols(MappedConfiguration<String, Object> configuration) 387 { 388 configuration.add(IOCSymbols.THREAD_POOL_CORE_SIZE, 3); 389 configuration.add(IOCSymbols.THREAD_POOL_MAX_SIZE, 20); 390 configuration.add(IOCSymbols.THREAD_POOL_KEEP_ALIVE, "1 m"); 391 configuration.add(IOCSymbols.THREAD_POOL_ENABLED, true); 392 configuration.add(IOCSymbols.THREAD_POOL_QUEUE_SIZE, 100); 393 } 394 395 public static void contributeRegistryStartup(OrderedConfiguration<Runnable> configuration, 396 PeriodicExecutor periodicExecutor) 397 { 398 configuration.add(PeriodicExecutor.class.getSimpleName(), 399 () -> periodicExecutor.init()); 400 } 401 402}