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